import { randomUUID } from "node:crypto"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { RegistrationService } from "../../apps/api/src/registration.js"; import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js"; import { wp604OperationMatrix } from "../fixtures/wp6-04-audit.js"; const roots: string[] = []; const services: RegistrationService[] = []; const now = Date.parse("2026-08-04T09:30:00.000Z"); function fixture() { const root = mkdtempSync(join(tmpdir(), "dada-wp6-04-integration-")); roots.push(root); const registration = new RegistrationService({ challengePepper: Buffer.alloc(32, 0xb1), clock: () => now, currentPrivacyNoticeVersion: "p0a-registration-notice-v1", databasePath: join(root, "dada.sqlite3"), invitePepper: Buffer.alloc(32, 0xb2), inviteCodeGenerator: () => "fixture-invite-code", resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 0xb3), }); services.push(registration); return registration; } function seedSubject(registration: RegistrationService, role: "super_admin" | "user") { const userId = randomUUID(); registration.database.prepare(` INSERT INTO users ( user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at ) VALUES (?, ?, ?, 'active', ?, ?, ?) `).run(userId, `${role}-${userId}@example.invalid`, role, role === "user" ? 1 : 0, randomUUID(), now); if (role === "super_admin") { registration.database.prepare("INSERT INTO admin_access (user_id, allowed) VALUES (?, 1)").run(userId); } return userId; } afterEach(() => { for (const service of services.splice(0)) service.close(); for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true }); }); describe("TDD-WP6-AUD-001-sensitive-operations", () => { it("writes invite and user status audits in the same transaction as the mutation", () => { const registration = fixture(); const adminId = seedSubject(registration, "super_admin"); const userId = seedSubject(registration, "user"); const adminOperations = registration as RegistrationService & { createAdminInvite(input: { actorId: string; expiresAt: number; maxUses: number }): { code: string; inviteId: string }; changeUserStatus(userId: string, status: "suspended" | "deleted", actorId: string): void; }; const invite = adminOperations.createAdminInvite({ actorId: adminId, expiresAt: now + 86_400_000, maxUses: 1 }); adminOperations.changeUserStatus(userId, "suspended", adminId); expect(registration.database.prepare(` SELECT operation_type, target_ref FROM admin_operation_logs WHERE operation_type IN ('invite_create', 'user_status_change') ORDER BY occurred_at `).all()).toEqual([ { operation_type: "invite_create", target_ref: invite.inviteId }, { operation_type: "user_status_change", target_ref: userId }, ]); registration.database.exec(` CREATE TRIGGER force_user_status_audit_failure BEFORE INSERT ON admin_operation_logs WHEN NEW.operation_type = 'user_status_change' BEGIN SELECT RAISE(ABORT, 'forced_audit_failure'); END; `); expect(() => adminOperations.changeUserStatus(userId, "deleted", adminId)).toThrow("forced_audit_failure"); expect(registration.database.prepare("SELECT status FROM users WHERE user_id = ?").get(userId)).toEqual({ status: "suspended" }); const evidenceRoot = process.env.DADA_EVIDENCE_DIR_WP6_AUD; if (evidenceRoot) { mkdirSync(evidenceRoot, { recursive: true }); writeFileSync(resolve(evidenceRoot, "operation-matrix.json"), `${JSON.stringify({ operations: wp604OperationMatrix }, null, 2)}\n`); writeFileSync(resolve(evidenceRoot, "db-diff.json"), `${JSON.stringify({ audit_failure_rollback: { user_status: "suspended" }, tables: { admin_operation_logs: "append_only", private_content_access_logs: "append_only_separate" }, }, null, 2)}\n`); } }); });