Some checks failed
Use-case regression gate / usecase-regressions (push) Failing after 6m57s
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
123 lines
6 KiB
JavaScript
123 lines
6 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { pathToFileURL } from 'node:url';
|
|
|
|
const [portal, fixtures, receiver, modulePath] = process.argv.slice(2);
|
|
const allowed = new Set([portal, fixtures, receiver]);
|
|
for (const base of allowed) {
|
|
const url = new URL(base);
|
|
assert.equal(url.hostname, '127.0.0.1');
|
|
assert.equal(url.protocol, 'http:');
|
|
}
|
|
const { chromium } = await import(pathToFileURL(modulePath).href);
|
|
const browser = await chromium.launch({ headless: true });
|
|
let outside = 0;
|
|
const context = await browser.newContext({ serviceWorkers: 'block' });
|
|
await context.route('**/*', route => {
|
|
if (!allowed.has(new URL(route.request().url()).origin)) {
|
|
outside += 1;
|
|
return route.abort();
|
|
}
|
|
return route.continue();
|
|
});
|
|
const page = await context.newPage();
|
|
page.setDefaultTimeout(15000);
|
|
const request = async (method, url, options = {}) => {
|
|
assert(allowed.has(new URL(url).origin));
|
|
return context.request[method](url, { ...options, maxRedirects: 0 });
|
|
};
|
|
const state = async () => (await request('get', fixtures + '/state')).json();
|
|
const control = async (path, data = {}) => {
|
|
const response = await request('post', fixtures + path, { data });
|
|
assert.equal(response.status(), 200);
|
|
};
|
|
async function register(name) {
|
|
await page.goto(portal + '/register');
|
|
await page.getByLabel('Username', { exact: true }).fill(name);
|
|
await page.getByLabel('Email', { exact: true }).fill(name + '@example.test');
|
|
await page.getByRole('button', { name: 'Send verification email' }).click();
|
|
await page.getByText('Check your email', { exact: false }).first().waitFor();
|
|
await page.goto(fixtures + '/mailbox');
|
|
const body = await page.locator(`article[data-recipient="${name}@example.test"]`).innerText();
|
|
const url = body.match(/http:\/\/127\.0\.0\.1:\d+\/registration\/verify\?handle=[A-Za-z0-9_-]+/)[0];
|
|
assert.equal(new URL(url).origin, portal);
|
|
return url;
|
|
}
|
|
async function consume(url, button, accepted) {
|
|
assert.equal(new URL(url).origin, portal);
|
|
await page.goto(url);
|
|
const response = page.waitForResponse(r => r.url().startsWith(portal + '/registration/')
|
|
&& r.request().method() === 'POST');
|
|
await page.getByRole('button', { name: button, exact: true }).click();
|
|
const result = await response;
|
|
assert.equal(result.status() < 400, accepted);
|
|
}
|
|
try {
|
|
const verified = await register('verified.person');
|
|
assert.equal((await state()).provisions, 0); // mail receipt alone cannot provision
|
|
assert.equal((await state()).users, 1); // only the synthetic inviter exists
|
|
const wrongCaller = await request('post', receiver + '/v1/registration-verifications/consume',
|
|
{ headers: { Authorization: 'Bearer synthetic-other-caller-token' },
|
|
data: { handle: new URL(verified).searchParams.get('handle') } });
|
|
assert.equal(wrongCaller.status(), 400);
|
|
await consume(verified, 'Verify and continue', true);
|
|
const passwordLink = page.getByRole('link', { name: 'Create password', exact: true });
|
|
assert.equal(await passwordLink.count(), 1, await page.locator('body').innerText());
|
|
assert.equal((await state()).provisions, 1);
|
|
assert.equal((await state()).users, 2);
|
|
await consume(verified, 'Verify and continue', false);
|
|
|
|
const canceled = await register('canceled.person');
|
|
await consume(canceled.replace('/verify?', '/cancel?'), 'Cancel registration', true);
|
|
await consume(canceled, 'Verify and continue', false);
|
|
const expired = await register('expired.person');
|
|
await control('/expire', { email: 'expired.person@example.test' });
|
|
await consume(expired, 'Verify and continue', false);
|
|
assert.equal((await state()).provisions, 1);
|
|
|
|
const headers = { Authorization: 'Bearer synthetic-user-engine-mail-token' };
|
|
const challenge = { registration_id: 'reg-wrong-binding',
|
|
normalized_email: 'denied@example.test', preferred_username: 'denied.person',
|
|
client_id: 'coulomb-social-test', tenant: 'tenant:communication-test', correlation_id: 'test' };
|
|
for (const bad of [{ tenant: 'tenant:other' }, { client_id: 'client-other' }]) {
|
|
const response = await request('post', receiver + '/v1/registration-verifications',
|
|
{ headers, data: { ...challenge, ...bad } });
|
|
assert.equal(response.status(), 400);
|
|
}
|
|
const missingCaller = await request('post', receiver + '/v1/registration-verifications',
|
|
{ headers: { Authorization: 'Bearer invalid-caller-token' }, data: challenge });
|
|
assert.equal(missingCaller.status(), 401);
|
|
assert.equal((await state()).messages, 3);
|
|
|
|
// Synthetic preauthenticated MFA session; real portal form and role/CSRF checks.
|
|
await context.addCookies([{ name: 'ue_session', value: 'synthetic-admin-session',
|
|
url: portal, httpOnly: true, sameSite: 'Lax' }]);
|
|
assert.equal((await request('get', portal + '/admin/tenant%3Aother')).status(), 403);
|
|
const admin = portal + '/admin/tenant%3Acommunication-test';
|
|
await page.goto(admin);
|
|
const form = page.locator('form[action$="/invitations"]');
|
|
await form.getByLabel('Email', { exact: true }).fill('invited@example.test');
|
|
await form.getByRole('button', { name: 'Send invitation', exact: true }).click();
|
|
await control('/deliver');
|
|
assert.equal((await state()).messages, 4);
|
|
await control('/deliver');
|
|
assert.equal((await state()).messages, 4);
|
|
await page.reload();
|
|
await page.getByRole('button', { name: 'Resend', exact: true }).click();
|
|
await control('/deliver');
|
|
assert.equal((await state()).messages, 5);
|
|
|
|
await control('/suppress', { email: 'suppressed@example.test' });
|
|
await page.goto(admin);
|
|
await form.getByLabel('Email', { exact: true }).fill('suppressed@example.test');
|
|
await form.getByRole('button', { name: 'Send invitation', exact: true }).click();
|
|
await control('/deliver');
|
|
assert.equal((await state()).messages, 5);
|
|
assert.equal((await state()).provisions, 1);
|
|
assert.equal(outside, 0);
|
|
console.log(JSON.stringify({ passed: true, browser_requests_outside_fixture: outside,
|
|
registration_verify_cancel_expire_replay: true, mailbox_not_authorization: true,
|
|
tenant_client_caller_denials: true, real_invitation_and_resend: true,
|
|
duplicate_delivery_and_suppression: true, provider_calls: 5 }));
|
|
} finally {
|
|
await browser.close();
|
|
}
|