Audit Logs
AnvilBase records every administrative action to an immutable, append-only audit log. Mutating management endpoints write a fire-and-forget entry; audit failures never block or fail the underlying request. Use it for compliance, incident response, and “who did what, when.”
What’s recorded
- Control-plane actions — project create/update/delete, key/JWT rotation, user
invite/remove, secret reveals, and security-sensitive config mutations: auth
settings & OAuth provider changes (
auth.settings.update,auth.provider.upsert/auth.provider.delete), SMS provider changes (auth.sms.configure/auth.sms.delete), SMTP + email-template changes (email.smtp.update,email.template.upsert/email.template.delete), and webhook lifecycle (webhook.create/update/delete/attach/detach). Details are masked — provider name, target host, table, port, from-address, or an SID’s last 4 — and never contain a secret (OAuth client secret, Twilio auth token, SMTP password, or webhook signing secret). - Auth events — sign-in, sign-out, failed attempts, MFA events, password reset.
- Storage access — object reads/writes/deletes (where enabled).
- Function invocations — invocations, errors, execution time (where enabled).
- Database query log — optional per-project toggle (has a performance cost; use sparingly).
Entries carry the action, the actor, the affected project/resource, a timestamp, and contextual metadata.
Read the log
# CLI — recent entries (optionally per-project)anvilbase logs --limit 50anvilbase logs --project-id <id> --limit 100
# live tail (polls every 2s)anvilbase logs --follow --project-id <id># API — paginated, filter by actioncurl "http://localhost:39001/api/v1/admin/audit?action=project.create&limit=20" \ -H "Authorization: Bearer $ANVILBASE_TOKEN"# → { entries, total, limit, offset }limit defaults to 50 (capped 100); action is an exact match (e.g.
project.create, secret.reveal.service_role).
Export for SIEM / compliance
Bulk-export as JSON or CSV (a downloadable attachment), with optional filters:
# CSV from a date, to a filecurl "http://localhost:39001/api/v1/admin/audit/export?format=csv&from=2026-05-01T00:00:00Z" \ -H "Authorization: Bearer $ANVILBASE_TOKEN" -o audit_log.csv
# JSON for one project's project.delete actionscurl "http://localhost:39001/api/v1/admin/audit/export?format=json&project_id=<id>&action=project.delete" \ -H "Authorization: Bearer $ANVILBASE_TOKEN" -o deletes.jsonFilters: format (json default | csv), project_id, action, from/to
(RFC3339), limit (default 10,000, capped 100,000). Feed the export into Splunk,
Elastic, Loki, or your SIEM of choice.
In the console
Project and platform views include an Audit screen with search, action filters, and date ranges, plus an export button.
Using the log in incident response
A few high-value queries:
# Who revealed the service_role key recently?anvilbase logs --project-id <id> | grep secret.reveal.service_role
# All key/JWT rotationscurl ".../admin/audit?action=project.rotate.jwt" -H "Authorization: Bearer $ANVILBASE_TOKEN"
# Failed auth attempts in a window (export + analyze)curl ".../admin/audit/export?action=auth.signin.failed&from=...&to=..." -o fails.csvSee API Keys & Scopes → Incident response.
Retention & integrity
-
Entries are append-only — there’s no update or delete path from the API, by design.
-
Automatic pruning (bounded growth). Both the
audit_logtable and the internal auth-event PGMQ transport are pruned on a nightly schedule so neither grows forever. The scheduled window is 90 days. On a stock deployment the prune runs as a pg_cron job in the platform database; ifpg_cronisn’t installed the prune functions still ship and can be invoked on demand. -
On-demand prune.
POST /api/v1/admin/audit/prune(and theanvilbase audit prune [--days N]CLI) prunes both stores immediately — for incident cleanup or to tighten retention ahead of a storage-pressure window. When--days/?days=is omitted it usesANVILBASE_AUDIT_RETENTION_DAYS(default 90; see Configuration). This env var sets the on-demand default only; the nightly window is the cron literal (change it viaUPDATE cron.job, see Monitoring).Terminal window # prune both stores past the server default window (90 days)curl -X POST "http://localhost:39001/api/v1/admin/audit/prune" \-H "Authorization: Bearer $ANVILBASE_TOKEN"# → { audit_log_deleted, auth_event_archive_deleted, retention_days }# or a tighter window for this runanvilbase audit prune --days 30 -
The retention window covers the whole platform log (rows without a project, and every project’s rows alike). The auth-event queue prune only sheds genuine poison messages (repeatedly-failed redeliveries) — a backlog of real, unprocessed events is never destroyed. Export regularly to immutable off-box storage if your compliance regime requires retention longer than the window.
-
Because the log survives upgrades (it’s immutable), it’s a reliable record across platform version changes within the retention window.
Best practices
- Export on a schedule to immutable, off-box storage (object lock / WORM) for regulated environments.
- Alert on sensitive actions (
secret.reveal.service_role,project.delete, platform-user creation) by tailing or ingesting the export into your SIEM. - Enable the optional database query log only when investigating — it’s the one audit source with a real performance cost.
Next: Network Security.