Audit Trail
Every security-relevant action is recorded in a hash-chained, optionally Ed25519-signed audit log. Max 1000 entries in memory, with NDJSON persistence.
Audit Actions (33 types)
SecureAuditEntry
| Field | Description |
|---|---|
| seq | Monotonic sequence number |
| principal | PrincipalId who performed the action |
| action | AuditAction enum variant |
| outcome | Success, Denied, or Failed(reason) |
| prev_hash | SHA-256 hex of the previous entry (chain) |
| hash | SHA-256 hex of this entry's content |
| signature | Optional Ed25519 hex signature |
Chain Verification
verify_chain() walks every entry checking: hash matches computed hash, prev_hash matches previous entry's hash, and Ed25519 signature verifies against the signing key.
SQL Sinks & Offline Verifier
Two optional SQL sinks mirror the NDJSON chain into a relational store
so auditors can query and verify it offline. PostgresSink
and SqliteSink share a small per-Org
ChainState cache so the latest
this_hash is available without re-reading the row on every append.
The auditor pulls the rows in seq order for one Org and feeds them to
verify_chain(). The function recomputes each row’s
this_hash from the canonical event payload and the previous row’s
this_hash, anchored at genesis_hash(),
and returns one of three verdicts:
| Verdict | Meaning |
|---|---|
| Valid | Every row’s hashes recompute and link correctly. |
| HashMismatch { seq } | A row’s payload or stored hash was tampered with. |
| LinkBreak { seq } | A row was inserted, deleted, or reordered. |
Periodic Merkle roots over closed chain ranges are published separately — see Merkle root attestation for the publication pipeline and offline proof verifier.
Questions?
Reach out for help with integration, deployment, or custom domain codecs.