Skip to content

feat(builder): add cargo-auditable to the builder image#97

Merged
ben-miru merged 1 commit into
mainfrom
feat/builder-cargo-auditable
Jun 29, 2026
Merged

feat(builder): add cargo-auditable to the builder image#97
ben-miru merged 1 commit into
mainfrom
feat/builder-cargo-auditable

Conversation

@ben-miru

@ben-miru ben-miru commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Why

Release SBOMs (e.g. for miru-agent_*.deb) currently list only the top-level package — zero dependency inventory. The cause: the Rust binaries carry no dependency manifest, so when syft scans the built artifacts it finds nothing to catalog beyond the package record itself. An SBOM that lists only the product and none of its dependencies provides no supply-chain value (a vuln scan against it checks nothing about the linked crates).

What

Install cargo-auditable in the builder image, plus a small wrapper script, so a follow-up goreleaser change can build via cargo auditable. That embeds each binary's dependency tree in a .dep-v0 ELF section, which syft (≥ 1.15; this image ships 1.46) reads to emit SBOMs listing every linked crate.

The wrapper is needed because cargo-auditable only activates when invoked as cargo auditable <cmd> — it inspects argv[1] and refuses to run otherwise — so goreleaser's Rust tool: cannot point at the binary directly. The wrapper restores the cargo auditable invocation while passing through whatever goreleaser appends (zigbuild --target=… --release -p=miru-agent).

Safe to merge on its own

This change is purely additive — nothing references cargo-auditable or the wrapper yet, so it cannot affect existing builds or releases. Merging publishes a new agent-builder image (via builder.yml).

Follow-up (PR 2)

Once this image is published, a second PR will:

  • bump build/Dockerfile's FROM ghcr.io/mirurobotics/agent-builder:<sha> to the new image, and
  • set the Rust builder's tool: cargo-auditable-zigbuild and switch the sboms: stanza to scan the binary/archive instead of the .deb (syft cannot deep-scan a .deb's nested ELF — confirmed empirically — so the SBOM source must be content syft can read).

Validation

Built the new layers on top of the current pinned image and confirmed cargo-auditable installs and the on-PATH wrapper produces a .dep-v0 binary via the exact cargo-auditable-zigbuild zigbuild --target=… --release invocation goreleaser will use. Also verified end-to-end that syft surfaces the embedded crates from such a binary (and from a tar.gz of it), while a .deb scan does not — which is what drives the PR 2 sbom-source change.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Release SBOMs currently list only the top-level package because the Rust
binaries carry no dependency manifest: syft scans the built artifacts and
finds nothing to catalog beyond the package record itself.

Install cargo-auditable and a small wrapper so a follow-up goreleaser
change can build via `cargo auditable`, embedding each binary's dependency
tree in a `.dep-v0` ELF section. syft (>= 1.15; the image ships 1.46) reads
that section and emits SBOMs that list every linked crate.

cargo-auditable only activates when invoked as `cargo auditable <cmd>` (it
inspects argv[1] and refuses otherwise), so goreleaser's Rust `tool:` cannot
point at the binary directly; the wrapper restores that invocation while
passing through `zigbuild --target=... --release` as usual.

This change is additive — nothing references the wrapper yet. Wiring it into
build/.goreleaser.yaml and bumping build/Dockerfile's pinned image follow in
a separate PR once this image is published.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ben-miru ben-miru merged commit 43e2c5b into main Jun 29, 2026
3 checks passed
@ben-miru ben-miru deleted the feat/builder-cargo-auditable branch June 29, 2026 19:52
ben-miru added a commit that referenced this pull request Jun 29, 2026
## Why

Release SBOMs list **only the top-level package** — no dependency
inventory — making them useless for vulnerability scanning. Follow-up to
#97, which added `cargo-auditable` + a wrapper to the builder image.
This PR wires it into the release and fixes what syft scans.

## What

- **`builds.agent.tool: cargo-auditable-zigbuild`** — the wrapper baked
into the builder image (#97). With `command: zigbuild`, goreleaser runs
`cargo-auditable-zigbuild zigbuild --target=… --release -p=miru-agent`,
i.e. `cargo auditable zigbuild …`. Each binary then embeds its full
dependency tree in a `.dep-v0` ELF section.
- **`sboms`: scan `binary` + `archive`, not `package`.** syft reads the
`.dep-v0` section straight out of the binary, and recurses into the
tar.gz to find it — both list every linked crate. A `.deb` scan only
reads DPKG control metadata and **never inspects the nested binary**, so
it could never enumerate dependencies.
- **`build/Dockerfile`**: bump the pinned builder image to `43e2c5b` —
the image published after #97 merged (verified to contain
`cargo-auditable` and the wrapper).

## Why drop the `.deb` SBOM

I tested this empirically in the builder image. syft scanning an
auditable binary inside a `.deb` returns only the package record (2
entries, no crates); the same binary scanned directly, or inside a
tar.gz, returns the full crate list. So the SBOM source has to be the
binary/archive. The published SBOMs now cover the binaries (the exact
bits shipped inside both the archives and the `.deb`s) and the archives.

> [!NOTE]
> If a downstream consumer specifically needs a `*.deb`-named SBOM file,
say so and I'll keep a `package` entry but repoint its syft invocation
at the binary instead of dropping it.

## Validation

- `goreleaser check` passes against the new pinned image (`43e2c5b`).
- Confirmed the published `agent-builder:43e2c5b` image contains
`cargo-auditable` and the wrapper.
- End-to-end in that image: the wrapper, invoked exactly as goreleaser
assembles it (`cargo-auditable-zigbuild zigbuild --target=… --release`),
produces a binary with a `.dep-v0` section, and syft surfaces the
embedded crate (`itoa`) from both the raw binary and a tar.gz of it —
but not from a `.deb`.

The first real release tag after this merges will be the live
confirmation; the SBOM that previously showed one package should then
list the agent's crates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/mirurobotics/codesmith/agent/pr/98"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1785354982&installation_id=142588636&pr_number=98&repository=mirurobotics%2Fagent&return_to=https%3A%2F%2Fgithub.com%2Fmirurobotics%2Fagent%2Fpull%2F98&signature=6601d178f8c208525372bf77f2f00363ff7065d0575652cd2d2f9bcf39229b7c"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>/codesmith</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant