Skip to content

minimal sbom + blueprint: session/task SBOM (CycloneDX 1.5), extended to a CycloneDX 2.0 Blueprint #700

Description

@bryan-minimal

Rewritten 2026-07-24 for trackability (previous body in edit history). A detailed implementation plan against main tip 3a05252c exists — "SBOM/Blueprint implementation plan" on Notion; this issue tracks goal, slices, and decisions.

Goal

A min sbom command on the new CLI (crates/minimal, NOT mip) emitting the supply-chain + posture story of a session / task+loadout:

  1. SBOM: components + dependency graph — CycloneDX 1.5 (per crates: extract SBOM generation into a shared minimal/crates/sbom (out of minimal-supply-chain) #433's close-out: nothing we generate needs 1.6-only attributes; the forward path is 2.0). SPDX deferred behind a thin Serializer seam (D10).
  2. Blueprint: the CycloneDX 2.0 draft threat-modeling schema — the session's posture: assets, behaviors, flows, zones. Declared-spec first; live-session later.

Two architectural consumers of the same model: this CLI, and build infra emitting per-package SBOMs at publish time (the unified architecture makes Built Package SBOM + its signature first-class) — so crates/sbom must stay lean (no clap/daemon/rcache deps in the default build).

Where this stands

  • Greenfield at tip: no crates/sbom/crates/blueprint, no CDX/SPDX/purl deps in the lock. crates: extract SBOM generation into a shared minimal/crates/sbom (out of minimal-supply-chain) #433 is closed (superseded here); its resolved decisions carry over.
  • Source material: ~1,500 portable LOC in minimal-supply-chain (CDX types, build-scan, store, purl subset) + rustmachineguard's working schema-gated CDX 2.0 Blueprint emitter (vendored-schema conformance-test pattern to port; its string-parsing identity resolution is the anti-pattern to avoid — we have structured provenance end-to-end).
  • Axis reality at tip (full ✓/△/✗ table in the plan): components/assets/behaviors/most flows ✓ (the carries_user_data per-var taint bit is a ready-made data-flow marker); network zones △ (declared, unenforced — emit with a caveat property); file_exports, github_imports+scopes, loadout_mode, otel endpoints, vpn_network_names ✗ — schema-TODOs, never fabricated.
  • Emitted vocabulary follows the Sandbox Spec (network.type = none|host_ip|no_ip, file_imports/exports, machine.*), so documents survive the Composition→Spec naming convergence.

PR slices (each lands green; 1–3 platform-neutral, 4+ Linux-lane testing)

  • 1+2 (PR-1, one PR): crates/sbom (portable subset from minimal-supply-chain, lean deps) + neutral IR + Serializer trait with CycloneDX 1.5 (full) and SPDX 2.3 (minimal-valid) + SerialPolicy::ContentDerived + CatalogPin = {repo, commit, closure_object} (the signed <commit>.closure.shisha, per feat(rcache): closure-union index reads behind index_source="closure" #995 — replaces uuid-v4 + wall clock); golden fixtures both formats; CDX schema conformance test. See the 2026-07-30 re-validation comment.
  • 3. Graph typed accessors + adapter: components from the closure walk, real dependency edges, artifact_sha256 via the signed-index reader, digest_gap for local/non-redistributable
  • 4. CLI min sbom declared-spec mode (--task/--loadout, --format): first end-to-end value; zero daemon changes
  • 5. crates/blueprint + --format cdx-blueprint: rmg-derived model, vendored-schema gate (re-pin to current 2.0-dev head; re-vendor at finalization, milestone 2026-08-31)
  • 6. Live-session mode (deferrable; gated on D2): GetSessionComposition RPC, observed acknowledgment, minvmd resources

Open decisions (recommendations in the plan doc)

  • D2 live-session in v1? → declared-only v1; slice 6 follows once the daemon wire layer settles
  • D4 "blueprint" naming collision (minimal.toml is already "the project blueprint") → crate name fine; user-facing --format cdx-blueprint; decide before slice 4
  • D5 persist policy-gate verdicts at FinalizeSession? → yes; cheap now, unreconstructible later
  • D6 legacy mfile::Task never produces a Composition → v1 reads graph side for packages, sessions side for posture; converging Task onto sessions primitives is the real fix (separate work)
  • D7 launcher-injected packages (baseline + bash/socat) → emit with minimal:added-by=launcher property, don't omit (an SBOM missing packages present in every environment is dishonest)
  • D9 authority when a sealed pkg-SBOM and a regenerated graph SBOM disagree → graph is authoritative for metadata, sealed for build-time facts; both carry CatalogPin so divergence is diffable
  • D11 Sandbox-Spec vocabulary conflicts → settle before slice 2's golden fixtures land (renames churn every checked-in BOM)

D1 (CDX 1.5) applied per #433's close-out. D10 revised 2026-07-30: minimal SPDX 2.3 ships in PR-1 alongside CDX (the serializer seam shouldn't land with one implementation); full SPDX profile depth stays deferred.

Refs

Prior art: rustmachineguard (blueprint emitter + ADBOM taxonomy — evaluate for agent-running sessions, follow-up). Signing/verifiability: the per-commit signed index (#912 reader; build-servers#86/#185) — session-SBOM component digests chain to it. Usage axis (STATIC/DYNAMIC link tiers): future, model field reserved.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions