Skip to content

ci: embed Rust dep graph in wheels + add SLSA build provenance#211

Merged
pudo merged 3 commits into
mainfrom
pudo/cargo-auditable-attestations
May 23, 2026
Merged

ci: embed Rust dep graph in wheels + add SLSA build provenance#211
pudo merged 3 commits into
mainfrom
pudo/cargo-auditable-attestations

Conversation

@pudo
Copy link
Copy Markdown
Member

@pudo pudo commented May 22, 2026

Summary

  • Wires cargo-auditable into the Linux and macOS maturin wheel builds so the compiled .so carries its Cargo dep graph — syft / cargo audit bin can now enumerate the embedded Rust crates instead of seeing rigour as a single opaque component. Windows wheels are intentionally skipped (see below).
  • Adds actions/attest-build-provenance@v4 on every wheel-matrix shard (incl. Windows) and on the sdist for GitHub-side verification (gh attestation verify, repo Attestations tab).
  • Extends workflow permissions: attestations: write, artifact-metadata: write (id-token: write was already present).

The release job is untouched — PEP 740 PyPI attestations should auto-engage via the existing tokenless pypa/gh-action-pypi-publish@release/v1. To verify on the next tagged release.

Closes #210.

Why cargo-auditable needs a wrapper

The naive integration is CARGO=cargo-auditable on the maturin step. That works for cargo build, but maturin invokes cargo rustc for cdylib builds (it needs precise control over linker args) — and cargo-auditable's dispatch interprets cargo-auditable rustc ... as "rustc-wrapper mode" (treating the literal string rustc as the path to the rustc binary), not as a pass-through to cargo rustc. The build then fails with error: Unrecognized option: 'profile' because rustc doesn't accept cargo's --profile flag.

This is cargo-auditable#211, closed June 2025. Upstream's documented fix in REPLACING_CARGO.md is a wrapper script that injects auditable as the cargo subcommand:

#!/bin/sh
exec "$REAL_CARGO" auditable "$@"

Set CARGO=/path/to/wrapper on the maturin step and maturin's cargo rustc ... becomes cargo auditable rustc ... which is the supported invocation.

Implementation notes per platform

  • linux / musllinux (Docker containers): before-script-linux does RUSTC_WRAPPER= cargo install cargo-auditable --locked (the RUSTC_WRAPPER= prefix is needed because the outer step config sets RUSTC_WRAPPER=sccache in the container env, but sccache isn't installed in the container until after before-script-linux runs), then writes the wrapper to /usr/local/bin/cargo-auditable-wrapper. CARGO points there.
  • macos: taiki-e/install-action@v2 grabs a prebuilt cargo-auditable, a follow-up step writes the wrapper to $RUNNER_TEMP, CARGO points there.
  • windows: cargo-auditable dropped — upstream's docs have no .bat/.cmd recipe (PRs welcome notice in REPLACING_CARGO.md), and rigour's Linux wheels are the ones yente actually consumes downstream. Windows wheels still get the GitHub attestation, just not the embedded dep graph. If a Windows consumer ever needs the BOM, we can revisit with a .cmd wrapper.
  • sdist: attestation only (no compiled bytes to embed into).

Test plan

  • CI green on this PR (linux + musllinux + macos + windows + sdist)
  • Download a wheels-manylinux-x86_64 artifact from the PR run, unzip, locate rigour/_core.*.so, and run cargo audit bin <path> — expect the Rust crate graph listed
  • Same check on a wheels-macos-* artifact
  • Confirm Windows wheels DO NOT have the embedded BOM (cargo audit bin returns "no auditable data found") — this is the intentional gap
  • Repo Attestations tab shows new entries for each wheel-matrix shard + sdist (incl. Windows)
  • gh attestation verify <wheel> --owner opensanctions passes locally
  • On next tag: PyPI page shows the PEP 740 attestation badge next to each wheel (if not, pin pypa/gh-action-pypi-publish to v1.11.0+)
  • Downstream smoke-check from a yente venv: syft <venv> -o cyclonedx-json now lists pyo3, aho-corasick, icu_*, etc. as components

🤖 Generated with Claude Code

pudo and others added 3 commits May 22, 2026 12:19
Wires cargo-auditable into each maturin wheel build so the compiled
extension carries its Cargo dep graph (readable by syft / cargo audit
bin) — closes the SBOM gap for downstream scanners. Adds
attest-build-provenance on every wheel and the sdist for GitHub-side
verification via `gh attestation verify`.

Closes #210

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
before-script-linux runs before maturin-action installs sccache into
the container, but the docker env already carries RUSTC_WRAPPER=sccache
from the outer step config. Cargo then fails with "could not execute
process sccache". Unset RUSTC_WRAPPER just for the install command so
the wrapper kicks in only for the actual maturin build that follows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cargo-auditable's dispatch interprets \`cargo-auditable rustc ...\` as
rustc-wrapper mode (treating "rustc" as the path to the rustc binary),
not as a pass-through to \`cargo rustc\`. That made the CARGO env
override break on macos. Upstream's documented fix is a wrapper that
injects \`auditable\` as the cargo subcommand
(see cargo-auditable#211, REPLACING_CARGO.md).

Linux/macOS now create such a wrapper and point CARGO at it. Windows
drops cargo-auditable entirely — upstream has no .bat recipe, and the
Linux wheels are the ones yente consumes anyway. Windows still gets
the attest-build-provenance step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pudo pudo merged commit 7d5fca9 into main May 23, 2026
22 checks passed
@pudo pudo deleted the pudo/cargo-auditable-attestations branch May 23, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Embed Rust dep graph in wheels (cargo auditable) and add SLSA provenance attestations

1 participant