Skip to content

Audit Integrity

Audit integrity is a security property, not a feature: the platform's records must be trustworthy enough to reconstruct who did what — including destructive and administrative actions — and to detect or survive attempts to erase activity. The design goals and their mechanisms:

Append-only events

Goal: once recorded, activity cannot be altered or removed.

Mechanisms (see Events & Audit):

  • events, admin_audit_log, and admin_health_history grant service_role only SELECT+INSERT — no UPDATE, no DELETE.
  • Each has an append-only trigger raising an exception on UPDATE/DELETE/TRUNCATE.
  • RLS is enabled with zero policies, so no browser role can read them either.

Threat addressed: a compromised session or API bug rewriting history to conceal an action. Even the application's own credential cannot rewrite the streams.

Atomic destructive operations

Goal: a destructive operation cannot succeed without its audit record.

rpc_delete_report (migration 034) performs the pre-image capture, the DELETE, and the forensic admin_write_audit call (which dual-writes the canonical report.deleted event) in one transaction. If the audit write fails, the deletion rolls back. Delete-first-log-after is structurally impossible — the "log" is a participant in the mutation, not a follow-up call.

Threat addressed: silent deletion of cases (data loss with no trail). The same pattern applies to every admin mutation: admin_write_audit runs inside the RPC transaction, so an admin action can never exist without its reason + before/after record.

Actor identity

Goal: attribution cannot be forged or laundered through display text.

  • actor_id is the canonical Discord ID (or api-key for the bot system actor), passed as a dedicated parameter derived from the authenticated session — never from client-supplied text.
  • actor_name is a display snapshot and is explicitly not identity.
  • The bot cannot impersonate an agent: bot writes carry the system identity, and agent_rank is not bot-settable.
  • Historical backfills assign identity only on exact identifier matches (034), never by guessing from names.

Threat addressed: forged attribution — an attacker writing an action "as" another agent, or hiding their own identity inside a display-name field.

Database-level authority

Goal: application bugs cannot bypass the audit contract.

The RPCs own both the mutation and its event/audit writes inside one transaction (033/034). Application-level event writes (event_service) are best-effort by design for non-critical telemetry, but every mutation whose integrity depends on its record goes through the transactional path. RPC EXECUTE is service_role-only (016), and the field/status/rank guards re-check inside the database.

Threat addressed: a route that forgets to record an event, or a future endpoint that performs a bare table write on an audited resource.

Historical integrity

Goal: history is not silently rewritten.

  • Trigger-protected append-only streams (above).
  • The only exception is the guarded 034 actor-identity backfill, which is non-destructive (adds actor_id where identity is unambiguous), idempotent, and re-enables the trigger in every path.
  • Retention: timeline/events have no FK to reports, so Director report deletions leave the audit trail intact (migration 017 model).

Threat addressed: "scrub the record" attacks that combine a privileged deletion with an audit purge.

Trust model summary

The audit streams do not depend on any single component: grants restrict the roles, triggers block rewrites, transactions bind records to mutations, and identity is derived from authentication. If one layer fails (e.g. a grant is misconfigured), the others still hold.