Skip to content

release: v0.9.8 — code-review-driven hardening (fuzz, coverage, lint, lib split)#27

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

release: v0.9.8 — code-review-driven hardening (fuzz, coverage, lint, lib split)#27
Metbcy merged 9 commits intomainfrom
release/v0.9.8

Conversation

@Metbcy
Copy link
Copy Markdown
Owner

@Metbcy Metbcy commented Apr 30, 2026

v0.9.8 — code-review-driven hardening

External agent reviewed bomdrift against the v0.9.7 state, surfacing
nine recommendations (P1/P2/P3). v0.9.8 takes five of the six high-
leverage items; the other four (mutation testing, remaining file
splits, calibration FPR docs, coverage gate ratchet) are explicitly
deferred to v1.0+ with documented rationale.

Highlights

  • Continuous parser fuzzing. New `fuzz/` standalone sub-workspace
    with three `cargo-fuzz` libfuzzer targets (CycloneDX / SPDX / Syft).
    Runs 60s per target on PRs that touch `src/parse/**`, and 600s
    weekly on cron. Closes the textbook "untrusted-input parser" gap
    for a security tool.
  • CI coverage report. New `coverage` job runs `cargo-llvm-cov`,
    posts a sticky PR comment with line-coverage %, emits `lcov.info`
    as a workflow artifact. Informational for now
    `--fail-under-lines` deferred until baseline visible across 2-3
    releases.
  • `unwrap`/`expect`/`panic`/`todo`/`unimplemented` lints
    enforced.
    Production audit found 4 sites; all true invariants,
    kept as `expect()` with explicit `#[allow(reason = ...)]`
    rationale. Test modules opt-out via inner allow. Zero production
    `.unwrap()` remain.
  • All 23 `unsafe` blocks now carry `// SAFETY:` comments (16
    needed annotation). Enforced via
    `#![warn(clippy::undocumented_unsafe_blocks)]`.
  • `src/lib.rs` 47 KB → 31 lines. Extracted 1,300-line `run_diff`
    orchestration into a new `src/run.rs`. Public API surface
    byte-preserved via re-export. Behavior-preserving — all 432 tests
    pass without modification beyond import-path updates.

What's deferred to v1.0+

Item Why
Remaining file splits (vex.rs, markdown.rs, sarif.rs, baseline.rs, typosquat.rs, license.rs) lib.rs was highest-ROI single split; others land organically
Mutation testing audit (`cargo-mutants`) High-signal but slow; v1.0 audit tool, not CI gate
Calibration FPR docs Needs data-collection infrastructure (top-1000 npm + PyPI × 12 mo of releases)
Coverage `--fail-under-lines` ratchet Flip after 2-3 releases of baseline visibility
WASM-sandboxed plugin model Carryover from v0.9.7; conflicts with single-binary tenet

Process

Two parallel background sub-agents on isolated git worktrees
(established v0.9.5 pattern, fifth release in a row):

  • `feat/v0.9.8-rust` (background, 11.5 min, opus 1M): Phase 1 SAFETY
    comments → Phase 2 unwrap-lint sweep + audit → Phase 3 lib.rs split
    into run.rs.
  • `feat/v0.9.8-platform` (background, 3.6 min, opus 1M, parallel
    with rust): coverage job → fuzz/ sub-workspace + workflow.

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

Test status

  • 432 → 432 (refactor commits are behavior-preserving).
  • 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.

Deps

No new top-level deps. `cargo-fuzz` and `cargo-llvm-cov` are
CI-installed tools; `fuzz/Cargo.toml` is a separate sub-workspace
with its own `libfuzzer-sys` dep that doesn't affect the main
crate.

Post-merge checklist (maintainer)

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

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

Metbcy and others added 8 commits April 30, 2026 13:00
Adds an informational coverage job to .github/workflows/ci.yml:
- runs cargo-llvm-cov on Ubuntu after the test matrix
- uploads lcov.info as a 30-day retention artifact
- posts a sticky PR comment (marocchino/sticky-pull-request-comment)
  with overall line coverage % (computed from lcov DA: records)

Intentionally NOT added to required-status-checks and NOT gated with
--fail-under-lines. The plan is to let coverage be visible for 2-3
releases before introducing a ratchet (v0.9.9 candidate).

Workflow gains pull-requests:write so the sticky-comment action can
upsert. CONTRIBUTING.md gains a short Coverage section under Tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds a standalone fuzz/ sub-workspace with three libfuzzer targets,
one per SBOM parser:

  fuzz/fuzz_targets/parse_cyclonedx.rs
  fuzz/fuzz_targets/parse_spdx.rs
  fuzz/fuzz_targets/parse_syft.rs

Each target uses a two-stage decode (serde_json::Value -> bomdrift
parser) so the fuzzer's budget is spent on bomdrift-side parsing
rather than re-fuzzing serde_json's well-tested layer.

Seed corpus is bootstrapped from tests/fixtures/{cdx,spdx,syft}*.json
under fuzz/corpus/<target>/. cargo-fuzz will grow these from there.

The new .github/workflows/fuzz.yml runs on PRs that touch
src/parse/** or fuzz/** (60s budget per target) and on a Sunday
schedule (600s budget). Crash artifacts are uploaded on failure.
Nightly toolchain is required by libfuzzer instrumentation; the
fuzz/ directory is its own [workspace] root so the main crate's
stable pin is unaffected.

README gains a 'Continuous fuzzing' subsection under Release signing.

This job is informational and is NOT in the required-status-checks
list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Annotate all 16 unsafe blocks that lacked SAFETY comments and turn on
clippy::undocumented_unsafe_blocks crate-wide so future sites are caught
at lint time. All annotated sites are env::{set_var,remove_var} calls
serialized by clock::test_env_lock() or an equivalent process-wide
mutex held by the test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tighten the lint policy crate-wide so accidental panics in production
code are caught at lint time:

Test modules opt out via an inner allow attribute; tests legitimately
use unwrap/expect for terse assertions on known-good fixtures.

Audited the 4 production .expect() sites surfaced by the new lints --
all are true invariants, kept as .expect("invariant: ...") with a
narrowly-scoped #[allow] carrying a reason rationale:

  - baseline.rs: as_object_mut() after is_object() check
  - render/json.rs: to_string_pretty on owned Value with string keys
  - render/sarif.rs: same
  - vex.rs: same

No production .unwrap() sites were flagged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
src/lib.rs went from 1341 lines (47 KB) to 31 lines: it now only
declares the public module tree and re-exports the orchestration
entry points. All other code -- run_diff and its private helpers,
the public predicates (tripped, any_kev, any_epss_at_or_above,
budget_tripped), the public entry point run(), the embedded
INIT_* config templates, the lib tests -- moved verbatim into
the new src/run.rs.

Behavior-preserving: every consumer keeps its historical paths
(bomdrift::run, bomdrift::tripped, ...) via re-exports in lib.rs.
Test count unchanged (432 tests, all green); fmt + clippy 1.88
strict + cargo test --release --all-features all pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bump Cargo.toml + Cargo.lock 0.9.7 → 0.9.8.
- CHANGELOG.md: v0.9.8 entry covering the five hardening items
  (parser fuzzing via cargo-fuzz, CI coverage report via cargo-llvm-
  cov, unwrap/expect lint policy, undocumented-unsafe-blocks lint
  with 16 SAFETY comments added, lib.rs orchestration extracted into
  src/run.rs). Includes scope notes for the four explicitly-deferred
  v1.0 candidates.
- README.md, docs/src/quickstart.md, .github/ISSUE_TEMPLATE/action-
  broke.md: bump example version pins from v0.9.7 → v0.9.8.

432 tests, fmt + clippy 1.88 strict clean.

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

github-actions Bot commented Apr 30, 2026

SBOM diff

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

Added (2)

Show details
Ecosystem Name Version
github dtolnay/rust-toolchain nightly
github marocchino/sticky-pull-request-comment v2

Version changed (1)

Show details
Ecosystem Name Before After
cargo bomdrift 0.9.7 0.9.8

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 Apr 30, 2026

Coverage report

Line coverage: 85.7% (9153 / 10679 lines)

Full lcov report available as workflow artifact lcov.info.

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

The three fuzz targets used unqualified `<Parser>::parse(value)` which
fails with E0599 because `parse` is a trait method defined on
`SbomParser`, not an inherent method. Add `use bomdrift::parse::
{SbomParser, <module>::<Parser>}` to each target.

Caught by all three fuzz CI jobs failing on PR #27 first run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Metbcy Metbcy merged commit c23c07a into main Apr 30, 2026
13 checks passed
@Metbcy Metbcy deleted the release/v0.9.8 branch April 30, 2026 20:22
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