Skip to content

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

Terminal window
# CLI — recent entries (optionally per-project)
anvilbase logs --limit 50
anvilbase logs --project-id <id> --limit 100
# live tail (polls every 2s)
anvilbase logs --follow --project-id <id>
Terminal window
# API — paginated, filter by action
curl "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:

Terminal window
# CSV from a date, to a file
curl "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 actions
curl "http://localhost:39001/api/v1/admin/audit/export?format=json&project_id=<id>&action=project.delete" \
-H "Authorization: Bearer $ANVILBASE_TOKEN" -o deletes.json

Filters: 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:

Terminal window
# Who revealed the service_role key recently?
anvilbase logs --project-id <id> | grep secret.reveal.service_role
# All key/JWT rotations
curl ".../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.csv

See 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_log table 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; if pg_cron isn’t installed the prune functions still ship and can be invoked on demand.

  • On-demand prune. POST /api/v1/admin/audit/prune (and the anvilbase 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 uses ANVILBASE_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 via UPDATE 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 run
    anvilbase 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.