mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:01:08 +02:00
test(integration): assert security_events audit rows after register + login
Adds two assertions to the auth-flow integration test that exercise the
audit-log path:
- after register: expect exactly 1 REGISTER row in auth.security_events
for the new user
- after login: expect exactly 1 LOGIN_SUCCESS row for the same user
This locks in the fix from the previous commit (security.ts ?? null
guard for optional fields) and catches any future regression where
security.logEvent silently swallows a SQL error and the audit log goes
into the void.
Verified by reverting security.ts to the broken pre-fix version and
re-running — the test fails with `Expected: 1, Received: 0` at the
register-audit assert in 211ms instead of taking hours of production
debugging.
Also adds an explicit DELETE FROM auth.security_events to the afterAll
cleanup. The FK from security_events.user_id to auth.users(id) is
ON DELETE CASCADE so it would clean up implicitly anyway, but listing
it explicitly makes the cleanup intent obvious from the test source.
Net: 24 → 26 expects per run. Still ~22s end-to-end on a warm cache.
This commit is contained in:
parent
624f5ce00b
commit
09f81d77de
1 changed files with 26 additions and 1 deletions
|
|
@ -121,13 +121,27 @@ async function pgExec(sql: string): Promise<string> {
|
|||
return out.trim();
|
||||
}
|
||||
|
||||
// Returns the count of audit rows for (user, eventType). Used to assert
|
||||
// that the security_events INSERT actually committed — historically this
|
||||
// was silently broken because the SQL builder collapsed undefined params
|
||||
// into literal nothing, which the catch swallowed as "(non-critical)".
|
||||
async function countSecurityEvents(userId: string, eventType: string): Promise<number> {
|
||||
const out = await pgExec(
|
||||
`SELECT COUNT(*) FROM auth.security_events WHERE user_id = '${userId}' AND event_type = '${eventType}';`
|
||||
);
|
||||
return parseInt(out, 10);
|
||||
}
|
||||
|
||||
// ─── Cleanup at the end so failed runs don't leak ────────────────────
|
||||
|
||||
afterAll(async () => {
|
||||
if (!createdUserId) return;
|
||||
try {
|
||||
// security_events would also CASCADE on auth.users delete, but we
|
||||
// drop it explicitly so the cleanup is obvious from reading.
|
||||
await pgExec(
|
||||
`DELETE FROM auth.encryption_vault_audit WHERE user_id = '${createdUserId}';
|
||||
`DELETE FROM auth.security_events WHERE user_id = '${createdUserId}';
|
||||
DELETE FROM auth.encryption_vault_audit WHERE user_id = '${createdUserId}';
|
||||
DELETE FROM auth.encryption_vaults WHERE user_id = '${createdUserId}';
|
||||
DELETE FROM auth.users WHERE id = '${createdUserId}';`
|
||||
);
|
||||
|
|
@ -149,6 +163,13 @@ test('full register → verify → login → vault → logout flow', async () =>
|
|||
expect(reg.json.user?.id).toBeTruthy();
|
||||
createdUserId = reg.json.user!.id;
|
||||
|
||||
// 1a. Audit row was actually committed.
|
||||
// Catches the bug class where security.logEvent silently swallows
|
||||
// a SQL error (e.g. undefined params collapsing the values list)
|
||||
// and the audit log goes into the void.
|
||||
const registerAuditCount = await countSecurityEvents(createdUserId, 'REGISTER');
|
||||
expect(registerAuditCount).toBe(1);
|
||||
|
||||
// 2. Wait for the verification email to land in mailpit
|
||||
const mail = await waitForMail(TEST_EMAIL);
|
||||
expect(mail.html.length).toBeGreaterThan(0);
|
||||
|
|
@ -188,6 +209,10 @@ test('full register → verify → login → vault → logout flow', async () =>
|
|||
expect(login.json.refreshToken).toBeTruthy();
|
||||
const jwt = login.json.accessToken!;
|
||||
|
||||
// 5a. Audit row for the successful login was committed too.
|
||||
const loginAuditCount = await countSecurityEvents(createdUserId, 'LOGIN_SUCCESS');
|
||||
expect(loginAuditCount).toBe(1);
|
||||
|
||||
// 6. Validate the JWT against the same service that minted it
|
||||
const validate = await postJson<{ valid: boolean; payload?: { sub: string; email: string } }>(
|
||||
'/api/v1/auth/validate',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue