Skip to content

feat(relay): gate local-only audit retention behind off-host shipping attestation#282

Closed
jeremi wants to merge 1 commit into
mainfrom
feat/relay-audit-offhost-gate
Closed

feat(relay): gate local-only audit retention behind off-host shipping attestation#282
jeremi wants to merge 1 commit into
mainfrom
feat/relay-audit-offhost-gate

Conversation

@jeremi

@jeremi jeremi commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds deployment.evidence.audit_offhost_shipping: bool (default false) to DeploymentEvidenceConfig: an operator attestation that audit records are shipped off-host (e.g. to a log collector or SIEM).
  • Adds a new deployment gate relay.audit.retention_local_only, which fires when the audit sink is a local rotating file sink and the off-host shipping attestation is false. Rationale: a local rotating file sink caps retention, and an attacker with host access can destroy the audit trail; operators either ship logs off-host (and attest to it) or accept a posture finding.
  • stdout and syslog sinks are exempt from this gate: stdout retention is the orchestrator's log pipeline's concern, and syslog forwarding is the syslog daemon's own surface. This exemption rationale is documented in crates/registry-relay/docs/configuration.md (Findings catalog section) and as an inline comment on the gate definition.
  • Severity bindings: local and hosted_lab unbound (None), productionFindingWarn, evidence_gradeFindingError. Both are waivable finding tiers (no StartupFail/ReadinessFail behavior change).

Security review notes

This changes deployment posture, not authentication/authorization/signing:

  • Production deployments using a local file audit sink will start seeing a finding_warn-tier finding (relay.audit.retention_local_only) unless they either declare deployment.evidence.audit_offhost_shipping: true or add an explicit, dated waiver.
  • evidence_grade deployments using a local file sink without the attestation will see a finding_error-tier finding. This does not change startup or readiness behavior; finding_error is a posture-only tier, same as the existing relay.audit.best_effort and relay.auth.api_key_no_rotation_evidence gates.
  • No startup-fail or readiness-fail behavior changes anywhere in this PR.
  • Defaults are unchanged for local and hosted_lab profiles (the gate is unbound there), and the new evidence flag defaults to false (fail-closed: absence of the attestation keeps the gate active), consistent with the existing ingress_rate_limit / api_key_rotation evidence flags.
  • The gate is waivable like the other audit posture gates (relay.audit.best_effort), with the standard mandatory-reason, mandatory-expiry waiver mechanism.

Test coverage

Unit tests in crates/registry-relay/src/deployment/mod.rs:

  • audit_retention_local_only_binds_production_and_evidence_only: unbound under local/hosted_lab, FindingWarn under production, FindingError under evidence_grade, silent when the fact is false.
  • audit_retention_local_only_is_waivable: a waiver suppresses the finding and reports waived.

Integration tests in crates/registry-relay/tests/deployment_profile_gates.rs:

  • file_sink_without_attestation_warns_under_production: file sink + no attestation under production produces the finding at warn.
  • file_sink_with_attestation_is_clean_under_production: same config with audit_offhost_shipping: true is clean.
  • stdout_and_syslog_sinks_are_exempt_without_attestation: both stdout and syslog sinks, without attestation, are clean.
  • file_sink_without_attestation_errors_under_evidence_grade_and_is_waivable: evidence_grade with file sink + no attestation yields the error-tier finding, and a waiver for it is honored.

Verification

  • cargo fmt --check — pass
  • cargo check --locked --workspace --all-targets — pass
  • cargo clippy -p registry-relay --all-targets -- -D warnings — pass
  • cargo test --locked -p registry-relay — pass (all suites green; no HTTP endpoint changes, so no OpenAPI regeneration needed)

npm run check in docs/site was not run: node_modules is not installed in this worktree and a full install was out of scope for this change; the only docs edit is the crate-local source doc (crates/registry-relay/docs/configuration.md) that npm run generate syncs into the site.

Deviations from spec

The task referenced docs/site/src/content/docs/products/registry-relay/configuration.mdx as a file to hand-edit. That path is generated (via docs/site/src/data/repo-docs.yaml's sync of crates/registry-relay/docs/configuration.md, run by npm run generate) and is gitignored (docs/site/.gitignore excludes src/content/docs/products/), so it does not exist as a source file in this repo and must never be hand-edited. This PR instead edits the actual source, crates/registry-relay/docs/configuration.md, which is what gets synced into that generated page.

… attestation

A local rotating file audit sink caps retention, and an attacker with host
access can destroy the audit trail. Add the
deployment.evidence.audit_offhost_shipping attestation and the
relay.audit.retention_local_only gate, which fires only for a local file
sink without the attestation. Stdout and syslog sinks are exempt: stdout
retention is the orchestrator's log pipeline's concern, and syslog
forwarding is the syslog daemon's own surface. Bound at finding_warn under
production and finding_error under evidence_grade; unbound under
local/hosted_lab; waivable like the other audit posture gates.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi

jeremi commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Superseded by the integration meta-PR #292 — this branch is merged there unchanged (with cross-PR conflicts resolved once). Branch retained.

@jeremi jeremi closed this Jul 7, 2026
@jeremi jeremi deleted the feat/relay-audit-offhost-gate branch July 11, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant