SBOM: include version-managed and parent-pom Maven dependencies - #168
Open
villelaitila wants to merge 2 commits into
Open
SBOM: include version-managed and parent-pom Maven dependencies#168villelaitila wants to merge 2 commits into
villelaitila wants to merge 2 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 '@'.
Softagram Impact Report for pull/168 (head commit: c149074)TL;DR Changed code files: 3 | Directly impacted code files: 1⭐ Change Overview
[] 📄 Full report
Impact Report explained. Give feedback on this report to support@softagram.com |
This was referenced Aug 4, 2026
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.

Problem
valid_for_bomrequired a version for a dependency to appear in the SBOM at all. A dependency whose version is governed by an imported BOM or an external parent pom has no version anywhere in the model, so it was dropped entirely. Modern Maven centralizes versions exactly there, which inverted SBOM quality: the newer the project, the emptier its SBOM.Measured on a three-repo test project (spring-petclinic / junit4 / commons-lang):
External parent poms were also dropped even though their exact version is already in the model under
parent_version(e.g.spring-boot-starter-parent4.1.0).Change
Commit 1 — include version-managed and parent-pom dependencies
valid_for_bomgains a coordinate branch: an element carrying maven coordinates and at least one incoming reference becomes a component with a versionless purl (pkg:maven/org.junit.jupiter/junit-jupiter). Versionless is canonical per purl spec and matches at package level — the same trade the existing${...}unresolved-expression case already accepted. The incoming-reference requirement keeps out the husks that version-management redirection leaves behind.extract_versionfalls back toparent_version, so external parents get full purls:pkg:maven/org.springframework.boot/spring-boot-starter-parent@4.1.0.maven_purltreats an empty version like an unresolved expression instead of splicing a trailing@.Commit 2 — harden against stored-model shapes (from adversarial review against real persisted models)
SBOMs are generated on demand from stored models with a multi-month lifetime, so the generator meets shapes the current analyzer no longer produces:
parent_version-only clause (no coordinate requirement) was dropped: every model persisted before analyzers wrote coordinates onto parents has that shape, and admitting it spliced space-bearing element names into generic purls for all existing deployments. On coordinate-carrying models the coordinate branch already admits every parent, verified equivalent.is_maven_coordinateon both attributes: a versionless element with a${}groupId builds no maven purl and has nothing spec-clean to emit.parent_version(two poms naming one parent at different versions collide on one versionless element) yields a versionless purl; the raw value stays disclosed in the componentversionfield instead of asserting a version that exists nowhere.@shape there too.A cross-shape invariant test asserts no emitted purl or bom-ref in any fixture carries a space, a semicolon, or a trailing
@.Backward compatibility
Old generator vs this branch on identical models — strict superset, nothing lost, nothing malformed:
All outputs (single and
--levelmulti) validate against the official CycloneDX 1.7 JSON schema.Companion change
softagram-live's
analyze_maven.pynow writesgroupId/artifactIdonto parent references (and omitsparent_versionwhen the<parent>block has no version, instead of storing the stringNone). Ordering is safe in both directions: this branch handles both model generations, and the old generator ignores the new attributes.Testing
${}groupId.