COR-1258: generate CycloneDX SBOMs alongside scan reports - #142
COR-1258: generate CycloneDX SBOMs alongside scan reports#142juangaitanv wants to merge 3 commits into
Conversation
Add `corgea scan --sbom [FILE]` (default bom.json): after a blast scan
completes, generate a CycloneDX SBOM locally from the project tree via
the offline deps engine, alongside any --out-format report.
- Upgrade the CycloneDX emitter from bare 1.4 to spec 1.7: serialNumber,
metadata (timestamp, tool, root component), bom-refs on components,
dependsOn grouped per ref. Output validates against the official
bom-1.7 JSON schema.
- Maven: resolve ${property} / ${project.version} version placeholders
and emit root->dependency graph edges (dependencies array was always
empty for pure-Maven projects).
- Warn on stderr when detected ecosystems (Go, Cargo) are not included
in the SBOM, instead of silently emitting an empty-looking document.
- Error cleanly (exit 2) on nonexistent paths in deps subcommands.
- Tests: e2e scan --sbom against the HTTP stub, Maven property/edge
coverage, warning + path-error CLI tests, emitter unit tests. Scrub
GIT_* env in the repo-info test so it passes inside git hooks.
…inherited-version deps
- Omit component version/purl when the version is unresolved (? placeholder
or ${...} Maven property) instead of emitting null versions and invalid
@? purls; bom-ref keeps the internal id.
- Dedup components by bom-ref and dependsOn per ref (schema uniqueItems).
- Maven: project.version falls back to the parent's version for child POMs
and resolves through properties (${revision} CI versioning).
- scan --sbom write failures exit 1 with a clean error instead of panicking.
All emitter outputs re-validated against the official bom-1.7 schema.
| Some(package_id.clone()), | ||
| false, | ||
| )); | ||
| ctx.graph.edges.push(DependencyEdge { |
There was a problem hiding this comment.
parse_pom_regex (lines 188–210) returns every <dependency> block, including entries under <dependencyManagement>, and this new edge now presents all of them as direct runtime dependencies. A standard POM that manages guava:32.1.3 under <dependencyManagement> and then declares Guava without a <version> produces both a false root edge to the management-only entry and a second direct component whose id/purl ends in @ because the declared version is empty. The resulting SBOM does not represent Maven's effective dependency graph, and downstream package/CVE matching can miss the actual dependency. Restrict edge/component emission to the project-level <dependencies> section and resolve omitted direct versions from dependency management (including imported/parent management as supported), then cover a managed version + versionless direct declaration.
| }; | ||
| let key = &after[..end]; | ||
| match props.get(key) { | ||
| Some(v) => out.push_str(v), |
There was a problem hiding this comment.
Property interpolation stops after one substitution: values are stored raw at line 130, and this branch appends the raw value without resolving placeholders inside it. For example, <base.version>2.5.0</base.version><guava.version>${base.version}</guava.version> with dependency version ${guava.version} remains ${base.version}. to_cyclonedx then treats it as unresolved and omits the component's version/purl even though Maven resolves it to 2.5.0, causing silent SBOM/CVE matching gaps. Resolve properties to a fixed point with a bounded iteration/cycle guard, and add a chained-property regression test.
unsupported_ecosystem_label re-encoded which ecosystems produce graph nodes; derive it from ecosystems::is_graphed, defined beside the scanner dispatch so a future Go/Cargo scanner updates both in one place.
Summary
Implements COR-1258: generate a CycloneDX (1.7, latest) SBOM immediately after a scan, alongside the SARIF report.
corgea scan --sbom [FILE]flag (defaultbom.json): after the blast scan completes and any--out-formatreport is written, a CycloneDX SBOM is generated locally from the project tree via the offlinedepsengine — no server changes, no network.serialNumber(urn:uuid),metadata(timestamp, tool, root component),bom-refon every component,dependsOngrouped per ref. Output validates against the officialbom-1.7.schema.json;corgea deps sbomshares the same emitter.${property}/${project.version}version placeholders now resolve before purl construction, and the scanner emits root→dependency edges (thedependenciesarray was always empty for pure-Maven projects).depssubcommands error cleanly (exit 2) on nonexistent paths instead of succeeding with empty output.Compliance enrichment (licenses, scope, hashes, Go/Cargo coverage) is tracked separately in COR-1733.
Test plan
cargo test— 543 passed, 0 failed (clippy clean, fmt clean)tests/cli_scan_sbom.rs: full stubbed scan flow → defaultbom.json, custom filename, no file without the flagmaven_tests.rs+ newjava-maven-propsfixturecli_deps.rs