# Deterministic SBOM Composition (Spec Draft) > **Status:** Draft v0.1 (Sprint 136 / 203 / 209 linkage) > **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.fragments` payloads 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.json` records `{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 then `component.identity.purl` (fallback to `identity.key`). - CycloneDX metadata gains: - `properties["stellaops:stella.contentHash"]` for each fragment and composition root. - `properties["stellaops:composition.manifest"]` referencing `_composition.json` CAS URI. - `properties["stellaops:merkle.root"]` for the composed BOM. - `ScannerTimestamps.Normalize` continues 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 - `SurfaceManifestArtifact` gains optional `attestations[]` with `{kind, mediaType, digest, uri}` for DSSE envelopes. - `_composition.json` is published as an additional artifact kind `composition.recipe`. - Surface reader/writer validate Merkle roots before caching manifest entries. ### 2.4 Tooling impacts - **CLI (`stella sbomer ...`)**: adds `layer` and `compose` verbs, 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/cli` plus policy references detailing how to interpret determinism metadata. - **Crypto**: PQ-friendly DSSE toggle delivered via `SCANNER-CRYPTO-90-002/003` so sovereign bundles can select Dilithium/Falcon. ## 3. Verification Flow (offline kit) 1. Verify DSSE on each fragment (using `verifiers.json`). 2. Recompute `sha256(c14n(fragment))` and compare with `_composition.json`. 3. Re-run composition locally (using canonical ordering) and compare `sha256(c14n(composed))` against `manifest.properties["stellaops:merkle.root"]`. 4. Optionally validate provided Merkle proofs (leaf → root) and attest that the UI/Policy gate marked the scan as deterministic. ## 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. References - `docs/modules/scanner/architecture.md` - `docs/modules/scanner/design/surface-fs.md` - `docs/replay/DETERMINISTIC_REPLAY.md` - `docs/modules/cli/architecture.md` - `docs/modules/policy/architecture.md`