Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,123 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.9.7] - 2026-04-29

The "v0.9.6 follow-up backlog" milestone. Five concrete items from the
v0.9.6 release notes' "Suggested next milestone candidates" list shipped
in one polish release: per-exception SPDX inheritance through compound
expressions, the last hardcoded calibration threshold lifted, proper
Windows plugin process timeouts, full `action.yml` parity with the CLI
flag surface, and air-gapped Sigstore documentation.

### Added

- **`--multi-major-delta <u32>`** CLI flag and matching
`[diff] multi_major_delta` config key (default `2`, validated `>= 1`).
Lifts the last hardcoded calibration threshold:
`version_jump::MIN_MAJOR_DELTA`. Raise to reduce false positives on
legitimate major-version-bump-heavy ecosystems; lower to flag any
major bump (1.x → 2.x). `--debug-calibration` rows now emit the
*active* delta rather than the const default.
- **`action.yml` input parity** with the v0.7-v0.9.7 CLI surface.
Twenty-five new inputs now map to their corresponding CLI flags:
`vex`, `emit-vex`, `vex-author`, `vex-default-justification`,
`allow-licenses`, `deny-licenses`, `allow-exception`,
`deny-exception`, `allow-ambiguous-licenses`, `no-epss`, `no-kev`,
`no-registry`, `fail-on-epss`, `recently-published-days`,
`typosquat-similarity-threshold`, `young-maintainer-days`,
`cache-ttl-hours`, `multi-major-delta`, `before-attestation`,
`after-attestation`, `cosign-identity`, `cosign-issuer`,
`require-attestation`, `plugin`. Multi-line inputs (`vex`, `plugin`)
iterate one flag per non-empty line. Empty inputs contribute no
CLI args, so existing workflows are byte-identical without changes.
- **Air-gapped / self-hosted Sigstore documentation** in
`docs/src/attestation.md`. Documents env vars cosign respects and
bomdrift inherits unchanged: `SIGSTORE_REKOR_URL`,
`COSIGN_REKOR_URL`, `SIGSTORE_FULCIO_URL`, `COSIGN_FULCIO_URL`,
`SIGSTORE_OIDC_ISSUER`, `COSIGN_OIDC_ISSUER`, `SIGSTORE_ROOT_FILE`,
`COSIGN_REPOSITORY`, `TUF_ROOT`. Includes a worked GitHub Actions
example with internal Sigstore endpoints, key-based attestation
fallback notes (for true air-gap where keyless OIDC isn't
reachable), and a 6-item troubleshooting checklist.

### Changed

- **SPDX `WITH`-chain exception inheritance through compound
expressions.** v0.9.5 added per-exception allow/deny via
`[license] allow_exceptions` / `deny_exceptions`, but the evaluator
only checked the immediate atom. v0.9.7 evaluates each leaf in the
expression tree and combines outcomes via the SPDX crate's native
AND/OR semantics:
- `(Apache-2.0 WITH LLVM-exception) AND (BSD-3-Clause)` with
`deny_exceptions=[LLVM-exception]` is now correctly **denied**
(the AND-chain inherits the exception denial).
- `(Apache-2.0 WITH LLVM-exception) OR
(Apache-2.0 WITH Classpath-exception-2.0)` with
`allow_exceptions=[LLVM-exception]` (Classpath not allowed) is
correctly **permitted** (the LLVM branch wins; OR doesn't poison).
- Single-WITH expressions (no compound) keep the v0.9.5 wording for
back-compat. Compound violations append `" (in <raw expression>)"`
so users can locate the offending atom.
- **Plugin process timeout** now uses the `wait-timeout` crate
(~50kb, `libc`-only transitive). Replaces the v0.9.6 manual
`Child::try_wait()` polling loop. Behavior unchanged on Unix; on
Windows the kill-on-timeout path is now first-class instead of
best-effort. Preserves the existing best-effort failure semantics
(timeout drops the offending plugin's findings, logs a warning at
`BOMDRIFT_DEBUG=1`, rest of the report renders).

### Deps

- Added `wait-timeout = "0.2"` to `[dependencies]` for cross-platform
process timeout in `src/plugin.rs`. Single transitive (`libc`,
already in tree).

### Tests

- 420 → 432 (+12). Eight new tests cover SPDX `WITH`-chain
inheritance through every operator combination
(AND-with-denied-exception, OR-with-permitted-fallback,
back-compat single-WITH); two tests cover the `--multi-major-delta`
knob (override default + reflect in `--debug-calibration`); two
cover the `wait-timeout`-based plugin timeout path.

### Documentation

- `docs/src/cli-reference.md`: new `--multi-major-delta` entry.
- `docs/src/license-policy.md`: new "WITH-chain exception
inheritance" subsection with three worked examples.
- `docs/src/enrichers/version-jump.md`: Calibration subsection
rewritten to cover the new knob.
- `docs/src/architecture.md`: `wait-timeout = "0.2"` row added to
the approved-deps table.
- `docs/src/github-action.md`: action input reference regrouped
by purpose; "What's new in v0.9.7" subsection added.
- `docs/src/attestation.md`: air-gapped subsection (above).

### Roadmap

This release closes 5 of the 6 "Suggested next milestone candidates"
from v0.9.6's release notes:

| Item | Disposition |
|---|---|
| Per-exception SPDX granularity through `WITH` chains | **Shipped** |
| Multi-major version-jump calibration knob | **Shipped** |
| Windows plugin timeout (proper, not best-effort) | **Shipped** |
| Action.yml parity with newer CLI flags | **Shipped** |
| Cosign air-gapped Sigstore docs | **Shipped** |
| WASM-sandboxed plugin model | **Deferred** (multi-week scope, conflicts with single-binary tenet; v1.0+ candidate if external-process model proves insufficient) |

### Scope notes

- **WASM-sandboxed plugin model** stayed deferred. The external-process
plugin model from v0.9.6 covers the use case adopters want; WASM
sandboxing would add a multi-week toolchain overhaul (`wasmtime`
~30MB / 80 transitive deps, or `wasmi`'s slower runtime, plus a Rust
plugin SDK, plus dual-runtime support to not break v0.9.6 plugins).
Stays a v1.0+ candidate if demand materializes.

## [0.9.6] - 2026-04-29

The "finish the roadmap" milestone. v0.9.6 closes out every entry in the
Expand Down
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bomdrift"
version = "0.9.6"
version = "0.9.7"
edition = "2024"
rust-version = "1.88"
description = "SBOM diff with supply-chain risk signals (CVEs, typosquats, maintainer-age)."
Expand Down Expand Up @@ -36,6 +36,10 @@ sha2 = { version = "0.10", default-features = false }
# Exact-pinned: SPDX list updates can shift LicenseId.is_gnu() / is_osi_approved membership and silently change license-policy semantics. Bump deliberately.
spdx = { version = "=0.10.9", default-features = false }
base64 = { version = "0.22", default-features = false, features = ["std"] }
# Robust child-process timeout. Tiny single-purpose crate (~50kb, no
# transitives). Used by src/plugin.rs to replace a hand-rolled polling
# loop with a proper Windows-aware wait_timeout call. v0.9.7+.
wait-timeout = "0.2"

[dev-dependencies]
criterion = { version = "0.5", default-features = false, features = ["html_reports"] }
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Recent incidents bomdrift would have surfaced:

The dimensions adopters actually filter on. Sourced from
[`files/competitor-research-v0.7-v0.9.md`](./files/competitor-research-v0.7-v0.9.md);
correct as of v0.9.6.
correct as of v0.9.7.

| | bomdrift | Socket | Snyk | Trivy | OSV-Scanner | Grype |
|------------------------------------------|:---:|:---:|:---:|:---:|:---:|:---:|
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:
# verify-signatures: true (set false on trusted mirrors)
```

Pin to `@v1` for the latest v0.x; pin to `@v0.9.6` for reproducible builds. Run `bomdrift init` if you want a checked-in `.bomdrift.toml` policy and both workflows scaffolded locally. See the [Action reference](https://metbcy.github.io/bomdrift/github-action.html) for every input — including `upload-to-code-scanning`, `verify-signatures`, `comment-size-limit`, and the `before-sbom`/`after-sbom` escape hatch.
Pin to `@v1` for the latest v0.x; pin to `@v0.9.7` for reproducible builds. Run `bomdrift init` if you want a checked-in `.bomdrift.toml` policy and both workflows scaffolded locally. See the [Action reference](https://metbcy.github.io/bomdrift/github-action.html) for every input — including `upload-to-code-scanning`, `verify-signatures`, `comment-size-limit`, and the `before-sbom`/`after-sbom` escape hatch.

**Other forges:** GitLab CI, Bitbucket Pipelines, and Azure DevOps Pipelines all have ready-to-copy templates under [`examples/`](./examples/) and dedicated docs chapters: [GitLab CI](https://metbcy.github.io/bomdrift/gitlab-ci.html), [Bitbucket](https://metbcy.github.io/bomdrift/bitbucket.html), [Azure DevOps](https://metbcy.github.io/bomdrift/azure-devops.html). Comment-driven `/bomdrift suppress` works on all four SCMs via the Cloudflare Worker bridges added in v0.9.5.

Expand Down Expand Up @@ -127,7 +127,7 @@ Comment `/bomdrift suppress GHSA-xxxx` on any PR; the sub-action appends to `.bo
Pre-built binaries cover Linux x86_64 + aarch64, macOS aarch64, and Windows x86_64. Each archive is cosign-signed via Sigstore + GitHub OIDC.

```bash
VERSION=v0.9.6
VERSION=v0.9.7
TARGET=x86_64-unknown-linux-gnu
curl -sSL -o bomdrift.tar.gz \
"https://github.com/Metbcy/bomdrift/releases/download/${VERSION}/bomdrift-${VERSION}-${TARGET}.tar.gz"
Expand All @@ -143,7 +143,7 @@ Verify the archive's signature before you trust the binary — see [Release sign
### From source

```bash
cargo install --locked --git https://github.com/Metbcy/bomdrift --tag v0.9.6 bomdrift
cargo install --locked --git https://github.com/Metbcy/bomdrift --tag v0.9.7 bomdrift
```

Requires Rust 1.85+ (the project uses edition 2024).
Expand Down Expand Up @@ -279,7 +279,7 @@ Every release archive is signed with cosign keyless via Sigstore (GitHub OIDC).

```bash
# Replace VERSION + TARGET with your downloaded archive's pair
VERSION=v0.9.6
VERSION=v0.9.7
TARGET=x86_64-unknown-linux-gnu
ARCHIVE=bomdrift-${VERSION}-${TARGET}.tar.gz

Expand Down
25 changes: 23 additions & 2 deletions STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,31 @@

bomdrift is usable today as a local CLI and as a composite GitHub Action,
with first-class templates + comment-driven suppression bridges for GitLab
CI, Bitbucket Pipelines, and Azure DevOps Pipelines. The v0.9.6 line ships
CI, Bitbucket Pipelines, and Azure DevOps Pipelines. The v0.9.x line ships
the last items off the public roadmap (calibration knobs, OCI attestation,
a plugin system) while keeping the project OSS-first: no hosted dashboard,
no account, no telemetry.
no account, no telemetry. v0.9.7 closes the v0.9.6 follow-up backlog
(SPDX `WITH`-chain inheritance, last hardcoded threshold lifted, Windows
plugin timeout, action.yml parity, air-gapped Sigstore).

## What's new in v0.9.7

Five polish items closing the v0.9.6 follow-up backlog:

1. **SPDX `WITH`-chain exception inheritance.** `(X WITH ex) AND (Y)`
and `(X WITH ex_a) OR (X WITH ex_b)` now evaluate per-leaf with
proper AND/OR semantics: AND inherits a denied exception, OR
doesn't poison if another branch is permitted.
2. **`--multi-major-delta <N>`.** Last hardcoded calibration threshold
lifted (default 2). Tunable via flag or `[diff] multi_major_delta`.
3. **First-class Windows plugin timeout.** Replaced the manual
`Child::try_wait()` polling loop with the `wait-timeout` crate.
4. **`action.yml` input parity** with the v0.7-v0.9.7 CLI surface.
Twenty-five new inputs cover VEX, license policy, enrichment
toggles, calibration, attestation, plugins.
5. **Air-gapped / self-hosted Sigstore docs** — env-var passthrough
model documented (bomdrift inherits `SIGSTORE_REKOR_URL` etc.
without any flag-side changes).

## What's new in v0.9.6

Expand Down
Loading
Loading