Skip to content

feat(security): audit_trail_events table, list endpoint and Maple's own events - #2510

Merged
Makisuo merged 11 commits into
mainfrom
audit-trail/table
Nov 13, 2026
Merged

Makisuo merged 11 commits into
mainfrom
audit-trail/table

Merge remote-tracking branch 'origin/main' into audit-trail/table

61c0c83
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review succeeded Nov 13, 2026 in 4m 18s

Confidence 10/10 · No issues found

🟢 Confidence 10/10 · safe to merge. The only unpinned cost is the second ingest the consumer awaits before acking; every new read, write and mapping path has a failing test.
no findings · tests covered · risk medium · 4/4 new units observable

Adds the unified audit trail: audit_trail_events, AuditTrailService, an admin-gated list endpoint, and Maple's changes/refusals copied into it. Additive, ingest-pinned and well tested, so safe once the Tinybird schema is deployed. The two open VcsWebhookEnqueueFailure issues are untouched: http-graph.ts only registers the new route.

  • AuditTrailService writes audit_trail_events and lists it keyset-paginated on (OccurredAt, Id)
  • GET /internal/audit-trail/events behind audit_log:read, session-only, cursor-validated
  • The audit-events consumer and direct writes copy changes and refusals into the trail
  • audit_trail_events is hidden from raw SQL and pinned to the managed warehouse

Before merge

Production impact

Open errors in the changed files (1)
Issue Service Occurrences File
@maple/api/routes/VcsWebhookEnqueueFailure (2 issues) maple-api 9 apps/api/src/runtime/http-graph.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/audit-trail.http.ts 3.0k maple 3.0k/day, 2.1% err
packages/backend/src/services/audit-trail/providers/maple.ts 3.0k maple 3.0k/day, 2.1% err
packages/domain/src/audit-trail.ts 3.0k maple 3.0k/day, 2.1% err
packages/backend/src/services/warehouse/warehouse-catalog.ts 67 GET /v2/audit_log 67/day, 0.0% err
packages/backend/src/services/audit-trail/AuditTrailService.ts 21 AuditTrailService.list 21/day, 0.0% err
Telemetry this change adds and removes (1)
  • ➕ span name AuditTrailService.write · packages/backend/src/services/audit-trail/AuditTrailService.ts:101
What was checked
  • Every new read filters OrgId and is pinned to the managed route (queries/audit-trail.ts:62, datasource-routing.ts:15)
  • Keyset cursor and unmerged-copy dedupe are pinned by real SQL assertions (AuditTrailService.test.ts:141, :173)
  • The actor email filter is redacted from span URLs, asserted against Effect's defaults (api-observability.test.ts:20)
Observability coverage: 4 of 4 changes observable
Change Kind Observable Evidence
GET /internal/audit-trail/events HTTP entrypoint yes Effect HttpApi server span plus Effect.fn("AuditTrailService.list"); live data shows AuditTrailService.list at 21 calls/day, p95 115 ms
AuditTrailService.list warehouse query outbound database read yes Goes through WarehouseQueryService.compiledQuery with profile list, the same instrumented path as audit_log
AuditTrailService.write ingest outbound database write yes WarehouseQueryService.ingest with bestEffort downgrades the failed insert to a Warn instead of an Error span
Audit-trail copy in the audit-events consumer queue consumer work yes Runs inside the existing AuditEvents.processBatch span; a dropped copy is logged with org, count and cause

61c0c83 · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.