Repository navigation
feat(security): audit_trail_events table, list endpoint and Maple's own events - #2510
Merged
Merged
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.
AuditTrailServicewritesaudit_trail_eventsand lists it keyset-paginated on(OccurredAt, Id)GET /internal/audit-trail/eventsbehindaudit_log:read, session-only, cursor-validated- The audit-events consumer and direct writes copy changes and refusals into the trail
audit_trail_eventsis hidden from raw SQL and pinned to the managed warehouse
Before merge
- Migration · Check it is safe on production data and with the code still deployed ·
packages/domain/src/clickhouse/migrations/0064_audit_trail_events.ts - Warehouse · Deploy the schema before the code that reads it ·
packages/domain/src/tinybird/datasources.ts - Manual · Deploy the Tinybird schema from this branch in both regions (
bun run tinybird:deploy: check, start, promote) before merging
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
OrgIdand 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
actoremail 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.
Loading