import { appendFile, mkdir, readFile } from "node:fs/promises"; import { dirname } from "node:path"; import type { PermissionConfig } from "./config.ts"; import type { AccessRequest } from "./policy.ts"; export interface AuditEntry { timestamp: string; tool: string; capability: string; zone: string; resource: string; decision: "allow" | "deny"; source: "profile" | "grant" | "judge" | "user" | "sandbox"; reason?: string; agent?: string; } export class AuditLog { constructor(private readonly config: () => PermissionConfig) {} async record( request: AccessRequest, decision: AuditEntry["decision"], source: AuditEntry["source"], reason?: string, ): Promise { const config = this.config(); if (!config.audit.enabled) return; const entry: AuditEntry = { timestamp: new Date().toISOString(), tool: request.tool, capability: request.capability, zone: request.zone, resource: request.resource, decision, source, reason, agent: request.agent, }; await mkdir(dirname(config.audit.path), { recursive: true }); await appendFile(config.audit.path, `${JSON.stringify(entry)}\n`, { encoding: "utf8", mode: 0o600 }); } async recent(limit = 20): Promise { try { const lines = (await readFile(this.config().audit.path, "utf8")).trim().split("\n").filter(Boolean); return lines.slice(-limit).map((line) => JSON.parse(line) as AuditEntry); } catch { return []; } } }