import { createHmac, randomUUID } from "node:crypto"; import { mkdtempSync, mkdirSync, 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 { readSecureConfigCandidate } from "../../apps/api/src/secure-config.js"; const roots: string[] = []; const services: RegistrationService[] = []; const now = Date.parse("2026-07-28T11:00:00.000Z"); const adminPepper = Buffer.alloc(32, 0xa1); function hash(email: string) { return createHmac("sha256", adminPepper).update(email.trim().toLowerCase(), "utf8").digest("hex").toUpperCase(); } function createService(withPepper = true) { const root = mkdtempSync(join(tmpdir(), "dada-wp1-04-config-")); roots.push(root); const service = new RegistrationService({ ...(withPepper ? { adminAllowlistPepper: adminPepper } : {}), challengePepper: Buffer.alloc(32, 0xa2), clock: () => now, codeGenerator: () => "418205", currentPrivacyNoticeVersion: "p0a-registration-notice-v1", databasePath: join(root, "dada.sqlite3"), invitePepper: Buffer.alloc(32, 0xa3), resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 0xa4), }); services.push(service); return service; } function writeEvidence(file: string, value: unknown) { const directory = process.env.DADA_EVIDENCE_DIR_CONFIG; if (!directory) return; mkdirSync(directory, { recursive: true }); writeFileSync(resolve(directory, file), `${JSON.stringify(value, null, 2)}\n`); } 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-WP1-CFG-001-secure-revision", () => { it("applies one complete revision atomically and rolls invalid candidates back without sensitive persistence", async () => { const service = createService(); const firstEmail = "first-admin@example.invalid"; const replacementEmail = "replacement-admin@example.invalid"; const firstHash = hash(firstEmail); const replacementHash = hash(replacementEmail); const configPath = join(roots[0]!, "instance.json"); writeFileSync(configPath, `${JSON.stringify({ admin_allowlist_hashes: [firstHash], admin_recovery_hashes: [], schema_version: 1, secure_config_revision: 1, })}\n`); expect(readSecureConfigCandidate(configPath)).toEqual({ adminAllowlistHashes: [firstHash], adminRecoveryHashes: [], secureConfigRevision: 1, }); expect(service.applySecureConfig({ adminAllowlistHashes: [firstHash], adminRecoveryHashes: [], secureConfigRevision: 1, })).toMatchObject({ appliedRevision: 1, status: "applied" }); const resend = service.options.resend as MockResendAdapter; const sent = await service.sendAdminLoginCode({ clientKey: "first-admin-client", email: firstEmail }); const loggedIn = service.completeAdminLogin({ clientKey: "first-admin-client", code: resend.readLatestCode(firstEmail), idempotencyKey: "wp1-04-config-first-login-00000000001", registrationId: sent.registrationId, }); expect(service.applySecureConfig({ adminAllowlistHashes: [replacementHash], adminRecoveryHashes: [], secureConfigRevision: 2, })).toMatchObject({ appliedRevision: 2, status: "applied" }); expect(service.readAdminSession(loggedIn.sessionToken)).toBeUndefined(); const ordinaryUserId = randomUUID(); service.database.prepare(` INSERT INTO users ( user_id, normalized_email, role, status, counts_toward_stage_limit, registration_id, created_at ) VALUES (?, 'ordinary-conflict@example.invalid', 'user', 'active', 1, ?, ?) `).run(ordinaryUserId, randomUUID(), now); const conflictHash = hash("ordinary-conflict@example.invalid"); expect(() => service.applySecureConfig({ adminAllowlistHashes: [replacementHash, conflictHash], adminRecoveryHashes: [], secureConfigRevision: 3, })).toThrow(/identity_conflict/); expect(() => service.applySecureConfig({ adminAllowlistHashes: ["not-a-valid-hmac"], adminRecoveryHashes: [], secureConfigRevision: 3, })).toThrow(/hmac_invalid/); const withoutPepper = createService(false); expect(() => withoutPepper.applySecureConfig({ adminAllowlistHashes: [replacementHash], adminRecoveryHashes: [], secureConfigRevision: 1, })).toThrow(/admin_pepper_not_configured/); const state = service.database.prepare("SELECT * FROM secure_config_apply_state WHERE singleton = 1").get() as any; expect(state).toMatchObject({ allowlist_count: 1, applied_revision: 2 }); expect(Object.keys(state)).not.toContain("admin_allowlist_hashes"); const audits = service.database.prepare(` SELECT actor_type, actor_ref, operation_type, result, before_summary, after_summary FROM admin_operation_logs ORDER BY occurred_at `).all(); expect(audits).toEqual(expect.arrayContaining([ expect.objectContaining({ actor_ref: "backend_secure_config", actor_type: "system", result: "succeeded" }), expect.objectContaining({ actor_ref: "backend_secure_config", actor_type: "system", result: "failed" }), ])); const retention = service.database.prepare(` SELECT occurred_at, expires_at FROM admin_operation_logs ORDER BY occurred_at LIMIT 1 `).get() as { expires_at: number; occurred_at: number }; expect(retention.expires_at - retention.occurred_at).toBe(180 * 24 * 60 * 60 * 1_000); expect(() => service.database.prepare(` UPDATE admin_operation_logs SET result = 'failed' WHERE log_id = (SELECT log_id FROM admin_operation_logs LIMIT 1) `).run()).toThrow(/admin_operation_logs_immutable/); expect(() => service.database.prepare(` DELETE FROM admin_operation_logs WHERE log_id = (SELECT log_id FROM admin_operation_logs LIMIT 1) `).run()).toThrow(/admin_operation_logs_immutable/); const redactionProbe = JSON.stringify({ audits, state }); for (const forbidden of [firstEmail, replacementEmail, firstHash, replacementHash, adminPepper.toString("hex")]) { expect(redactionProbe).not.toContain(forbidden); } writeEvidence("config-result.json", { applied_revision: state.applied_revision, failed_candidates: ["identity_conflict", "hmac_invalid", "admin_pepper_not_configured"], status: "passed", }); writeEvidence("db-diff.json", { after: { allowlist_count: state.allowlist_count, applied_revision: state.applied_revision }, removed_admin_sessions_revoked: true, rejected_revision_advanced: false, status: "passed", }); writeEvidence("redaction.json", { forbidden_values_absent: true, stored_secure_state_fields: Object.keys(state).sort(), status: "passed", }); }); });