feat(audit): off-box chain-head export, verify-heads, maintenance login (ScadaBridge#107)
Item 1 (owner decision: no signing). AuditLog:HashChain:HeadExport (default
off): both centrals periodically read every month's chain head (LastSeq,
LastHash, purge anchor, chained rows, tombstones; one snapshot under the
chain lock SHARED) and append the changed heads to a sink the DB login cannot
write - File (append-only JSONL per node per day, local or UNC) or Syslog
(RFC 5424 over UDP / TCP octet counting). `audit verify-heads --path` reads
those records back (file or syslog-collector lines) and the new
VerifyAuditChainHeads command checks each against the database: Matches /
Extended / Purged, or Mismatch / Regressed / MissingHead / MissingLink /
CountMismatch (exit 3). AuditChainHeadStoreTests forges a chain with the
production hasher: verify-chain says Intact, verify-heads says Mismatch.
Item 3. AuditLog:MaintenanceConnectionString (${secret:}-capable, unset =
today's single login) runs the chain job, chain verify / head export, the
partition switch-out + archive and the per-channel purge on
AuditMaintenanceContext (keyed audit-maintenance repository/archive, purge
actor prefers them). AuditMaintenanceLoginTests runs the hardened setup on
SQL Server: writer (datareader/datawriter/audit_writer) ingests and is
refused chaining and deleting; the chainer+purger login does the full cycle.
Two-login grants documented in Component-AuditLog.md.
Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -501,7 +501,11 @@ See §8.2. Contract: unredacted secrets never persist. Safety net over-redacts o
|
||||
- Purges keep the chain verifiable: the partition switch records a checkpoint anchor on
|
||||
the month's chain head; the per-channel DELETE leaves a tombstone per chained row.
|
||||
- Verifiable via `scadabridge audit verify-chain --month YYYY-MM` (first break reported
|
||||
with partition, `ChainSeq`, `EventId`). Unsigned; signing / external anchoring are open.
|
||||
with partition, `ChainSeq`, `EventId`). Unsigned (owner decision, ScadaBridge#107): instead
|
||||
the per-month heads are exported off-box (`AuditLog:HashChain:HeadExport`, append-only files
|
||||
or syslog, default off) and `scadabridge audit verify-heads` checks them against the database.
|
||||
The chain job and both purge paths can run on a separate maintenance login
|
||||
(`AuditLog:MaintenanceConnectionString`).
|
||||
- Default **off** (`AuditLog:HashChain:Enabled`). Full design: Component-AuditLog.md,
|
||||
Security & Tamper-Evidence.
|
||||
|
||||
@@ -598,6 +602,7 @@ New `scadabridge audit` command group:
|
||||
- `scadabridge audit query --site <s> --since <t> --kind <k> [...]` — same filter set as the UI.
|
||||
- `scadabridge audit export --since <t> --until <t> --format csv|jsonl|parquet --output <path>` — bulk export, server-side streaming.
|
||||
- `scadabridge audit verify-chain --month <YYYY-MM>` — hash-chain verification (when §11.4 is enabled).
|
||||
- `scadabridge audit verify-heads --path <file-or-dir>` — off-box exported chain heads vs the database (ScadaBridge#107).
|
||||
|
||||
Requires the same **OperationalAudit** / **AuditExport** permissions as the UI.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user