Skip to content

release: v0.9.7 — milestone follow-ups (SPDX WITH chains, last calibration knob, action parity)#24

Merged
Metbcy merged 9 commits intomainfrom
release/v0.9.7
Apr 30, 2026
Merged

release: v0.9.7 — milestone follow-ups (SPDX WITH chains, last calibration knob, action parity)#24
Metbcy merged 9 commits intomainfrom
release/v0.9.7

Conversation

@Metbcy
Copy link
Copy Markdown
Owner

@Metbcy Metbcy commented Apr 30, 2026

v0.9.7 — milestone follow-ups

Closes the v0.9.6 release notes' "Suggested next milestone candidates"
backlog. Five concrete polish items shipped in one release; the sixth
(WASM-sandboxed plugin model) explicitly deferred as a v1.0+ candidate
because the external-process model from v0.9.6 covers the use case
without the multi-week toolchain overhaul WASM would require.

Highlights

  • SPDX WITH-chain exception inheritance. v0.9.5's per-exception
    allow/deny now propagates correctly through compound expressions:
    • (Apache-2.0 WITH LLVM-exception) AND (BSD-3-Clause) with
      deny_exceptions=[LLVM-exception] is correctly denied (AND
      inherits the denial).
    • (Apache-2.0 WITH LLVM-exception) OR (Apache-2.0 WITH Classpath-exception-2.0) with allow_exceptions=[LLVM-exception]
      is correctly permitted (OR doesn't poison if one branch is
      permitted). Single-WITH expressions keep v0.9.5 wording for back-
      compat. Compound violations append " (in <raw expression>)".
  • --multi-major-delta <u32>. Last hardcoded calibration
    threshold lifted (version_jump::MIN_MAJOR_DELTA = 2). Default 2,
    validated >= 1, matching [diff] multi_major_delta config key.
    --debug-calibration rows now emit the active delta.
  • First-class Windows plugin timeout. Replaced manual
    Child::try_wait() polling with the wait-timeout crate (~50kb,
    libc-only transitive). Behavior unchanged on Unix; first-class
    on Windows instead of best-effort.
  • action.yml input parity. 25 new inputs cover the v0.7-v0.9.7
    CLI flag surface that was previously CLI-only: VEX (consume + emit +
    author + justification), license policy (allow/deny + exceptions +
    ambiguous), enrichment toggles (no-epss / no-kev / no-registry),
    calibration knobs (similarity / young-maintainer-days / cache-TTL /
    multi-major-delta / recently-published-days / fail-on-epss),
    attestation (before / after / cosign-identity / cosign-issuer /
    require), and plugins. Empty inputs contribute no CLI args, so
    existing workflows keep working without any changes.
  • Air-gapped / self-hosted Sigstore documentation. New
    docs/src/attestation.md subsection covers env-var passthrough
    (SIGSTORE_REKOR_URL, COSIGN_FULCIO_URL, etc.). bomdrift inherits
    the calling environment, so air-gapped Sigstore works without
    bomdrift-side changes. Includes a worked GH Actions example, key-
    based attestation fallback notes, and a 6-item troubleshooting
    checklist.

What stayed deferred

WASM-sandboxed plugin model — multi-week toolchain overhaul
(wasmtime ~30MB / 80 transitive deps, plus a Rust plugin SDK, plus
dual-runtime support to not break v0.9.6 plugins). Conflicts with
bomdrift's single-binary tenet. The external-process model from v0.9.6
covers the use case adopters want; WASM stays a v1.0+ candidate if
demand materializes.

Process

Two parallel background sub-agents on isolated git worktrees, mirroring
the v0.9.5/v0.9.6 pattern:

  • feat/v0.9.7-rust (background, 14 min): SPDX exception inheritance →
    --multi-major-delta knob → wait-timeout-based plugin timeout, all
    on isolated worktree.
  • feat/v0.9.7-platform (background, 5.5 min, parallel with rust):
    action.yml input parity + entrypoint.sh mapping → air-gapped Sigstore
    docs → cli-reference / license-policy / version-jump / architecture
    docs touch-ups.

Both branches merged cleanly into release/v0.9.7 with zero conflicts
(disjoint file ownership).

Test status

  • 420 → 432 (+12). All green: cargo test --release ubuntu /
    macos / windows.
  • cargo clippy --all-targets --all-features --release -- -D warnings
    clean (Rust 1.88 toolchain).
  • cargo fmt --all -- --check clean.
  • cargo deny check clean.

Deps

  • Added wait-timeout = "0.2" (Phase C, plugin Windows timeout).
    Single transitive (libc, already in tree).

Post-merge checklist (maintainer)

  1. Tag v0.9.7 on the merge commit.
  2. Re-point the floating v1 tag to v0.9.7.
  3. Cut the GitHub Release with the cosign-signed archives.
  4. Delete release/v0.9.7, feat/v0.9.7-rust, feat/v0.9.7-platform
    branches.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Metbcy and others added 9 commits April 29, 2026 20:40
Closes the action.yml/CLI parity gap. Every CLI flag that previously had
to be driven through .bomdrift.toml or a direct cargo install is now a
first-class action input:

- VEX: vex (multi-line), emit-vex, vex-author, vex-default-justification
- License policy: allow-licenses, deny-licenses, allow-exception,
  deny-exception, allow-ambiguous-licenses
- Enrichment toggles: no-epss, no-kev, no-registry
- Failure threshold: fail-on-epss
- Calibration: recently-published-days, typosquat-similarity-threshold,
  young-maintainer-days, cache-ttl-hours, multi-major-delta (new in 0.9.7)
- Attestation: before-attestation, after-attestation, cosign-identity,
  cosign-issuer, require-attestation
- Plugins: plugin (multi-line)

entrypoint.sh maps each input to the corresponding CLI flag through an
extra_args array; empty inputs contribute nothing so existing workflows
remain byte-identical. Multi-line inputs (vex, plugin) iterate one flag
per non-empty line; comma-list inputs pass through as a single value.

docs/src/github-action.md replaces the old single Inputs table with
purpose-grouped reference tables (Core / Output / Suppression / License
policy / Enrichment / Calibration / Failure thresholds / Attestation /
Plugins / Release verification) and a 'What's new in v0.9.7' subsection
listing the freshly exposed inputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expand the brief 'Self-managed Sigstore instances' note into a full
'Air-gapped / self-hosted Sigstore' subsection covering:

- when this matters (regulated environments where the public-good
  Sigstore stack isn't reachable);
- the full set of cosign-respected env vars bomdrift inherits unchanged
  (SIGSTORE_REKOR_URL, COSIGN_FULCIO_URL, SIGSTORE_OIDC_ISSUER,
  SIGSTORE_ROOT_FILE, TUF_ROOT, COSIGN_REPOSITORY);
- a worked GitHub Actions example with a private Sigstore stack;
- the key-based fallback for true air-gaps where the OIDC keyless flow
  isn't reachable, including COSIGN_PUBLIC_KEY / cosign.pub auto-detection;
- a six-item troubleshooting checklist tied to the most common failure
  modes (TUF metadata, Rekor reachability, untrusted intermediate CA,
  key vs identity matching, env propagation, runner cosign install).

bomdrift's attestation module shells out to cosign without scrubbing the
calling environment, so all of this works through env-var passthrough
without any bomdrift-side flag. The 'What's NOT in v0.9.6' bullet that
called air-gapped 'best-effort' is updated to reference the new section.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e for v0.9.7

- cli-reference: add --multi-major-delta entry under Calibration with
  default 2 / minimum 1 / config key [diff] multi_major_delta. Note
  that --debug-calibration version-jump rows now emit the active
  threshold, not a const default.
- license-policy: replace the v0.9 'WITH (exception) granularity is a
  future ask' note with a worked-example subsection covering the
  v0.9.7 compound-expression inheritance refinement (AND inherits / OR
  doesn't poison / bare-WITH falls through / atomic deny still wins),
  including a resolution table for the most common shapes.
- enrichers/version-jump: rewrite the Calibration subsection from
  'hardcoded by design' to documenting --multi-major-delta with
  raise/lower guidance and the >=1 validation contract.
- architecture: add wait-timeout = "0.2" to the approved-deps table
  with the v0.9.7 attribution and a note on its role in bounding
  Windows plugin-process waits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nd expressions

Refactor the SPDX policy evaluator to evaluate each leaf via a typed
LeafOutcome (Permitted | DeniedBase | DeniedException |
NotInAllowedException) and combine outcomes via the standard SPDX
expression semantics (AND = all permitted; OR = any permitted). The
behavior is unchanged for v0.9.5 single-WITH cases — back-compat
test asserts the bare matched_rule wording.

For compound expressions (more than one leaf) the matched_rule now
appends " (in <raw spdx expression>)" so reviewers can locate the
offending atom in expressions like
'(Apache-2.0 WITH LLVM-exception) AND BSD-3-Clause'.

Module doc-comment gains a 'WITH-chain inheritance' section that
explains AND/OR semantics in plain English.

Tests cover: AND with allowed exception permits; AND with denied
exception violates and cites the leaf with compound context; OR
with one allowed exception branch permits regardless of the
sibling failure; OR with all exceptions denied violates;
AND inherits exception denial from either side; back-compat
regression for compound expressions without exceptions; SARIF/VEX
synthetic id distinct between compound-exception and base-only
violations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d lifted)

Add the v0.9.7 calibration knob that closes the calibration backlog:
every threshold the enrichers gate on is now adopter-tunable.

- Add `enrich::version_jump::enrich_with(cs, Option<u32>)`. `None`
  preserves the v0.9.6 behavior of using `MIN_MAJOR_DELTA = 2`.
  `enrich` now delegates to `enrich_with(cs, None)`.
- Add `--multi-major-delta <u32>` CLI flag on `diff` (range >= 1).
- Add `multi_major_delta: Option<u32>` to `[diff]` config block,
  honored when the CLI flag is unset (mirrors the existing
  young-maintainer / typosquat / cache-ttl knobs).
- Plumb the override through `run_diff` to the enricher and into
  `CalibrationOverrides` so `--debug-calibration` rows for
  version-jump findings emit the *active* threshold rather than
  the unconditional const default.

Tests:
- enrich_with default threshold matches enrich (back-compat)
- threshold=1 trips on a single major bump (1.x → 2.x)
- threshold=5 suppresses what default would flag (1.x → 4.x)
- clap rejects 0 / -1 / non-numeric
- smoke test that the flag wires through to a successful diff run

Docs are owned by the platform agent (cli-reference.md update).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the hand-rolled 25ms try_wait() polling loop in
src/plugin.rs with wait_timeout::ChildExt::wait_timeout. The crate
provides a real platform-aware wait primitive — WaitForSingleObject
on Windows; self-pipe + sigchld on Unix — making timeouts
first-class on Windows instead of best-effort polling that could
race the kill() against a finishing child.

The protocol / JSON / finding-on-success path is unchanged; only
the timeout-detection branch swaps to wait_timeout. Existing
Unix-tagged plugin tests (success / timeout / non-zero-exit /
malformed-JSON / two-plugin merge) all pass and now exercise the
new code path.

Cargo dep added: wait-timeout 0.2 — single-purpose, ~50kb, only
transitive is libc which we already pull in. v0.9.7+.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bump Cargo.toml + Cargo.lock 0.9.6 → 0.9.7.
- CHANGELOG.md: v0.9.7 entry covering SPDX WITH-chain exception
  inheritance, --multi-major-delta knob (last hardcoded threshold
  lifted), Windows plugin timeout via wait-timeout crate, action.yml
  input parity (25 new inputs), and air-gapped Sigstore docs.
- STATUS.md: "What's new in v0.9.7" section above the v0.9.6 one.
- docs/src/roadmap.md: new "Shipped (v0.9.7 — milestone follow-ups)"
  section.
- README.md, docs/src/quickstart.md, .github/ISSUE_TEMPLATE/action-
  broke.md: bump example version pins from v0.9.6 → v0.9.7
  (introduced-in markers like "(v0.9.6)" preserved).

432 tests pass, fmt + clippy 1.88 strict clean.

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

SBOM diff

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

Version changed (1)

Show details
Ecosystem Name Before After
cargo bomdrift 0.9.6 0.9.7

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

@Metbcy Metbcy merged commit 60e3286 into main Apr 30, 2026
9 checks passed
@Metbcy Metbcy deleted the release/v0.9.7 branch April 30, 2026 03:58
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