first commit
This commit is contained in:
73
docs/api-stack/api/api-host/src/admin-api/audit-sink.md
Normal file
73
docs/api-stack/api/api-host/src/admin-api/audit-sink.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# `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 `AdminAuditSink` interface so it composes with
|
||||
the admin API's mounting helper.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
// 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.
|
||||
Reference in New Issue
Block a user