Files
2026-05-27 23:29:53 +01:00

3.0 KiB

@suaveplan/api-audit-file — file-rotating audit sink

Package: @suaveplan/api-audit-file Status: PROPOSED Type: new-package Stage: 8 — see umbrella openspec/changes/api-plugin-foundation/

Why

Per design doc §12.5, some operators (single-host deployments, on-prem environments without a log shipper) need an audit sink that writes to a local file with rotation. This package is that sink. It mirrors the api-audit-stdout contract (audit capability, JSON-per-line, HMAC-signed records) and adds size + time rotation.

What changes

  • ADDED: createFileAuditSink({ path, hmacKey, clock, rotation }) — returns an AuditSink. Writes JSON-per-line with HMAC signature to path. Rotation policy: size-based (maxSizeBytes, default 100 MB) AND time-based (maxAgeMs, default 1 day). Rotated files are renamed to <path>.<utc-ISO>.log and optionally gzipped if compress: true.
  • ADDED: Retention policy — maxFiles (default 30) keeps the most recent N rotated files; older files are deleted with a api.audit.rotation_evicted_total{sink="file"} increment.
  • ADDED: Atomic-write strategy — writes go through a temp file path then fsync + rename for crash safety, OR an append-on-open fd model gated by host.audit.file.appendMode ("strict-sync" | "append").
  • ADDED: Same backpressure model as api-audit-stdout: bounded queue, observable drops via api.audit.dropped_total{sink="file"}.
  • ADDED: Error codes (AUDIT_FILE_*): INVALID_RECORD, WRITER_FAILED, QUEUE_FULL, ROTATION_FAILED, RETENTION_FAILED, PATH_NOT_WRITEABLE.

Out of scope

  • Cross-host audit aggregation — separate package.
  • Encryption at rest — caller handles (the sink writes plaintext + HMAC; disk-encryption is outside scope).
  • Centralised log shipping (fluentd, vector, …) — operators wire the rotated files into those tools.

Source mapping

Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.

Requirement Design doc section
File-rotating audit sink (api-audit-file) §12.5
HMAC-signed records §12.5
Same audit capability contract §12.5

Verification approach

  • src/sink/sink.test.ts — write 1000 records, assert all are present, JSON-parseable, HMAC-valid.
  • src/rotation/rotation.test.ts — exercise size rotation (write enough bytes to exceed maxSizeBytes) and time rotation (advance FakeClock past maxAgeMs); assert rotated file exists with the expected timestamp suffix.
  • src/retention/retention.test.ts — create N+1 rotated files (with FakeClock), assert oldest is evicted and api.audit.rotation_evicted_total increments.
  • src/sink/sink.spec-conformance.test.ts — drop policy mirrors api-audit-stdout; observability assertions.
  • tests/dep-graph.test.ts — runtime deps (api-types, crypto-hash, error, logger, zod).

Migration impact

None — additive only. api-host registers this when host.audit.sink = "file".