diff --git a/server/audit.ts b/server/audit.ts index 0af21af..73cd4ab 100644 --- a/server/audit.ts +++ b/server/audit.ts @@ -43,7 +43,8 @@ export let auditLog = function auditLog( }, ${ipAddress}, ${leafHashHex}) `; } catch (error: any) { - console.error("[Audit Logger] Failed to insert audit record:", error); + const msg = error?.code || error?.message || String(error); + console.error(`[Audit Logger] Failed to insert audit record: ${msg}`); } })(); }; diff --git a/server/tests/auth.test.ts b/server/tests/auth.test.ts index 65540b1..873077f 100644 --- a/server/tests/auth.test.ts +++ b/server/tests/auth.test.ts @@ -7,6 +7,7 @@ import { auditWrapper } from "../audit.ts"; import { rateLimitWrapper } from "../ratelimit.ts"; const originalSql = sqlWrapper.sql; +const originalAudit = auditWrapper.auditLog; function setMockSql(mockImpl: () => Promise) { sqlWrapper.sql = mockImpl as any; @@ -36,7 +37,6 @@ Deno.test("Phase 4: Audit Ledger Verification - Login failed", async () => { }); let auditArgs: any[] = []; - const originalAudit = auditWrapper.auditLog; auditWrapper.auditLog = (...args: any[]) => { auditArgs = args; }; @@ -57,7 +57,6 @@ Deno.test("Phase 4: Audit Ledger Verification - Login failed", async () => { assertEquals(auditArgs[1], "login_failed"); restoreMockSql(); - auditWrapper.auditLog = originalAudit; }); Deno.test("WebAuthn - /api/register/verify extracts PRF", async () => { @@ -397,6 +396,7 @@ Deno.test("Ephemeral 1-Click Magic Link Redemption (/pass)", async (t) => { } finally { valkeyGetStub.restore(); valkeyTtlStub.restore(); + auditWrapper.auditLog = originalAudit; } }, ); diff --git a/server/tests/scopes.test.ts b/server/tests/scopes.test.ts index caa01a0..4b7031e 100644 --- a/server/tests/scopes.test.ts +++ b/server/tests/scopes.test.ts @@ -4,8 +4,13 @@ import { app } from "../main.ts"; import { sqlWrapper } from "../db.ts"; import { valkey } from "../valkey.ts"; import { rateLimitWrapper } from "../ratelimit.ts"; +import { auditWrapper } from "../audit.ts"; const originalSql = sqlWrapper.sql; +const originalAudit = auditWrapper.auditLog; +const auditEvents: Array< + { action: string; resource?: string | null; details?: any } +> = []; function setMockSql(mockImpl: () => Promise) { sqlWrapper.sql = mockImpl as any; @@ -16,6 +21,14 @@ function restoreMockSql() { } rateLimitWrapper.checkRateLimit = () => Promise.resolve(true); +auditWrapper.auditLog = ( + _userId: string | null, + action: string, + resource: string | null, + details: Record | null, +) => { + auditEvents.push({ action, resource, details }); +}; Deno.test("Zero-Trust Scope Guards", async (t) => { const mockUserId = "user-id-guards"; @@ -385,6 +398,7 @@ Deno.test("Agent Session Delegation & Scoped Permissions", async (t) => { const json = await res.json(); assert(json.success === true); assert(json.newExpiresAt); + assert(auditEvents.some((e) => e.action === "session_extended")); } finally { sqlWrapper.sql = originalSql; valkeyStub.restore(); @@ -392,4 +406,10 @@ Deno.test("Agent Session Delegation & Scoped Permissions", async (t) => { } }, ); + + // Verify full audit coverage across delegation endpoints + assert(auditEvents.some((e) => e.action === "session_delegated")); + assert(auditEvents.some((e) => e.action === "session_scopes_updated")); + + auditWrapper.auditLog = originalAudit; });