Files
buzz/schema/tables/public/relay_operator_audit.sql

26 lines
1.5 KiB
SQL

-- ── Relay operator audit (append-only roster mutation trail) ─────────────────
-- One row per PUT/DELETE /operators/{pubkey} mutation. The roster is the
-- deployment-wide root of trust and its mutations overwrite/remove in place;
-- this append-only trail records who granted, elevated, or revoked whom, and
-- when, so privilege changes are as auditable as the enforcement actions those
-- principals perform. Written only inside the upsert/delete transactions; no
-- UPDATE/DELETE path.
CREATE TABLE relay_operator_audit (
id UUID NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(),
actor_pubkey BYTEA NOT NULL CHECK (length(actor_pubkey) = 32),
target_pubkey BYTEA NOT NULL CHECK (length(target_pubkey) = 32),
op TEXT NOT NULL CHECK (op IN ('grant', 'revoke')),
prev_role TEXT CHECK (prev_role IN ('operator', 'moderator')),
new_role TEXT CHECK (new_role IN ('operator', 'moderator')),
-- created_at is wall-clock occurrence time (clock_timestamp()), informational
-- only — not monotonic, so it never establishes order. `seq` is the sole
-- chronology key: mutations write their audit row under the serializing lock,
-- so identity order equals the true privilege chain. Reads use ORDER BY seq.
created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
seq BIGINT GENERATED ALWAYS AS IDENTITY
);
CREATE INDEX idx_relay_operator_audit_target
ON relay_operator_audit (target_pubkey, seq);