Skip to content

release: v0.9.9 — the distribution release#41

Merged
Metbcy merged 7 commits intomainfrom
release/v0.9.9
May 1, 2026
Merged

release: v0.9.9 — the distribution release#41
Metbcy merged 7 commits intomainfrom
release/v0.9.9

Conversation

@Metbcy
Copy link
Copy Markdown
Owner

@Metbcy Metbcy commented May 1, 2026

Phase 1 of the bomdrift adoption plan. Every plausible install path now works in one command; the source-code surface of bomdrift is unchanged.

Why this PR exists

bomdrift v0.9.8 shipped a polished tool whose only documented install path was cargo install --locked --git https://github.com/Metbcy/bomdrift --tag v0.9.8 bomdrift. The handoff plan (bomdrift-adoption-plan.md) called this out as the single biggest leverage point in the 90-day adoption push: a Rust CLI that isn't on crates.io is invisible to its primary audience, and downstream packagers (Homebrew, nix, AUR, winget, scoop) all want a stable upstream release artifact + tag flow before they'll consume it.

v0.9.9 is the distribution release. After it ships, all of the following work:

Path Command
Cargo cargo install bomdrift
Docker docker run --rm ghcr.io/metbcy/bomdrift:v0.9.9 --version
Action uses: Metbcy/bomdrift@v1 (auto-points at v0.9.9 via the new retag-major job)
Tarball curl https://github.com/Metbcy/bomdrift/releases/download/v0.9.9/bomdrift-v0.9.9-...tar.gz

Every release artifact carries:

  • cosign-keyless signature (existing) — proves the maintainer's GitHub OIDC identity signed it.
  • SLSA build provenance (new) — proves the public release.yml workflow on tag v0.9.9 produced it. Verifiable with gh attestation verify --owner Metbcy <archive> or slsa-verifier.

How to review

Each commit is one logical PR per the plan in bomdrift-adoption-plan.mdv0.9.9 plan:

  1. 9e9f55b — Cargo metadata + cargo publish --dry-run CI guard.
  2. 838c2e0 — Rustdoc cleanup so docs.rs auto-build is clean.
  3. 918bf6b — Dockerfile + ghcr build job (gated if: false).
  4. 83ef28d — SLSA provenance steps + release-signing.md docs (gated if: false).
  5. cedb9f8 — README badges + new install paths + STATUS.md drift fix.
  6. d41655b — Flip the distribution gates + cargo-publish job + v1 retag.
  7. 6115333 — Bump to 0.9.9 + write CHANGELOG.

The staging design means main was never in a broken-release-pipeline state during the build-up — commits 3 and 4 land the release.yml additions inert (if: false); commit 6 is the single "this PR will fundamentally change what git tag v0.9.9 does" diff to focus on.

Local verification done

  • cargo publish --dry-run --locked → 54 files / 220 KiB compressed (well under the 10 MB crates.io limit).
  • cargo test → 444 passed.
  • cargo build --release → ok.
  • RUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-features → clean.
  • python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))" → valid; job graph is preflight → build → publish → {docker, cargo-publish, retag-major}.

Verification after tagging

Within 24h of git tag v0.9.9 && git push origin v0.9.9:

  • cargo install bomdrift && bomdrift --version works on Linux + macOS.
  • docker run --rm ghcr.io/metbcy/bomdrift:v0.9.9 --version works on linux/amd64 + linux/arm64.
  • cosign verify-blob succeeds (regression check; existing behavior).
  • gh attestation verify --owner Metbcy bomdrift-v0.9.9-x86_64-unknown-linux-gnu.tar.gz succeeds (new).
  • docs.rs/bomdrift build is green.
  • Metbcy/bomdrift@v1 resolves to v0.9.9's commit (the retag-major job moved it).

Out of scope (deferred)

  • Homebrew tap, nix flake, AUR PKGBUILD, winget + Scoop manifests — separate plans, no version coupling.
  • README diet (the wall-of-text comparison table moves to docs/src/compare.md).
  • Asciinema demo recorded against examples/axios-incident/.
  • File splits deferred from v0.9.8 (vex.rs, render/markdown.rs, render/sarif.rs, baseline.rs, enrich/typosquat.rs, enrich/license.rs) — held for the next code-hygiene release.
  • Coverage --fail-under-lines ratchet — planned for "after 2-3 releases of visibility"; v0.9.9 is the second.

🤖 Generated with GitHub Copilot

Metbcy and others added 7 commits April 30, 2026 17:04
Prep for the v0.9.9 distribution release. crates.io publication needs a
few things in place first:

  - Cargo.toml gains `documentation = "https://docs.rs/bomdrift"` so
    crates.io links docs correctly, and a `[package.metadata.docs.rs]`
    block so the auto-built docs.rs page renders with all features.
  - Cargo.toml gains an `exclude` list trimming the published crate
    to source + runtime data + project meta. tests/ (2.7 MB of
    fixtures), docs/ (mdbook source published separately), examples/,
    benches/, fuzz/, comment-suppress/, scripts/, .github/, and the
    GitHub Action manifests are all excluded. data/ stays IN — the
    typosquat reference lists are pulled at compile time via
  - New `publish-dry-run` job in ci.yml runs `cargo publish
    --dry-run --locked` on every PR, catching crate-metadata
    regressions (oversized package, missing fields, exclude list
    dropping a build-time include) BEFORE they reach a release tag.
    Path-filtered to PR runs only.

Verified locally: published crate is 54 files / 220 KiB compressed,
data/*.txt are in, all 443 tests still pass.

Refs the v0.9.9 plan (Track 1).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Once v0.9.9 is published to crates.io, docs.rs will auto-build the docs
page. Run `RUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-features`
locally and fix every broken intra-doc link surfaced.

Two failure shapes:

  - Module-level docstrings reference private items
    (`MAX_QUERIES_PER_BATCH`, `SUFFIX_BOOST_SCORE`, `run_with`,
    `eval_leaf`, `LeafOutcome`). rustdoc rejects these because the link
    target isn't visible to the public docs build. Demoted from
    bracketed intra-doc links to plain backtick-quoted code spans —
    same reading experience, no broken-link warning.
  - Reference paths broken by the v0.9.8 lib.rs split. `crate::run_diff`
    no longer exists at the crate root; the orchestration module is
    `crate::run`. Updated to [`mod@crate::run`] and qualified the
    `VulnRef`/`Severity`/`Cache` references with full paths.
  - One redundant explicit link target (osv.rs `Severity::None`)
    flagged by `-D rustdoc::redundant-explicit-links` — the label
    already resolves to the same destination, so the explicit target
    is noise.
  - One reference to `Cache::with_root` rephrased — that constructor
    is `#[cfg(test)]` so it isn't visible to the public docs build.

No public API surface change. All 444 tests still pass.

Refs the v0.9.9 plan (Track 4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the second install path: ghcr.io/metbcy/bomdrift. Multi-arch
(linux/amd64, linux/arm64) via docker buildx. Tag matrix follows the
standard convention — :v0.9.9, :v0.9, :v0, :latest.

Design notes:

  - Single-stage Dockerfile. Consumes the per-arch binaries already
    cosign-signed by the build matrix; no `cargo build` runs in the
    image. The bytes baked into ghcr.io are exactly the bytes attached
    to the corresponding GitHub Release.
  - Distroless cc-debian12 base. ~22 MB base + ~6 MB stripped binary
    = ~28 MB final image. Runs as the distroless `nonroot` user.
  - .dockerignore is allowlist-style: nothing from the repo is in the
    docker build context except dist/ (the staged binaries) and the
    Dockerfile itself. Keeps context uploads small and prevents
    accidental `target/` poisoning.
  - The buildx step asks docker/build-push-action@v6 for inline
    `provenance: true` and `sbom: true`; that gets us GitHub-attested
    build provenance + an SBOM attached to the registry manifest at
    no extra cost. Image-level cosign sign step runs after.

GATED `if: false`. The job is parsed for syntax but never runs. The
v0.9.9 "flip the gates" PR removes the gate after the crates.io
prerequisites (name reservation, CARGO_REGISTRY_TOKEN secret) are in
place.

Refs the v0.9.9 plan (Track 2).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add actions/attest-build-provenance@v2 steps to both artifact-producing
jobs:

  - the build matrix (per-target archives — gated step inside each
    matrix run, so each archive gets its own attestation)
  - the docker job (multi-arch image — push-to-registry: true so the
    attestation lives alongside the manifest in ghcr.io)

Top-level workflow permissions gain `attestations: write` (required by
attest-build-provenance) and `packages: write` (anticipates the
ungated docker job). Both are restricted by GitHub to the workflow
run's OIDC identity, so they don't widen the trust surface.

docs/src/release-signing.md gains a SLSA section explaining:

  - why cosign + SLSA are complementary (signer-identity vs
    build-identity), with the threat model where each one catches
    what the other misses.
  - how to verify with `gh attestation verify` (the recommended
    path) and `slsa-verifier` (the air-gapped path).
  - how to verify the ghcr.io image's inline attestation.

GATED `if: false` until the v0.9.9 "flip the gates" PR. The
attestations write nothing until then.

Refs the v0.9.9 plan (Track 3).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
README gains four new badges at the top:

  - crates.io (was missing entirely)
  - docs.rs (was missing entirely)
  - GitHub Marketplace (was missing — listing has been live since v0.9.8)
  - The existing CI / Release / Docs / License badges stay.

README's Detailed install section gains two new install paths under
"As a binary (local / CI)":

  - `cargo install --locked bomdrift` (v0.9.9+) — the canonical
    Rust-CLI install path.
  - `docker run --rm ghcr.io/metbcy/bomdrift:v0.9.9` (v0.9.9+) — for
    teams that prefer pulling images. Multi-arch, distroless, runs as
    nonroot, ships with an inline SLSA attestation.

The existing release-archive download path is kept as a third option
(some teams really do want to pin a tarball checksum). The from-source
path is bumped from v0.9.8 to v0.9.9.

STATUS.md drops the stale "Marketplace publication is a repository
setting; the action metadata is ready, but a maintainer must enable
the listing" line. The listing has been live at
github.com/marketplace/actions/bomdrift since v0.9.8 — leaving the
line in place was actively misleading.

The Marketplace listing description rewrite (lead with the axios
narrative) is a Marketplace dashboard edit, not a repo file edit, so
it's not in this commit. Tracked separately in the v0.9.9 plan.

Refs the v0.9.9 plan (Track 5).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The v0.9.9 release is the first that actually pushes to crates.io,
ghcr.io, and the SLSA attestation store. This PR flips the
`if: false` gates added in the prior commits and adds the two
remaining jobs the plan called for:

  - `docker` job (and its embedded SLSA attestation step) ungated.
  - `Attest build provenance` step in the build matrix ungated.
  - `Attest build provenance (image)` step in docker ungated.
  - New `cargo-publish` job: runs `cargo publish --locked` after
    the GitHub Release is up. Independent of docker / retag-major so
    a transient crates.io failure doesn't fail the rest of the
    release.
  - New `retag-major` job: force-pushes the major-version tag (v1
    today; v${major} once we hit v1.0.0+) to point at the new
    release. Marketplace + sloppy adopters consume the floating tag
    and expect it to track latest. Runs against the same SHA the
    GitHub Release used.

Job graph:

   preflight
     └→ build (matrix)
          └→ publish (GitHub Release)
               ├→ docker (ghcr.io + SLSA)
               ├→ cargo-publish (crates.io)
               └→ retag-major (v1 → this tag)

The three terminal jobs run in parallel; a failure in any one
doesn't unwind the others. This is the design the plan called for —
crates.io being temporarily unreachable shouldn't block the GitHub
Release that's already live.

PREREQUISITE before tagging v0.9.9: reserve `bomdrift` on crates.io
and add `CARGO_REGISTRY_TOKEN` to repo secrets. Without the secret,
the cargo-publish job will fail; the rest of the release still
succeeds.

Refs the v0.9.9 plan (Track 1 + 2 + 3 finalized).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cargo.toml + Cargo.lock: 0.9.8 → 0.9.9.

CHANGELOG.md: rename Unreleased → [0.9.9] - 2026-04-30 with the full
release-notes prose for the distribution release. Brings together:

  - Added: crates.io publish + Cargo.toml metadata + exclude;
    ghcr.io multi-arch image + Dockerfile; SLSA build provenance
    on archives + image; publish-dry-run PR guard.
  - Changed: README install section + badges; Marketplace listing
    description; Node.js 24 runner opt-in; v1 major-tag retag.
  - Fixed: coverage-comment fake-link autolink (carried from
    Unreleased).
  - Documentation: SLSA section in release-signing.md; rustdoc
    cleanup; STATUS.md + README drift fixes.
  - Tests: 444 → 444. Distribution-release plumbing only; no
    source-code feature change.
  - Scope notes: what's deferred and why (Homebrew, nix, AUR,
    winget/Scoop, README diet, asciinema, file splits, mutation
    testing, coverage ratchet).

The release.yml preflight job validates this matches the tag at push
time. Locally:

  - cargo publish --dry-run --locked → 220 KiB compressed, ok
  - cargo test → 444 passed
  - cargo build --release → ok
  - cargo doc --no-deps --all-features → clean with -D warnings

PREREQUISITE before pushing the v0.9.9 tag:

  1. Reserve `bomdrift` on crates.io and verify owner.
  2. Generate a publish-scoped registry token.
  3. Add it as repo secret CARGO_REGISTRY_TOKEN.

Without that secret, `cargo-publish` fails; the rest of the
release pipeline (GitHub Release, ghcr.io image, SLSA, v1 retag)
still runs to completion.

Refs the v0.9.9 plan (final commit; tag and verify is the next
operator step).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

SBOM diff

Change Count
Added 5
Removed 0
Version changed 1
License changed 0

Added (5)

Show details
Ecosystem Name Version
github actions/attest-build-provenance v2
github docker/build-push-action v6
github docker/login-action v3
github docker/setup-buildx-action v3
github docker/setup-qemu-action v3

Version changed (1)

Show details
Ecosystem Name Before After
cargo bomdrift 0.9.8 0.9.9

False positive? Report it · Suppress a finding? Comment /bomdrift suppress <ID> (requires the comment-suppress sub-action) · Docs

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Coverage report

Line coverage: 86.6% (9346 / 10797 lines)

Full lcov report available as workflow artifact coverage-lcov: download from this run.

v0.9.8 introduces this report; --fail-under-lines will be added once coverage is visible across 2–3 releases.

@Metbcy Metbcy merged commit 4575833 into main May 1, 2026
11 checks passed
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