mirror of
https://github.com/block/buzz.git
synced 2026-10-28 13:01:10 +00:00
Hash new audit entries from a TLV buffer built with one-byte field tags, big-endian u64 byte lengths, and raw values. Absent optional fields are omitted; present empty values retain their tag and zero length. This prevents bytes from moving between fields without restricting object IDs or inferring boundaries from field contents. Store an explicit `hash_version`. Migration 0048 labels existing rows as version 1, and new writers use version 2. Historical hashes are unchanged and mixed-version chains verify. The legacy encoding retains its original ambiguity; TLV protects new entries. Apply the migration before deploying the updated writers and verifiers. Tests cover both boundary collisions, absent versus empty fields, stable digests, unknown versions, mixed-version chains, and stored-row tampering. All 16 audit and 128 database unit tests passed. The six PostgreSQL audit tests passed against both migrated and fresh schemas, and a populated-row migration check preserved the historical hash. Full `just ci` passed. Related audit fixes: #4216 and #4249; issue #4173. Signed-off-by: Jordan Mecom <jm@squareup.com>
36 lines
1.5 KiB
Rust
36 lines
1.5 KiB
Rust
#![deny(unsafe_code)]
|
|
#![warn(missing_docs)]
|
|
//! Tamper-evident, **per-community** hash-chain audit log.
|
|
//!
|
|
//! Each community owns an independent chain: rows are keyed `(community_id, seq)`,
|
|
//! `seq` is monotonic *within a community*, and each entry chains to the previous
|
|
//! entry *of the same community* via SHA-256. The `community_id` is folded into the
|
|
//! hash, so a row lifted out of one community's chain can never verify inside
|
|
//! another's — chain identity carries the tenant. This is the audit half of the
|
|
//! non-interference floor (`auditHeads[c]` in `MultiTenantRelay.tla`): an audit
|
|
//! observation reveals only its own community's head.
|
|
//!
|
|
//! Writes for a given community are serialized by a **per-community** Postgres
|
|
//! advisory lock, so the chain stays consistent across relay processes without one
|
|
//! global lock serializing (and timing-coupling) every tenant.
|
|
//!
|
|
//! The `audit_log` table is owned by `migrations/` — this crate is pure chain
|
|
//! logic and ships no DDL.
|
|
|
|
/// Audit action types recorded in the log.
|
|
pub mod action;
|
|
/// Audit log entry types (stored and input).
|
|
pub mod entry;
|
|
/// Error types for audit operations.
|
|
pub mod error;
|
|
/// SHA-256 hash computation for audit entries.
|
|
pub mod hash;
|
|
/// Audit log service — append and verify entries.
|
|
pub mod service;
|
|
|
|
pub use action::AuditAction;
|
|
pub use entry::{AuditEntry, NewAuditEntry};
|
|
pub use error::AuditError;
|
|
pub use hash::{compute_hash, GENESIS_HASH};
|
|
pub use service::AuditService;
|