Skip to content

Relay bricks permanently when its audit chain is corrupted by an unclean stop; no supported recovery path #196

Description

@jeremi

Observed

In a long-running compose lab (Solmara), two Relay containers came back from an unclean stop with a torn last line in their audit.jsonl. From that point every audited request failed closed:

audit.write_failed: audit chain verification failed: line 103 prev_hash mismatch

and callers saw 5xx (audit.write_failed from the relay; upstream Notary evaluations surfaced it as source.unavailable). The services stayed in that state indefinitely; health checks reported the containers healthy while every real request failed.

Why (code path on main)

JsonlFileSink recomputes the retained chain tail before appending (tail_hash_from_files / verify_chain in crates/registry-platform-audit/src/lib.rs). Any corruption in the retained JSONL set makes every subsequent append return AuditError::ChainVerification, which the relay maps to audit.write_failed (crates/registry-relay/src/audit/mod.rs). Size-based rotation exists, but there is no path that ever moves a corrupt segment aside.

What's missing

Failing closed is the right default for audit integrity; the gap is operability:

  1. No supported recovery. The only way out today is manual surgery inside the audit volume (stop the relay, move audit.jsonl aside, restart). Nothing documents this, and doing it silently discards the operator-visible record of the discontinuity. A supported operation (CLI or admin endpoint) should quarantine the corrupt segment, record an explicit chain-break event (why, when, tail hash before/after), and restart the chain, ideally anchored via the existing ChainVerificationAnchors mechanism.
  2. No startup detection. The relay only discovers the broken chain on the first audited request. Verifying the retained chain at startup (and reflecting it in readiness/health) would turn a confusing per-request 5xx into an actionable operational signal.
  3. Crash consistency. The corruption source was an unclean container stop, which is routine in container platforms. The append path could be hardened against torn writes (e.g. tolerate and quarantine a partial final line as a distinct, explicitly-logged case rather than a generic prev_hash mismatch).

Notes

Audit integrity is a security-sensitive area per CONTRIBUTING; any fix needs explicit review notes on how the chain break is itself made tamper-evident.

Metadata

Metadata

Assignees

No one assigned

    Labels

    1.0-blockerBlocks the 1.0 release intent.area:platformRegistryStack platform and cross-product ownership.area:relayRegistry Relay ownership.bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions