Fix Playwright OTP login and UAT security tests

This commit is contained in:
A R R R Associates
2026-06-28 12:57:42 +05:30
parent 6bf24cf860
commit db56738731
4 changed files with 593 additions and 87 deletions
+69 -2
View File
@@ -19,7 +19,7 @@ function unauthorizedRole(v) {
async function safeGoto(page, route) {
const resp = await page.goto(route || '/employee/dashboard');
await page.waitForLoadState('domcontentloaded');
await page.waitForLoadState('domcontentloaded').catch(() => {});
return resp;
}
@@ -38,12 +38,71 @@ async function boundaryInputIfAny(page) {
await submitBlankFormIfAny(page);
}
function sec101TenantBCaseId() {
return process.env.TENANT_B_NOTICE_CASE_ID || process.env.CROSS_TENANT_NOTICE_CASE_ID || '7';
}
async function expectNoTenantBNoticeLeak(page, resp) {
// A correct ERP may reject with 401/403/404/405/422 or redirect away.
// If it returns 200/303, the page still must not disclose Tenant B notice data.
await expectBlockedOrSafe(page, resp);
const body = await page.locator('body').innerText().catch(() => '');
expect(body).not.toMatch(/Tenant B SEC-101 Cross Tenant Notice/i);
expect(body).not.toMatch(/UAT-B-NOTICE-SEC101/i);
expect(body).not.toMatch(/UAT-NC-B-SEC101/i);
expect(body).not.toMatch(/Traceback|Internal Server Error|Exception/i);
}
async function runSec101CrossTenant(page, context, v) {
const tenantBNoticeCaseId = sec101TenantBCaseId();
await login(page, 'System Admin'); // Tenant A system admin from env, e.g. uat.admin@vavalam.com.
const variant = String(v.variantType || '').toLowerCase();
const probes = [];
if (variant === 'negative') {
probes.push(`/notice-cases/${tenantBNoticeCaseId}?tamper=1`);
probes.push(`/notice-cases/${tenantBNoticeCaseId}/../../${tenantBNoticeCaseId}`);
} else if (variant === 'rbac') {
await logout(page);
await login(page, 'Staff');
probes.push(`/notice-cases/${tenantBNoticeCaseId}`);
} else if (variant === 'idor') {
probes.push(`/notice-cases/${tenantBNoticeCaseId}`);
probes.push(`/notice-cases/${tenantBNoticeCaseId}/edit`);
probes.push(`/notice-cases/${tenantBNoticeCaseId}/documents`);
} else if (variant === 'headers') {
await context.setExtraHTTPHeaders({
'X-Tenant-ID': '3',
'X-Branch-ID': '3',
'X-Tenant-Code': 'UAT-B',
'X-Branch-Code': 'UAT-BB',
});
probes.push(`/notice-cases/${tenantBNoticeCaseId}`);
} else {
probes.push(`/notice-cases/${tenantBNoticeCaseId}`);
}
for (const route of probes) {
const resp = await safeGoto(page, route);
await expectNoTenantBNoticeLeak(page, resp);
}
}
async function runSecuritySpecific(page, context, v) {
const id = v.sourceId;
if (/SEC-101/i.test(id)) {
await runSec101CrossTenant(page, context, v);
return;
}
if (/SEC-001/i.test(id)) {
await page.goto('/login');
for (let i = 0; i < 5; i++) {
await fillFirst(page, ['input[name="email"]','input[name="login_id"]','input[type="email"]'], process.env.SYSTEM_ADMIN_EMAIL || 'admin@auditfirm.local');
await fillFirst(page, ['input[name="email"]','input[name="login_id"]','input[type="email"]'], process.env.SYSTEM_ADMIN_EMAIL || 'uat.admin@vavalam.com');
await fillFirst(page, ['input[name="password"]','input[type="password"]'], 'wrong-password-' + i);
await clickFirst(page, ['button[type="submit"]','input[type="submit"]']);
await page.waitForLoadState('domcontentloaded').catch(() => {});
@@ -95,6 +154,14 @@ for (const v of matrix) {
test.info().annotations.push({ type: 'variantType', description: v.variantType });
test.info().annotations.push({ type: 'expected', description: String(v.expected || '').slice(0, 250) });
// SEC-101 was marked manual in the generated matrix, but it is now automated here
// using a seeded Tenant B notice case. This keeps ERP features unchanged and only
// replaces the scaffold/manual handling for these five variants.
if (/SEC-101/i.test(v.sourceId || '')) {
await runSec101CrossTenant(page, context, v);
return;
}
if (v.automation === 'manual') {
test.skip(true, v.manualReason || 'Marked manual in generated matrix');
}