rust-supply-chain-attestation · git:20260618.40ecf42 · 2026-06-18 · sha256 dc497645f6e67b80
rust-supply-chain-attestation git:20260618.40ecf42A
Immutable. This exact content is served forever at /api/v1/blob/dc497645f6e67b80.
---
name: rust-supply-chain-attestation
description: How sparq attests its Rust/cargo supply chain — cargo-deny (advisories/bans/licenses/sources), cargo-vet/cargo-auditable, CycloneDX SBOM + VEX, SLSA build provenance, and OpenSSF Scorecard — and which evidence each tool produces for the SBOM, SLSA, NIST SSDF, EU CRA, and OpenSSF certification frameworks. Use when working any of the sbom/slsa/ssdf/cra/openssf certification worktrees, when adding or changing a supply-chain CI lane, when filling out an SBOM/VEX or a SLSA-level claim, or when asked what evidence a given framework wants from a cargo workspace. Grounded in sparq's real deny.toml + supply-chain.yml + scorecard.yml + dependency-monitoring.yml + release.yml.
---
# Rust supply-chain attestation (sparq)
How sparq proves the integrity of what it ships — a Rust **library + binaries +
container** consumed as a dependency on crates.io / npm (WASM) / PyPI / ghcr.
The dominant risk for a dependency is **supply-chain integrity + build
provenance**, so this is the highest-fit framework family. This skill is the
cargo-specific recipe so the `sbom`, `slsa`, `ssdf`, `cra`, and `openssf`
engineers do not re-derive it.
> NON-CANONICAL timing. No measured numbers belong in this file.
## The tools, what they prove, and which framework consumes the evidence
| Tool | What it asserts | Evidence artifact | Frameworks |
|---|---|---|---|
| **cargo-deny** (advisories) | No known-vulnerable / yanked dependency in the tree | CI log + the daily tracking issue | SBOM, SSDF (RV), CRA (vuln-handling) |
| **cargo-deny** (bans) | No banned/duplicate-version crate sneaks in | CI log | SSDF (PW), SBOM |
| **cargo-deny** (licenses) | Every dependency is permissive / explicitly excepted | CI log + `deny.toml` allowlist | SBOM (NTIA "license"), ISO 27001, CRA |
| **cargo-deny** (sources) | Crates come only from crates.io (no rogue git/registry) | CI log + `deny.toml [sources]` | SLSA, SSDF (PS), SBOM (supplier) |
| **CycloneDX SBOM** (`cargo-cyclonedx`) | The full component inventory of the build | `*.cdx.json` | SBOM (the artifact itself), CRA (Annex I §2), SSDF (PS.3) |
| **VEX** (CycloneDX/CSAF) | Why a flagged advisory is *not exploitable* in sparq | `*.vex.json` alongside the SBOM | SBOM, CRA (vuln-handling) |
| **cargo-auditable** | The exact dependency manifest is embedded *inside* the binary | `cargo audit bin <file>` reads it | SLSA, SBOM, SSDF |
| **cargo-vet** | Each dependency carries a human audit attestation | `supply-chain/audits.toml` | SLSA (higher assurance), SSDF (PS) |
| **attest-build-provenance** | This binary was built by *this* workflow run (Sigstore-signed) | `gh attestation verify` | SLSA (the core L2 claim), CRA, SSDF |
| **OpenSSF Scorecard** | Aggregate posture score (pinned deps, branch protection, SAST…) | SARIF in Security tab + public dashboard | OpenSSF, SSDF |
## How each is wired in sparq today (ground truth — cite these, don't re-propose)
### cargo-deny — `deny.toml` + `.github/workflows/supply-chain.yml`
The policy lives in `deny.toml` (schema targets cargo-deny >= 0.18, "version 2"
advisories/licenses). The `supply-chain.yml` `audit` job runs on the **host
stable toolchain** (not the EmbarkStudios Docker action — its bundled cargo 1.83
can't parse the vendored `spargebra`, which needs `edition2024` / cargo >= 1.85).
- **GATING now:** `cargo deny check bans sources licenses` (every push/PR/merge_group).
- **Licenses:** an allowlist of permissive licenses only (MIT, Apache-2.0, BSD-*,
ISC, Unicode-3.0, CC0-1.0, Zlib, BlueOak-1.0.0) plus **per-crate exceptions**
(CeCILL-B for the sophia/HDT tree, AFL-3.0 for `ntriple`, MPL-2.0 for `resiter`,
Apache-2.0-WITH-LLVM-exception, CDLA-Permissive-2.0 for `webpki-roots`). Each
exception is scoped to one crate so the broad allowlist stays permissive-only.
- **Sources:** `unknown-registry = "deny"`, `unknown-git = "deny"`, only
crates.io allowed. The vendored `spargebra` is a `[patch.crates-io]` PATH source
(a path patch is not a registry/git source, so it doesn't trip the gate);
`allow-git = []` is the hook for any deliberately-allowed future git source.
- **Advisories ignore list:** only `unmaintained` *informational* advisories on
transitive deps with no safe upgrade (today: `rustls-pemfile` via ureq → bead
sq-g2xs). A real **vulnerability** or a **yanked** crate FAILS the gate.
(`paste` via wgpu → bead sq-l8bv was previously ignored under RUSTSEC-2024-0436;
the GPU stack dropped `paste`, so it left the tree and the ignore was removed —
the gate now re-flags any regression that reintroduces it.)
### The advisories-gate gap (GX-1 — know this)
`cargo deny check advisories` is currently **`continue-on-error` (non-gating)**:
cargo-deny 0.19.x can't parse RustSec advisories that use **CVSS v4.0** — it
fails *loading* the freshly-cloned advisory DB ("unsupported CVSS version: 4.0"),
a DB-wide parse error before any per-advisory `ignore` applies, so it can't be
configured around. The **real** advisory gate today is the daily watchdog
(`dependency-monitoring.yml`), which runs advisories-only off-peak and
opens/updates a single idempotent `security:dependency-vuln` tracking issue.
Flip the PR-time advisories check back to gating once cargo-deny ships CVSS-4.0
support — **bead sq-q8de tracks it**. When an auditor asks "is there PR-time vuln
gating?", the honest answer is *no, the daily watchdog is the gate* — say so.
### CycloneDX SBOM — `supply-chain.yml` `sbom` job
`cargo cyclonedx --all --format json` emits one SBOM per workspace member plus an
aggregate (`**/*.cdx.json`), uploaded as a CI **artifact**. Gaps the `sbom`/`cra`
engineers must close (GX-2): there is **no checked-in / per-release SBOM** and
**no VEX** yet. CRA/SBOM want a *published, per-release* SBOM with VEX to justify
non-applicable advisories. Map the SBOM to the **NTIA minimum elements**
(supplier, component name, version, unique identifier/PURL, dependency
relationship, author, timestamp) when scoring.
### SLSA build provenance — `release.yml`
- `actions/attest-build-provenance` (SHA-pinned) signs (Sigstore) an attestation
binding each packaged archive's digest to the workflow run; verify with
`gh attestation verify <file>`. Plus `SHA256SUMS` over all archives.
- The container build uses buildkit `provenance: mode=max` + `sbom: true`,
attaching SLSA provenance + an embedded SBOM to the ghcr.io image (verifiable
via cosign / gh).
- **Honest level:** ≈ **SLSA L2** on GitHub-hosted runners (signed provenance,
hosted build platform). The gaps to higher (GX-7/GX-8): no `cargo-auditable`
(binaries don't embed their dependency manifest), no `cargo-vet`, and no
reproducible-build evidence. State the level *honestly* and name the gap —
never inflate to L3.
### OpenSSF Scorecard — `scorecard.yml`
Runs on push-to-main + weekly; `publish_results: true` uploads to the public
OpenSSF dashboard (required for the Scorecard badge) and to code-scanning (SARIF).
Gaps for the `openssf` worktree: the **Best-Practices (bestpractices.dev / CII)**
questionnaire isn't filled (GX-4), and there's no `.well-known/security.txt`
(RFC 9116) machine-discoverable disclosure pointer (GX-3).
## How to use this when working a certification framework
1. **Don't re-propose existing controls.** The list above is the live posture;
cite the file (`deny.toml:line`, `supply-chain.yml:job`) as evidence.
2. **Gap-fixes land test-first.** Use the `test-driven-development` skill — a new
CI lane or a checked-in SBOM lands with a verifying check before the change.
3. **Frameworks → evidence:** SBOM → the `*.cdx.json` + NTIA mapping + VEX; SLSA →
the provenance attestation + the honest level statement; SSDF → map PO/PS/PW/RV
to these tools; CRA → SBOM + coordinated-disclosure discoverability +
security-update channel; OpenSSF → Scorecard score + Best-Practices badge.
4. **Honesty contract.** Never let a control table launder a gap (the degraded
advisories PR-gate, the missing per-release SBOM/VEX, the SLSA-L2-not-L3
reality) into a "done". Record each gap as a bead, not a silent pass.
## Local commands
```
cargo install --locked cargo-deny cargo-cyclonedx cargo-auditable cargo-audit
cargo deny check # advisories + bans + sources + licenses
cargo deny check bans sources licenses # the currently-gating subset
cargo cyclonedx --all --format json # CycloneDX SBOMs
gh attestation verify <archive> --owner jeswr # SLSA provenance check
```
<!-- [OPUS-4.8] Authored for bead sq-toze.1 (epic sq-toze, cert framework). Grounded in
deny.toml + .github/workflows/{supply-chain,scorecard,dependency-monitoring,release}.yml.
Re-review when Fable returns. -->