# Advisory: SBOM Evidence Verification and Auditability Pipeline **Date:** 2026-02-19 **Status:** ARCHIVED (translated to sprint tasks) **Reviewed:** 2026-02-19 ## Review Outcome Advisory reviewed against current codebase. ~85% of proposed capabilities already exist in Stella Ops across Scanner, Signer, Attestor, Excititor, VexLens, Signals, EvidenceLocker, and ReachGraph modules. ### Capabilities Confirmed (no action needed) - CycloneDX v1.7 SBOM generation (Scanner.Emit) - DSSE/in-toto attestation with 10+ predicate types (Attestor.Envelope) - Cosign-compatible signing via Signer (keyless Fulcio + keyful KMS/HSM) - Rekor v2 anchoring with RFC 6962 tile verification and offline mode (Attestor) - Deterministic VEX ingestion with AOC enforcement (Excititor + VexLens) - eBPF micro-witness collection with cross-distro replay (Signals + Scanner) - Evidence bundle storage with Merkle roots and portable audit packs (EvidenceLocker) - Offline verification for air-gapped deployments ### Gaps Identified → Sprint Tasks Created 1. **Unified canonical_id contract** → SPRINT_20260219_009 (CID-01, CID-02) 2. **Artifact Canonical Record** → SPRINT_20260219_009 (CID-03, CID-04) 3. **Predicate Schema Registry** → SPRINT_20260219_010 (PSR-01, PSR-02) 4. **CI Assertion Pack** → SPRINT_20260219_011 (CIAP-01 through CIAP-04) 5. **Micro-witness → VEX Auto-Suppress workflow** → SPRINT_20260219_012 (MWS-01 through MWS-03) ### Proposals Explicitly Rejected - Replacing Signer with raw cosign CLI (Signer adds PoE, quotas, DPoP/mTLS) - Simplifying VEX handling (Excititor+VexLens+AOC is more sophisticated) - Adopting advisory's simplified schema URIs (keep existing Stella URIs, add to registry) - `replay_token` pointing to external S3 (keep CAS with BLAKE3 digests) --- ## Original Advisory Content (Inline advisory provided by user — full text preserved below for audit trail.) --- # Why this matters (quick primer) * **SBOM** (software bill of materials) says what's inside an artifact. * **DSSE / in-toto** wraps evidence in a tamper-evident envelope. * **cosign** signs/verifies those envelopes. * **Rekor (transparency log)** proves *when/what* was published. * **VEX** states whether known CVEs affect your artifact. * **Micro-witnesses** are runtime breadcrumbs you can join back to SBOM/VEX for triage. --- # NOW (MVP you can ship immediately) **Goal:** Minimal, reproducible spine with canonical SBOMs, signed attestations, Rekor v2 anchoring, and deterministic VEX ingestion. ### Canonical SBOM & ID 1. Emit CycloneDX v1.7 JSON. 2. Canonicalize via JSON-JCS -> `canonical_id := sha256(JCS(sbom.json))`. ### DSSE attestation (SBOM predicate) * Wrap CycloneDX content (or pointer) in an **in-toto Statement**. * `subject[0].digest.sha256 == canonical_id`. * Sign with cosign (**DSSE mode**). * Capture Rekor v2 tile pointer / entry id and embed it in predicate metadata. ### Rekor v2 anchoring * cosign publish creates the log entry. * Store the **tile URL** and **entry id** in your artifact record. ### Deterministic VEX ingestion (OpenVEX & CycloneDX VEX) * Ingest OpenVEX or CycloneDX VEX, map to a **canonical CycloneDX VEX** form. * Apply strict merge rules (source priority, timestamp, exact `canonical_id` target). ### CI assertions (must-pass) * **Unit:** `cyclonedx-cli validate ./bom.json && jcs_canonicalize ./bom.json | sha256sum` -> equals expected `canonical_id`. * **Integration:** `cosign attest --predicate predicate.json --key cosign.key ` `cosign verify-attestation --key --type in-toto ` Rekor proof: `rekor-cli tile get --entry ` -> inclusion proof valid. * **VEX mapping:** jsonschema validate; assert `vulnerabilities[].analysis.state` and target match `canonical_id`. --- # LATER (scale/hardening) * Rekor v2 **tile batching** & multi-tile reconciliation. * **Signed micro-witness aggregation** service. * **Deterministic replay** harness (nightly) for large volumes. * Predicate **schema registry** (stable `predicateType` URIs, semver). --- # Flow A: Build-time SBOM + Attestation Anchor (end-to-end) 1. **Producer:** CycloneDX v1.7 -> validate -> JCS canonicalize -> `canonical_id = sha256(canonical_bytes)`. 2. **Predicate:** in-toto Statement with CycloneDX JCS content. 3. **Sign & anchor:** cosign attest -> capture Rekor tile URL and entry_id. 4. **Verify:** Fetch referrers, extract DSSE, cosign verify-attestation, recompute canonical_id, validate Rekor inclusion proof. # Flow B: VEX -> Apply -> Runtime Micro-witness Join 1. **VEX provider:** Publish OpenVEX or CycloneDX VEX; DSSE-sign; optionally anchor in Rekor. 2. **Ingest & map:** OpenVEX -> canonical CycloneDX VEX; store DSSE + rekor_tile + provenance. 3. **Runtime micro-witness:** Emit DSSE micro-witness predicate referencing canonical_id. 4. **Correlate:** Join micro-witness DSSE with VEX; if not_affected -> auto-suppress; else surface audit pack. --- # Failure modes * Payload > Rekor limit: Put artifact in immutable store; Rekor entry contains digest + pointer. * Missing symbol bundle: Emit unknown_state micro-witness entry. * Digest mismatch anywhere: fail the build.