feat: complete Epic 1 production foundation
This commit is contained in:
@@ -84,3 +84,134 @@ test('generic json secret modal stays inside compact viewport', async ({ page })
|
||||
await expect(page.locator('[data-testid="secret-name-input"]')).toBeVisible();
|
||||
await expect(page.locator('[data-testid="secret-submit-button"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('secret modal clears sensitive values and locks duplicate submit while saving', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto('/secrets');
|
||||
|
||||
await page.locator('[data-testid="secret-create-button"]').click();
|
||||
await page.locator('[data-testid="secret-name-input"]').fill(uniqueName('ui_secret_guard'));
|
||||
await page.locator('[data-testid="secret-value-input"]').fill('ui-secret-canary-close');
|
||||
await page.locator('#secret-modal-cancel-btn').click();
|
||||
await page.locator('[data-testid="secret-create-button"]').click();
|
||||
await expect(page.locator('[data-testid="secret-name-input"]')).toHaveValue('');
|
||||
await expect(page.locator('[data-testid="secret-value-input"]')).toHaveValue('');
|
||||
|
||||
let releaseCreate;
|
||||
const createReleased = new Promise((resolve) => {
|
||||
releaseCreate = resolve;
|
||||
});
|
||||
let createPosts = 0;
|
||||
await page.route(/\/api\/admin\/workspaces\/[^/]+\/secrets$/, async (route) => {
|
||||
if (route.request().method() !== 'POST') {
|
||||
await route.continue();
|
||||
return;
|
||||
}
|
||||
createPosts += 1;
|
||||
await createReleased;
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: 'secret_ui_guard',
|
||||
workspace_id: 'ws_test',
|
||||
name: 'ui_secret_guard',
|
||||
kind: 'token',
|
||||
status: 'active',
|
||||
current_version: 1,
|
||||
created_at: '2026-08-15T00:00:00Z',
|
||||
updated_at: '2026-08-15T00:00:00Z',
|
||||
last_used_at: null,
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.locator('[data-testid="secret-name-input"]').fill(uniqueName('ui_secret_guard'));
|
||||
await page.locator('[data-testid="secret-value-input"]').fill('ui-secret-canary-submit');
|
||||
const submit = page.locator('[data-testid="secret-submit-button"]');
|
||||
await submit.click();
|
||||
await expect(submit).toBeDisabled();
|
||||
await submit.click({ force: true });
|
||||
expect(createPosts).toBe(1);
|
||||
releaseCreate();
|
||||
await expect(page.locator('[data-testid="secret-create-modal"]')).toBeHidden();
|
||||
expect(createPosts).toBe(1);
|
||||
});
|
||||
|
||||
test('stale secret rotation cannot close or report success for a newer modal context', async ({ page }) => {
|
||||
await login(page);
|
||||
const workspace = await getCurrentWorkspace(page);
|
||||
const firstName = uniqueName('rotate_stale_first');
|
||||
const secondName = uniqueName('rotate_stale_second');
|
||||
const firstSecret = await browserJson(
|
||||
page,
|
||||
'POST',
|
||||
`/api/admin/workspaces/${encodeURIComponent(workspace.id)}/secrets`,
|
||||
{ name: firstName, kind: 'token', value: 'rotate-stale-first-value' },
|
||||
);
|
||||
await browserJson(
|
||||
page,
|
||||
'POST',
|
||||
`/api/admin/workspaces/${encodeURIComponent(workspace.id)}/secrets`,
|
||||
{ name: secondName, kind: 'token', value: 'rotate-stale-second-value' },
|
||||
);
|
||||
|
||||
let releaseRotate;
|
||||
const rotateReleased = new Promise((resolve) => {
|
||||
releaseRotate = resolve;
|
||||
});
|
||||
let secretListRequests = 0;
|
||||
await page.route(/\/api\/admin\/workspaces\/[^/]+\/secrets(?:\/[^/]+\/rotate)?$/, async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method() === 'GET') {
|
||||
secretListRequests += 1;
|
||||
await route.continue();
|
||||
return;
|
||||
}
|
||||
if (request.method() === 'POST' && /\/rotate$/.test(request.url())) {
|
||||
await rotateReleased;
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: firstSecret.id,
|
||||
workspace_id: workspace.id,
|
||||
name: firstName,
|
||||
kind: 'token',
|
||||
status: 'active',
|
||||
current_version: 2,
|
||||
created_at: '2026-08-15T00:00:00Z',
|
||||
updated_at: '2026-08-15T00:00:00Z',
|
||||
last_used_at: null,
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await route.continue();
|
||||
});
|
||||
|
||||
await page.goto('/secrets');
|
||||
const firstRow = page.locator('#secrets-tbody tr').filter({ hasText: firstName }).first();
|
||||
const secondRow = page.locator('#secrets-tbody tr').filter({ hasText: secondName }).first();
|
||||
await expect(firstRow).toBeVisible();
|
||||
await expect(secondRow).toBeVisible();
|
||||
const listRequestsBeforeRelease = secretListRequests;
|
||||
|
||||
await firstRow.getByTestId('secret-rotate-action').click();
|
||||
await page.locator('[data-testid="secret-value-input"]').fill('rotate-stale-first-new-value');
|
||||
await page.locator('[data-testid="secret-submit-button"]').click();
|
||||
await expect(page.locator('[data-testid="secret-submit-button"]')).toBeDisabled();
|
||||
await page.locator('#secret-modal-cancel-btn').click();
|
||||
await expect(page.getByTestId('secret-rotate-modal')).toBeHidden();
|
||||
|
||||
await secondRow.getByTestId('secret-rotate-action').click();
|
||||
await expect(page.getByTestId('secret-rotate-modal')).toBeVisible();
|
||||
await expect(page.locator('[data-testid="secret-name-input"]')).toHaveValue(secondName);
|
||||
|
||||
releaseRotate();
|
||||
await page.waitForTimeout(150);
|
||||
await expect(page.getByTestId('secret-rotate-modal')).toBeVisible();
|
||||
await expect(page.locator('[data-testid="secret-name-input"]')).toHaveValue(secondName);
|
||||
await expect(page.locator('.toast-success')).toHaveCount(0);
|
||||
expect(secretListRequests).toBe(listRequestsBeforeRelease);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user