DSSE & Policy Hash Linkage (FL6)

Goal: Every export, replay report, and anchor manifest is tied to the exact policy digest that produced it and is verifiable offline via DSSE.

Binding rules

  1. Policy digest: policyVersion (SHA-256 over policy bundle) is mandatory in ledger events, projections, exports, and replay reports.
  2. DSSE payload types
    • application/vnd.stella-ledger-export+json — export manifests (hashlist + filtersHash).
    • application/vnd.stella-ledger-anchor+json — Merkle anchors (see merkle-anchor-policy.md).
    • application/vnd.stella-ledger-harness+json — replay harness report.
    • Alert evidence bundle archives use media type application/vnd.stellaops.findings.evidence-bundle.v1+tar inside manifest.json; their HTTP download remains application/gzip.
  3. Hashlists: export manifests contain sha256 for each emitted NDJSON line (lineDigest), plus a dataset digest (datasetSha256) over concatenated line digests. Replay harness exposes eventStreamChecksum and projectionChecksum.
  4. Policy linkage: DSSE payload must include policyHash and schemaVersion to prevent replay under mismatched policy versions.

Offline verification flow

  1. Verify DSSE signature (local key or Rekor transparency log if online).
  2. Recompute dataset checksum with tools/LedgerReplayHarness/scripts/verify_export.py --input <export.ndjson> --expected <datasetSha256>.
  3. Cross-check policyHash in payload matches policy bundle in use; mismatch → block import/export.
  4. For alert evidence bundles, recompute the gzip tar SHA-256 and compare it with /v1/alerts/{alertId}/bundle/verify; when the alert id contains image path slashes, call /v1/alerts/bundle/verify?alert_id=<url-encoded-alert-id> instead. If a DSSE signature envelope is supplied, the verifier requires the envelope payload to bind to the regenerated bundle hash and validates the signature against configured PEM trust roots (findings:ledger:evidenceBundles:dsseVerification:trustRootPaths or trustedPublicKeysPem).
  5. Local-compose trust roots: devops/compose/docker-compose.findings-dsse-dev.yml. The overlay was deleted at SPRINT_20260722_010 FND-10 (it keyed the volume mount and findings__ledger__EvidenceBundles__DsseVerification__TrustRootPaths__0 to the retired findings-ledger-web) and re-created against findings-web at FND-21 on 2026-08-28. The section binds on the consolidated host: LedgerServiceOptions.SectionName is findings:ledger (src/Findings/StellaOps.Findings.Ledger/Options/LedgerServiceOptions.cs:8), findings-web binds that section at src/Findings/StellaOps.Findings.WebService/Program.cs:163-171, and its PostConfigure overrides only Database.ConnectionString, so the EvidenceBundles subtree survives the bind. The value is read at src/Findings/StellaOps.Findings.Ledger/Services/DsseEvidenceBundleSignatureVerifier.cs:59,69. Point FINDINGS_DSSE_TRUST_ROOT_DIR at a host directory of PEM public keys and layer the overlay on the live -f list (read it off the running container’s com.docker.compose.project.config_files label). Verify the setting took effect by the error code, not by the container starting: without trust roots the verify endpoints answer finding.evidence_bundle.trust_roots_required; with them the call proceeds to signature verification. Production trust roots are provisioned through the deployment’s normal config channel; this overlay is only a development shortcut.

File locations

Change management