Repository navigation
bom-tools 0.3.0: license report and SBOM from build evidence - #9
Merged
Merged
Conversation
Classify every compiled crate as runtime or build-time using Cargo's own resolver (`cargo tree`), cross-checked against the build log, and approve the result against the allow-list instead of filtering with it. - input/: readers that turn one target's evidence (build log + full and runtime `cargo tree`) into a format-neutral TargetGraph (graph.rs) - inventory.rs: merge targets (runtime wins), resolve against the cargo metadata dictionary, normalize declared licenses once, `embedded` - approval.rs: every crate in exactly one list, build-only crates may not ship, reviewed licenses checked against the declared SPDX expression - sbom.rs + gen-sbom-log[-dir]: CycloneDX 1.5 output - gen-licenses-log[-dir] now take --root-package and per-target directories with build.json, tree.txt and runtime-tree.txt - Apache-2.0 license, `embedded` and `commercial_license` config fields - tests: unit tests, a fixture workspace built with the installed Cargo, golden tests on real dnp3 evidence, and a regression test that the deprecated cargo-cyclonedx commands still match 0.2.1 output
- README: what the tool does, the producer recipe for the build evidence, commands, allowed.json rules, and the guarantees and limits of the cross-checks - CHANGELOG entry for 0.3.0 (breaking changes to gen-licenses-log*) - GitHub Actions: fmt, clippy, tests (including the real-Cargo fixture), and CycloneDX 1.5 schema validation of an SBOM with a pinned, checksum-verified cyclonedx-cli
- the root must be a workspace member (it is never approved) - the root's product artifact is matched by full package identity, so a dependency with the same name cannot satisfy it - build log lines are parsed whole; nothing may follow build-finished - lockfile checksums must be 64 hex digits - third_party entries are sanity-checked whatever the package's role - single-target flags are --log/-g, --tree, --runtime-tree - tests: reader negatives (dropped/extra packages, feature mismatch, runtime tree from other arguments, roots, product artifact), direct TargetGraph SBOM tests (per-version hashes, bom-ref collision, license encoding), exact per-version hash and report/SBOM invariant checks, a host-only feature dependency in the Cargo fixture, Windows expectations, and a fresh fixture directory per run
- deserialize each cargo message from the original line rather than an intermediate serde_json::Value, which kept the last of duplicate keys - fixture build evidence lives in a fixed, cleared directory inside the target directory instead of accumulating in the system temp dir - README: state exactly what the cross-checks prove, scope the approval rules to the build-evidence commands and non-workspace packages, and document the workspace-root and commercial_license requirements
Concurrent test runs must not share the fixture build or the golden test's temporary config; keep them per process inside the target directory.
Agreed with Codex review: - cut tests duplicated elsewhere (Role ordering, path-key resolution, the executable-documentation limitation test, standalone 1.5 validation now folded into the SBOM content test as a parse-back check) - the missing commercial license is a renderer unit test; the command test proves --lockfile reaches the renderer without temp files - repaired tests that passed with a wrong implementation: build-script skip (distinct features), blank lines after build-finished, runtime-wins in both target orders, and an independent expected set for the license report (precursor-derived) - one graph test helper and one Variant constructor instead of copies
Architecture review (Claude and Codex): - remove gen-licenses / gen-licenses-dir: BOM scope always comes from the build, so reading cargo-cyclonedx output has no place in the tool - licenses.rs is now only the report renderer (`licenses::write`, the counterpart of `sbom::write`) and renders straight from the validated inventory, without config lookups or unreachable error paths - one definition per license (SPDX id and text; the URL is derived) instead of four parallel matches - ValidatedInventory fields are private: only approval constructs it - config entries named for what they are (ThirdPartyEntry, VendorEntry) - the target-directory convention moved into `input` with the other file-name knowledge; doc fixes (Runtime, TargetInput, third_party) - golden test pinning the license report format byte for byte Report and SBOM output verified identical before and after on the dnp3 fixture and on the merged, JNI and cross-musl evidence.
- README: notice that 0.3.0 removed the cargo-cyclonedx commands, with the 0.2.1 pin for consumers that have not migrated - README: say explicitly that Cargo's SBOM precursor files are a future input reader for this tool; approval and outputs stay the same - licenses::write only performs writes, so it returns std::io::Result
The tool produces the license report and the SBOM from build evidence and enforces the allow list, so name it after the repository it lives in. - crate, binary and directory: allow-list -> bom-tools - `licenses` and `sbom` replace gen-licenses-log[-dir] and gen-sbom-log[-dir]; both read a directory of targets (-e/--evidence-dir), so a single target is one subdirectory - README, CHANGELOG (with a migration section) and CI updated
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.
Implements #7. Supersedes #6.
What
bom-tools0.3.0 (renamed fromallow-list) produces the third-party license report and a CycloneDX 1.5 SBOM from the evidence of the build that produced the product, and enforcesallowed.jsonas an approval list.cargo build --message-format jsonlog (what compiled, with features) and twocargo treeoutputs (Cargo's own resolver decides runtime vs build-time), cross-checked so that disagreeing evidence fails. Recipe in the README.allowed.jsonapproves, it doesn't filter. Every package outside the workspace must be in exactly one list; abuild_onlycrate that becomes linked fails; reviewed licenses of shippedthird_partycrates are checked against the declared SPDX expression in both directions. All violations are reported together.bom-tools licensesandbom-tools sbom, each reading a directory with one subdirectory per target.sbomrequires the build'sCargo.lockfor SHA-256 hashes.gen-licenses/gen-licenses-dir(cargo-cyclonedx input).gen-licenses-log*replaced bylicenses.Motivating regression: dnp3 1.7.0 builds most targets with
tls-aws-lc, butcargo cyclonedx(no feature flags) reportedringand omittedaws-lc-rs/aws-lc-sys, which were also never approved. With this tool, dnp3's currentallowed.jsonfails on exactly those gaps.Design
Only
input/knows the evidence formats, so Cargo's SBOM precursor files can become another reader later (#8). On a nightly build of dnp3 the precursor gives the identical runtime (90) and full (140) package sets.Verification
crossmusl build.xxhash-rust 0.8.15.Not yet verified
Consumers
Breaking. Repos that
cargo install --gitthis tool without a tag (dnp3, rodbus) will break on merge; pin--tag 0.2.1until migrated. See the README's migration section.