SBOM: transitive mode — inline the internal exposure chain per SBOM - #170
Open
villelaitila wants to merge 3 commits into
Open
SBOM: transitive mode — inline the internal exposure chain per SBOM#170villelaitila wants to merge 3 commits into
villelaitila wants to merge 3 commits into
Conversation
A dependency whose version is governed by an imported BOM or an external parent has no version attribute anywhere in the model, and valid_for_bom dropped it entirely. Modern Maven centralizes versions in parents and BOMs, so the newer the project, the emptier its SBOM: a Spring Boot application lost its whole starter stack while a 2010-era pom came out complete. Three changes, one per missing shape: - An element carrying maven coordinates and at least one incoming reference is now a component with a versionless purl. The incoming requirement keeps out the husks that version-management redirection leaves behind, whose references were re-pointed at versioned elements. - extract_version falls back to parent_version, the attribute a <parent> block produces: the parent's exact version was already in the model and was discarded. - maven_purl treats an empty version like an unresolved expression. Splicing it in would emit a trailing '@' - not a canonical versionless purl but a malformed versioned one.
Review against real stored models found four holes in the previous
commit, all in shapes the fresh-model happy path never meets:
- valid_for_bom admitted parent_version-only elements. Every model
persisted before the analyzer wrote coordinates onto parents has that
shape, and SBOMs are generated on demand from stored models, so the
clause spliced space-bearing element names into generic purls for all
existing deployments. Dropped: on coordinate-carrying models the
coordinate branch already admits every parent.
- The coordinate branch accepted charset-rejected coordinates such as a
${} groupId resolved only in an external parent. Versionless, such an
element builds no maven purl and the fallback splice emits the raw
space-bearing name. The branch now requires is_maven_coordinate on
both attributes.
- Two poms naming one parent at different versions collide on one
versionless element and the attribute transfer joins the versions
with a semicolon. maven_purl now omits such a version; the raw value
stays disclosed in the component's version field.
- The generic fallback splice had no empty-version guard, emitting a
trailing '@' for versionless elements that fall through maven_purl.
A cross-shape invariant test asserts no emitted purl or bom-ref in any
fixture carries a space, a semicolon, or a trailing '@'.
Dependency-Track resolves dependency refs only within one uploaded BOM; the BOM-Link URNs of the default multi-SBOM mode are never followed across projects, so the chain repo -> internal library -> vulnerable 3rd-party component was invisible there. generate_multi_from_sgraph(..., transitive=True) inlines each element's reachable internal elements as components (softagram:internal, with a BOM-Link back to their standalone SBOM as an externalReference) plus the 3rd-party components of the whole chain (softagram:via provenance), and emits a multi-entry dependencies graph in which every ref resolves within the BOM. CLI: --transitive (requires --level).
Softagram Impact Report for pull/170 (head commit: 5816d42)TL;DR Changed code files: 3 | Directly impacted code files: 1⭐ Change Overview
⭐ Details of Dependency Changes
[] 📄 Full report
Impact Report explained. Give feedback on this report to support@softagram.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.


Why
Dependency-Track (the typical consumer of these SBOMs) resolves dependency refs strictly within one uploaded BOM. The BOM-Link URNs emitted by the multi-SBOM mode are never followed across projects — DT drops them as dangling refs — so the exposure chain repoA → internal library → vulnerable 3rd-party component is invisible when each element uploads its own SBOM. DT's own recommendation for this is a merged SBOM with a full transitive
dependenciesgraph; sgraph holds the whole cross-repo graph in one model, so it can generate exactly that, per level element.What
generate_multi_from_sgraph(sgraph, level, transitive=True)— new opt-in mode:softagram:internal=true), each carrying a BOM-Link back to its standalone SBOM as anexternalReferenceof typebomsoftagram:via=<element>dependenciesgraph in which every ref resolves within the BOM — DT's Dependency Graph tab then shows the full path and rolls indirect vulnerabilities up to the root projectCLI:
--transitive(requires--level).Example output for the multi-repo test fixture:
Tests
9 new tests (chain emission, provenance annotation, in-BOM ref resolution, cycle termination, default-mode regression lock, CLI flag incl. rejection without
--level). Full suite: 211 passed.Notes
feature/sbom-versionless-managed-deps) — merge that first; until then this diff includes its commits.?format=cyclonedx-sbom&level=N&transitive=trueREST param is prepared, gated on the next sgraph release.