- Introduced `BinaryReachabilityLifterTests` to validate binary lifting functionality. - Created `PackRunWorkerOptions` for configuring worker paths and execution persistence. - Added `TimelineIngestionOptions` for configuring NATS and Redis ingestion transports. - Implemented `NatsTimelineEventSubscriber` for subscribing to NATS events. - Developed `RedisTimelineEventSubscriber` for reading from Redis Streams. - Added `TimelineEnvelopeParser` to normalize incoming event envelopes. - Created unit tests for `TimelineEnvelopeParser` to ensure correct field mapping. - Implemented `TimelineAuthorizationAuditSink` for logging authorization outcomes.
5.9 KiB
Deterministic SBOM Composition
Status: Ready v1.0 (Sprint 136 linkage; fixtures dated 2025-12-03)
Owners: Scanner Guild · DevEx/CLI Guild · UI Guild · Docs Guild · Security Guild
Related Tasks:SCANNER-SURFACE-04,SURFACE-FS-07,SCANNER-EMIT-15-001,SCANNER-SORT-02,CLI-SBOM-60-001,CLI-SBOM-60-002,UI-SBOM-DET-01,UI-POLICY-DET-01,DOCS-SCANNER-DET-01,DOCS-POLICY-DET-01,DOCS-CLI-DET-01,SCANNER-CRYPTO-90-002,SCANNER-CRYPTO-90-003
1. Purpose
Guarantee that every container scan yields provably deterministic SBOM artifacts that can be verified offline. Each layer fragment is DSSE-signed before merge, _composition.json captures the canonical merge recipe, and the final CycloneDX inventory/usage SBOMs expose Merkle roots and stella.contentHash properties. CLI/UI/policy layers consume those signals to block non-deterministic releases and provide human-friendly diagnostics.
2. Scope
2.1 Fragment attestation
- Scanner Worker emits
layer.fragmentspayloads as canonical JSON (lexicographic keys, compact whitespace, normalized timestamps, ordered component arrays). - Each fragment is signed via DSSE (default Ed25519; PQ/Dilithium toggle routed through
ICryptoProviderRegistry). _composition.jsonrecords{layerDigest, fragmentSha256, dsseEnvelopeSha256}per fragment alongside the overall Merkle root.- Surface manifests append links to fragment DSSE envelopes so offline kits can fetch them without re-scan.
2.2 Canonical merge
- Merge order strictly follows
layerDigest(ascending hex) and thencomponent.identity.purl(fallback toidentity.key). - CycloneDX metadata gains:
properties["stellaops:stella.contentHash"]for each fragment and composition root.properties["stellaops:composition.manifest"]referencing_composition.jsonCAS URI.properties["stellaops:merkle.root"]for the composed BOM.
ScannerTimestamps.Normalizecontinues to zero fractional microseconds; SBOM timestamps should default to"0001-01-01T00:00:00Z"when no semantic timestamp is required.
2.3 Surface manifest extensions
SurfaceManifestArtifactgains optionalattestations[]with{kind, mediaType, digest, uri}for DSSE envelopes._composition.jsonis published as an additional artifact kindcomposition.recipe.- Surface reader/writer validate Merkle roots before caching manifest entries.
2.4 Tooling impacts
- CLI (
stella sbomer ...): addslayerandcomposeverbs, deterministic diff reporting, and offline verification per_composition.json. - UI/Policy: determinism badge, drift diffs, and a policy gate that blocks releases when fragment DSSE/verifications fail.
- Docs: new guides under
docs/scanner&docs/cliplus policy references detailing how to interpret determinism metadata. - Crypto: PQ-friendly DSSE toggle delivered via
SCANNER-CRYPTO-90-002/003so sovereign bundles can select Dilithium/Falcon.
3. Verification Flow (offline kit)
- Verify DSSE on each fragment (using
verifiers.json). - Recompute
sha256(c14n(fragment))and compare with_composition.json. - Re-run composition locally (using canonical ordering) and compare
sha256(c14n(composed))againstmanifest.properties["stellaops:merkle.root"]. - Optionally validate provided Merkle proofs (leaf → root) and attest that the UI/Policy gate marked the scan as deterministic.
3.1 Reference fixture (deterministic-compose)
- Path:
docs/modules/scanner/fixtures/deterministic-compose/(generated 2025-12-03 bygenerate.py). - Quick verify:
Expected Merkle root:
cd docs/modules/scanner/fixtures/deterministic-compose sha256sum -c hashes.txt jq -r '.payload' fragment-layer1.dsse.json | base64 -d | sha256sum jq -r '.merkleRootSha256' _composition.json jq -r '.properties[] | select(.name=="stellaops:merkle.root").value' bom.cdx.json963e421d21be2db87895ea5fd973a0ad71aa638499c274308e013d2b6c8243f6(matches_composition.jsonandbom.cdx.json). - Regenerate deterministically:
python generate.py && sha256sum -c hashes.txt(standard library only).
4. Deliverables Checklist
| Area | Deliverable |
|---|---|
| Scanner Worker | DSSE per fragment, _composition.json, canonical fragment serializer, Surface manifest updates |
| Emit pipeline | Layer-sorted composition, stella.contentHash, Merkle metadata, PQ-aware signing hooks |
| CLI | stella sbomer layer/compose/drift, verification commands, documentation |
| UI | Determinism badge, drift diagnostics, policy gate wiring |
| Docs | Updated scanner/cli/policy guides, offline kit instructions |
| Tests | Regression suites covering canonicalization, DSSE verification, PQ keypaths, Merkle roots |
5. Operational workflow (worker → CLI/UI/Policy)
- Worker: emit fragment DSSE +
_composition.jsoninto the surface manifest; persiststellaops:composition.manifestandstellaops:merkle.rootproperties on composed BOMs so downstream consumers do not recompute merges. - CLI: verify bundles offline with
stella sbomer compose --recipe docs/modules/scanner/fixtures/deterministic-compose/_composition.json --fragments-dir docs/modules/scanner/fixtures/deterministic-compose --verify(seedocs/cli/sbomer.md). The command should fail if any DSSE signature, Merkle root, or BOM hash diverges. - UI / Policy: render determinism badge using
stellaops:merkle.root; block promotion when_composition.jsonis missing or hashes disagree; expose drift diagnostics by recomputing composition locally and comparing to BOM properties. - Export/Offline: include
_composition.json, fragment DSSEs,bom.cdx.json, andhashes.txtwhen building Offline Kit bundles so replay jobs can validate without network.
6. References
docs/modules/scanner/architecture.mddocs/modules/scanner/design/surface-fs.mddocs/replay/DETERMINISTIC_REPLAY.mddocs/modules/cli/architecture.mddocs/modules/policy/architecture.md