2.4 KiB
audit-sink.ts
Purpose
MemoryAdminAuditSink is the in-memory default audit sink for the
host's admin API. Every admin endpoint emits a structured
AdminAuditRecord after the request settles — the sink decides what
to do with it. The in-memory sink records into a local array suitable
for tests + dev; production deployments swap in a sink that forwards
to @suaveplan/audit-logging, syslog, or a managed audit pipeline.
The sink interface is intentionally narrow (emit(record)) so the
admin API never depends on a specific audit backend. The
AdminAuditRecord shape carries the principal id, action,
optional plugin name, request params, outcome (success / failure),
and the failure cause when applicable.
Features
- Zero-dependency in-memory recorder.
snapshot()reads without clearing — useful for asserting state across multiple admin calls.drain()reads + clears in one atomic step.- Implements the public
AdminAuditSinkinterface so it composes with the admin API's mounting helper.
Usage: Basic
import { MemoryAdminAuditSink } from "@suaveplan/api-host/admin-api";
const sink = new MemoryAdminAuditSink();
sink.emit({
at: new Date().toISOString(),
principal: { id: "alice", scopes: ["host:admin"] },
action: "plugin.start",
plugin: "@acme/billing",
params: {},
outcome: "success",
});
console.log(sink.snapshot().length); // 1
Usage: Advanced
// In an integration test — drain between scenarios.
const sink = new MemoryAdminAuditSink();
// ... hit admin endpoint ...
const first = sink.drain();
// ... hit admin endpoint again ...
const second = sink.drain();
API Reference
new MemoryAdminAuditSink()— zero-arg ctor.emit(record)— append to the in-memory log.snapshot(): readonly AdminAuditRecord[]— copy without clearing.drain(): readonly AdminAuditRecord[]— copy + clear.
Implementation Notes
emit is synchronous for the in-memory case — the admin API treats
the return value as Promise<void> | void so an async sink (HTTP
POST, IPC) plugs in identically. A failed emit raises
ADMIN.AUDIT_EMIT_FAILED on the request boundary — the admin call
is still considered a success because the side effect already
occurred, but the audit failure is logged.
The sink never persists past process exit. Production sinks MUST ship audit records to durable storage before acknowledging the emit; otherwise tamper-evidence is impossible to assert.