release: v0.9.6 — finish the roadmap + comprehensive docs refresh#23
Merged
release: v0.9.6 — finish the roadmap + comprehensive docs refresh#23
Conversation
Resolves every entry in docs/src/roadmap.md's Future candidates and Calibration backlog sections per the v0.9.6 finish-the-roadmap plan: - New Shipped (v0.9.6) section listing F1+A+B+C. - Reachability moved to Non-goals as its own subsection (lifted from STATUS pair-with-Endor recommendation). - GraphQL maintainer-age recorded under new "Investigated and decided" section with the per_page=1+Link rationale; decided REST stays. - VEX vocabulary justification documented in vex.md; entry removed from roadmap. - PyPI / crates.io maintainer-set-changed moved to new "Blocked on upstream" subsection with precise API gap. - Calibration backlog collapsed to a single sentence pointing at the three new flags + config keys. - cli-reference: documented --typosquat-similarity-threshold, --young-maintainer-days, --cache-ttl-hours. - STATUS: added rows for plugin system + attestation verification. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Promote pub const CACHE_TTL_SECS in src/enrich/cache.rs as the only definition. Replace the duplicated const in epss.rs, kev.rs, and registry.rs with a use of crate::enrich::cache::CACHE_TTL_SECS. Foundation for v0.9.6 calibration knobs (cache-ttl-hours override needs to plumb through one place, not four). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reference plugin demonstrating bomdrift's external-process plugin
protocol. Reads banned.txt (one purl prefix per line, # comments
allowed), checks each Added or VersionChanged component's purl as a
prefix match, emits {kind, message, severity, rule_id} findings on
stdout per the v0.9.6 plugin protocol.
Includes:
- plugin.toml manifest (timeout_ms=5000, invoke_on=[added, version-changed])
- check-banned.sh bash + jq executable (bash -n clean)
- banned.txt with 6 illustrative entries (event-stream, coa, ctx,
rustdecimal, etc.) + comments documenting why each was flagged
- README covering adaptation, CI wiring, performance (O(N x M)),
and security (plugins are not sandboxed) notes
Smoke-tested against a matching, non-matching, and exact-version
purl envelope.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New docs/src/attestation.md covering the v0.9.6 OCI attestation flow: overview, prerequisites, generating attestations (sketch), the four new flags (--before-attestation, --after-attestation, --cosign-identity, --cosign-issuer), --require-attestation hard mode, explicit threat-model trust boundaries, self-managed Sigstore via SIGSTORE_REKOR_URL etc, troubleshooting top failure modes, and what is intentionally not in v0.9.6 (SPDX, in-process Sigstore client, air-gap test coverage). Linked from SUMMARY.md under the Output section. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New docs/src/plugins.md covering the v0.9.6 plugin system end to end: - Overview + threat model (plugins are not sandboxed). - Design rationale for shell-out vs WASM. - TOML manifest schema (name, exec, timeout_ms, invoke_on, ...). - Stdin/stdout JSON protocol with the full envelope shapes. - SARIF mapping under the new bomdrift.plugin rule. - Failure semantics table (non-zero, timeout, malformed JSON, ...). - Windows timeout caveat. - Worked-example pointer to examples/plugins/banned-packages/. - Performance notes (sequential, N x P, fork costs). - Security checklist (vet, pin, scrub env, mirror). - v0.9.6 stability promise + protocol_version forward-compat plan. - GitHub Actions wiring example. Linked from SUMMARY.md under Operations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ays, cache TTL
Three new CLI flags + matching [diff] config keys:
- --typosquat-similarity-threshold <FLOAT> (0.0..=1.0, clap-validated)
- --young-maintainer-days <i64> (>= 1, clap-validated)
- --cache-ttl-hours <u64> (>= 1, applies uniformly to
OSV/EPSS/KEV/Registry caches)
New helper: cache::effective_ttl_secs(Option<u64>) -> u64. Single
source of truth for resolving the override-vs-default decision; threaded
through all four cache call sites.
New helpers in enrichers, preserving the v0.9 public surface:
- typosquat::enrich_with_threshold(cs, Option<f64>)
- maintainer::enrich_with(..., Option<i64>) — extended in-place
- osv::enrich_cached_with_ttl(cs, no_cache, Option<u64>)
- epss::enrich_with_ttl / kev::enrich_with_ttl
- registry::enrich(cs, recently_published_days, cache_ttl_hours)
Calibration tap now emits the *active* threshold (the override when
set, else the const default), so adopters running --debug-calibration
with custom knobs see what the enricher actually used.
Tests: clap rejection for out-of-range / non-numeric values; calibration
threshold-column reflects the override; typosquat findings drop when
threshold is raised; cache TTL helper conversion + override semantics.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gistries New `bomdrift::attestation` module wraps `cosign verify-attestation --type=cyclonedx`, decodes the resulting in-toto DSSE envelope, and extracts the embedded CycloneDX predicate as serialized JSON ready for the standard parser pipeline. CLI: - --before-attestation <oci-ref> (conflicts with positional 'before') - --after-attestation <oci-ref> (conflicts with positional 'after') - --cosign-identity <regex> (passed to --certificate-identity-regexp) - --cosign-issuer <url> (passed to --certificate-oidc-issuer) - --require-attestation (refuses local-file fallback) The positional `before`/`after` paths become optional, gated by `required_unless_present` on the matching attestation flag. Cosign is treated as an optional runtime dep: when missing on PATH we surface a clear error pointing at the install docs (no in-process sigstore verification — that demands a Fulcio CA bundle + rekor witness validation that's out of scope for v0.9.6). `--debug-calibration` gains an `attestation|<oci>|verified|<identity>` row so adopters can confirm the cert regex cosign accepted. New direct dep: `base64 = "0.22"` (already transitively present via ureq; promoted to direct so we own the version pin). Tests: in-toto envelope parse (well-formed + per-line emission + malformed payload variants); fake-cosign integration test prepends a tempdir to PATH (serialized via clock::test_env_lock); cosign-not-on-PATH error path; clap conflicts and --require-attestation gating. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Minimum-viable Phase C: bomdrift learns to load plugins via TOML
manifests, shell out to the plugin executable per added /
version-changed component, and merge plugin findings into the standard
Enrichment surface. No WASM, no sandbox, no language commitment —
plugins are whatever executable the author wants.
New `bomdrift::plugin` module:
- PluginManifest / InvokeEvent / PluginFinding / PluginSeverity types.
- load_manifest(path) — parses TOML, resolves relative `exec` against
manifest dir, validates timeout_ms > 0.
- run_plugins(manifests, cs) — spawns child per (plugin, component, event),
feeds JSON to stdin, polls try_wait() with 25ms tick + manifest
timeout_ms, parses stdout JSON. Best-effort: timeout / non-zero exit /
malformed JSON drops findings + emits stderr at BOMDRIFT_DEBUG=1.
Wire format ("v1", may evolve):
stdin: { protocol_version: 1, component, event, before }
stdout: { findings: [{ kind, message, severity, rule_id }] }
CLI: --plugin <path> (repeatable). Manifests load eagerly so a typo
fails the run; runtime plugin failures stay best-effort.
Renderers gain a Plugin findings section:
- Markdown: subsection per plugin, severity-emoji-prefixed bullets.
- Term: [PLG] tag, severity-toned ANSI coloring.
- JSON: enrichment.plugin_findings array (already wired via #[serde]).
- SARIF: new bomdrift.plugin rule + properties.pluginName /
findingKind / ruleId / purl. Stable partialFingerprints from
sha256(plugin_name + component_purl + rule_id) — distinct per finding,
byte-stable across runs. Severity maps info→note / warning→warning /
error→error.
No new heavy deps. Timeouts use std::thread::sleep + Child::try_wait
in a loop (no wait-timeout crate needed for the v0.9.6 contract).
Tests: manifest parse (min + full + missing-exec + bad-enum-value);
happy invocation; timeout drops findings (well under sleep duration);
non-zero exit drops findings; malformed JSON drops findings; two
plugins merge correctly; fingerprint stability + distinctness;
SARIF emits one bomdrift.plugin result per finding with distinct
fingerprints; CLI end-to-end produces 'Plugin findings' in markdown
and bomdrift.plugin results in SARIF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…on, plugin system)
…docs, plugin docs)
….9.6-new section Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-code-scanning + cross-link comment-bridges Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dd introduced-in annotations Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… + test conventions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…bling, see-also Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ssions / Advanced Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bump release-signing example to VERSION=v0.9.6 - Replace stale GitLab 'deferred to v0.8' note with v0.9 Worker bridge documentation - Fix two anchor links in baseline.md to match actual headings (vex.md#emitting-vex, license-policy.md#suppression) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bump Cargo.toml + Cargo.lock 0.9.5 → 0.9.6. - CHANGELOG.md: v0.9.6 entry covering OCI attestation verification, external-process plugin system, CLI calibration knobs (typosquat similarity / young-maintainer-days / cache-ttl-hours), CACHE_TTL_SECS unification, the comprehensive documentation refresh across every chapter, and the roadmap cleanup that closes out every Future candidate from v0.9.5 with explicit dispositions. 420 tests, clippy + fmt clean, base64 promoted to direct dep (transitive via ureq, now pinned). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SBOM diff
Version changed (1)Show details
False positive? Report it · Suppress a finding? Comment |
Metbcy
added a commit
that referenced
this pull request
Apr 30, 2026
…code) Every caller of `fn comp` is inside `#[cfg(unix)]` tests (the bash-script plugin runners). Without the matching cfg on `comp` itself, Windows test builds fail with `dead_code` under `-D warnings`. Caught by ubuntu+macos passing while windows-latest failed on PR #23. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Metbcy
added a commit
that referenced
this pull request
Apr 30, 2026
…code) Every caller of `fn comp` is inside `#[cfg(unix)]` tests (the bash-script plugin runners). Without the matching cfg on `comp` itself, Windows test builds fail with `dead_code` under `-D warnings`. Caught by ubuntu+macos passing while windows-latest failed on PR #23. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…code) Every caller of `fn comp` is inside `#[cfg(unix)]` tests (the bash-script plugin runners). Without the matching cfg on `comp` itself, Windows test builds fail with `dead_code` under `-D warnings`. Caught by ubuntu+macos passing while windows-latest failed on PR #23. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.9.6 — finish the roadmap
Closes out every "Future candidates" entry from the v0.9.5 roadmap with
explicit dispositions (ship / non-goal / blocked-on-upstream / decided)
plus a comprehensive documentation refresh across every chapter.
Highlights
bomdrift diff --before-attestation <oci-ref> --after-attestation <oci-ref>shells out tocosign verify- attestation --type=cyclonedx, verifies + decodes the in-toto envelope,feeds the verified SBOM into the standard parser. New
--require-attestationflag refuses falling back to file inputs forproduction CI gates. New chapter
docs/src/attestation.md.--plugin <manifest.toml>(repeatable). JSON over stdin/stdout. Best-effort failures (timeout,
non-zero exit, malformed output drop the offending plugin's findings;
rest of report renders). New
bomdrift.pluginSARIF rule with stablefingerprints. Worked example shipped at
examples/plugins/banned- packages/. New chapterdocs/src/plugins.md.thresholds:
--typosquat-similarity-threshold,--young-maintainer-days,--cache-ttl-hours.--debug-calibrationrows now emit the active threshold so collected data reflects the
real run.
CACHE_TTL_SECSunified. Previously duplicated in 4 modules.Single source of truth in
src/enrich/cache.rswitheffective_ttl_secs(Option<u64>)helper.comparison table vs Socket / Snyk / Trivy / OSV-Scanner / Grype.
cli-reference.mdrewritten end-to-end — every flag documented andgrouped by purpose with introduced-in annotations.
architecture.mdmodule map covers all 8 v0.7-v0.9.6 new modules.
baseline.mdschemareference. Per-enricher chapter audit + standardized subsections.
SUMMARY.mdreorganized.Roadmap closures (v0.9.5 Future candidates → v0.9.6 dispositions)
After this PR merges the "Future candidates" section is empty.
Process
Three sequential sub-agents on isolated worktrees / branch:
feat/v0.9.6-rust(parallel): 4 phases of Rust source changes(cache-TTL unify → calibration knobs → OCI attestation → plugin
system core).
feat/v0.9.6-platform(parallel with rust): 4 phases ofdocs/examples/CI changes (roadmap cleanup → banned-packages example
plugin → attestation docs chapter → plugins protocol docs chapter).
release/v0.9.6(sequential after both): comprehensive10-phase documentation refresh, then this release-prep commit.
Both feature branches merged cleanly into
release/v0.9.6with zeroconflicts (disjoint file ownership). 420 tests green throughout.
Test status
cargo test --releaseubuntu / macos /windows.
cargo clippy --all-targets --all-features --release -- -D warningsclean (Rust 1.88 toolchain pinned in CI by v0.9.5).
cargo fmt --all -- --checkclean.Scope notes
Stayed deferred (v1.0+ candidates):
revisit if demand materializes).
vex:/emit-vex:/plugin:inputs (CLI surface is broader than action surface).
MIN_MAJOR_DELTAcalibration knob (onlyremaining hardcoded threshold).
Post-merge checklist (maintainer)
v0.9.6on the merge commit.v1tag tov0.9.6.release/v0.9.6,feat/v0.9.6-rust,feat/v0.9.6-platformbranches.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com