Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLIPublic
Assigneesstack72

Relationships

#2004 Serve Audit Log - Phase 1: Event pipeline and durable storage

Opened by stack72 · 9/4/2026· Shipped 9/4/2026

Summary

Add a tamper-evident audit event stream to swamp serve. Phase 1 establishes the core event pipeline: domain types, ring buffer, durable storage via remote audit stores, and handler instrumentation for the highest-value request types.

Design doc: https://claude.ai/code/artifact/40e51500-334b-40ef-89a9-dbd9185a109e

Goal

Events flow from handlers to a dedicated remote store. Denials are automatically audited for all handlers. The top ~20 highest-value handlers emit success/failure events.

Shippable because: Behind audit config — no config means zero behavior change. When configured, events silently persist to a remote store. No new CLI commands, no new API surface.

What gets built

Domain types (src/domain/serve_audit/)

  • audit_event.ts — AuditEvent entity, AuditCategory, AuditStage, AuditOutcome types. ULID ids, ISO 8601 timestamps, chain hashing.
  • ring_buffer.ts — generic RingBuffer with per-sink cursors (10,000 capacity)
  • audit_sink.ts — AuditSink port interface
  • audit_emitter.ts — AuditEmitter service (synchronous emit, ring buffer, async fan-out to sinks)
  • audit_event_builder.ts — builds events from handler context
  • audit_store.ts — AuditStore port interface (mirrors ControlPlaneStore)
  • mod.ts — barrel re-exports

Infrastructure (src/infrastructure/persistence/)

  • remote_audit_store.ts — AuditStore adapter using datastore extensions
  • audit_wal.ts — write-ahead log for durable delivery (local JSONL, replays on restart)

Serve integration

  • src/serve/audit_sinks/store_sink.ts — batches events into date-partitioned JSONL, writes to all configured store targets
  • src/serve/audited.ts — the audited() dispatch wrapper
  • src/serve/serve_config.ts — parse audit config block (stores, batch settings)
  • src/serve/handlers/shared.ts: Change authorizeOrReject to return { allowed, decision } instead of boolean. Add audit emitter to ConnectionContext. Emit denial events inside authorizeOrReject (Layer 1 — all 106 handlers get denial auditing from one code change).
  • src/serve/connection.ts — wrap first ~20 handler cases with audited(): auth, authorization grants, execution, secrets, admin

What it delivers

  • Automatic denial auditing across all 106 handlers
  • Success/failure events for authentication, authorization, execution, secrets, and admin handlers
  • Durable storage via batched JSONL to remote targets with multi-target fan-out
  • WAL for surviving backend outages
  • Chain hashing per instance for tamper evidence

Subsequent phases (not in scope)

  • Phase 2: Audit policy, complete handler coverage, query API and CLI
  • Phase 3: Real-time WebSocket streaming
  • Phase 4: Webhook and syslog sinks, bulk export, HMAC
  • Phase 5: Extension sinks, alerting, compliance templates
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 15 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/4/2026, 11:05:33 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack729/4/2026, 5:17:32 PM

Sign in to post a ripple.