Deterministic SBOM composition fixtures
Reference bundle for DOCS-SCANNER-DET-01. Use it to prove fragment-level DSSE, _composition.json, and CycloneDX composition metadata stay deterministic and offline-verifiable.
Contents
_composition.json— composition recipe with Merkle root, fragment hashes, BOM hash, and determinism pins.fragment-layer{1,2}.json— canonical fragments (sorted keys, newline-terminated).fragment-layer{1,2}.dsse.json— DSSE envelopes over the canonical fragments (demo keydemo-ed25519).bom.cdx.json— composed CycloneDX 1.7 BOM (JSON) withstellaops:merkle.rootandstellaops:composition.manifestproperties.bom.cdx.xml— composed CycloneDX 1.7 BOM (XML), produced from the same canonical model asbom.cdx.jsonviaCycloneDxXmlComposer.ConvertJsonToXml. SprintSPRINT_20260512_044(TASK-044-01/04) — verified for byte-stability byCycloneDxXmlGoldenTests.DeterministicCompose_XmlMatchesGoldenand bytools/scripts/scanner/verify-determinism.sh.bom.spdx3.json— composed SPDX 3.0.1 JSON-LD SBOM produced bySpdxComposerfrom the same two-layer fixture data (busybox + express). SprintSPRINT_20260512_043(TASK-043-01/03) — verified bySpdxComposerGoldenTests.DeterministicCompose_Spdx3MatchesGoldenand by theverify-determinism.shSPDX 3 cross-checks (@context,specVersion, document namespace,profileConformance).hashes.txt— sha256 for every file in this directory.generate.py— reproducible generator for the JSON / DSSE artifacts (standard library only). The XML and SPDX 3 goldens are regenerated by re-running the Emit test suite withSTELLAOPS_REGEN_GOLDEN=1.
Verify offline
cd docs/modules/scanner/fixtures/deterministic-compose
sha256sum -c hashes.txt
# Check DSSE payload matches fragment
jq -r '.payload' fragment-layer1.dsse.json | base64 -d > /tmp/payload.json
diff -u fragment-layer1.json /tmp/payload.json
# Recompute Merkle root from fragment hashes
python - <<'PY'
import hashlib, json
from pathlib import Path
frag_hashes = [line.split()[0] for line in Path('hashes.txt').read_text().splitlines() if 'fragment-layer' in line and '.json' in line and '.dsse' not in line]
frag_hashes = [bytes.fromhex(h) for h in frag_hashes]
while len(frag_hashes) > 1:
nxt = []
it = iter(frag_hashes)
for a in it:
b = next(it, a)
nxt.append(hashlib.sha256(a+b).digest())
frag_hashes = nxt
print(f"merkle={frag_hashes[0].hex()}")
PY
Regenerate
python generate.py
sha256sum -c hashes.txt
