Skip to content

fix(maven): resolve version ranges in component analysis#536

Open
Strum355 wants to merge 1 commit into
guacsec:mainfrom
Strum355:fix/maven-version-range-resolution
Open

fix(maven): resolve version ranges in component analysis#536
Strum355 wants to merge 1 commit into
guacsec:mainfrom
Strum355:fix/maven-version-range-resolution

Conversation

@Strum355
Copy link
Copy Markdown
Member

@Strum355 Strum355 commented May 21, 2026

Summary

Maven version ranges (e.g. [1.2.17,1.3.0), (1.0,2.0]) in pom.xml dependency versions are preserved verbatim by mvn help:effective-pom. Component analysis uses the effective POM to extract dependency versions, so range expressions end up as the version in the PackageURL (e.g. pkg:maven/log4j/log4j@[1.2.17,1.3.0)). The backend cannot look up vulnerabilities for a range-valued purl, so these dependencies are silently dropped — no editor diagnostics appear for them.

Stack analysis is unaffected because it uses mvn dependency:tree, which resolves ranges to concrete versions before output.

How it works

After extracting dependencies from the effective POM, #resolveVersionRanges checks whether any dependency has a version range (starts with [ or (). If none do, it returns immediately — no performance impact for normal projects.

When ranges are detected, it runs mvn dependency:tree -DoutputType=text -Dscope=compile (without -Dverbose or clean, unlike stack analysis) and parses the direct dependencies (depth 1) from the text output. Each resolved groupId:artifactId → version mapping is collected, and range-valued versions in the dependency list are replaced with the concrete resolved versions before SBOM generation.

If the dependency tree invocation fails for any reason, the method logs (when debug is enabled) and falls back to the original unresolved versions, so the overall flow is never broken.

Changes

  • src/providers/java_maven.js — Add #isVersionRange and #resolveVersionRanges private methods. Call #resolveVersionRanges in #getSbomForComponentAnalysis after filtering ignored deps.
  • src/providers/base_java.js — Harden _getDepth (renamed from #getDepth, now protected) to handle root lines (depth 0) and empty strings, making it safe to call from subclasses on full dependency tree output.
  • test/providers/java_maven.test.js — Add pom_deps_with_version_range test case.
  • test/providers/tst_manifests/maven/pom_deps_with_version_range/ — New fixture with range-valued dependency (log4j [1.2.17,1.3.0)) and concrete dependency (snappy-java 1.1.10.0), verifying both stack and component analysis resolve the range to 1.2.17.

Test plan

  • All existing Maven provider tests pass (stack + component analysis)
  • New version range test passes for both stack and component analysis
  • Manually verified in VS Code with a pom.xml containing [12.0.1,12.0.9) for jetty-server — diagnostics now appear

Ref: fabric8-analytics/fabric8-analytics-vscode-extension#812

🤖 Generated with Claude Code

Summary by Sourcery

Resolve Maven dependency version ranges during component analysis so SBOMs use concrete versions and previously dropped dependencies receive diagnostics.

Bug Fixes:

  • Ensure Maven dependencies declared with version ranges are resolved to concrete versions for component analysis instead of emitting range-valued PackageURLs, preventing them from being silently ignored.

Enhancements:

  • Extend the base Java provider depth calculation to safely handle root and empty lines in Maven dependency tree output, allowing subclasses to reuse it.
  • Add Maven test fixtures and a new test scenario to cover projects using dependency version ranges and verify both stack and component analysis resolve them consistently.

Maven version ranges (e.g. `[1.2.17,1.3.0)`) in pom.xml dependencies
are preserved verbatim by `mvn help:effective-pom`, which is used for
component analysis. The backend cannot look up vulnerabilities for a
range-valued purl like `pkg:maven/log4j/log4j@[1.2.17,1.3.0)`, so
these dependencies were silently dropped from analysis results.

Stack analysis was unaffected because it uses `mvn dependency:tree`
which resolves ranges to concrete versions.

Add `#resolveVersionRanges` to detect range-valued versions in the
effective POM output and resolve them by running
`mvn dependency:tree -DoutputType=text -Dscope=compile`, parsing the
direct dependencies (depth 1) to extract the concrete versions Maven
selects. The resolution is guarded: it only runs when at least one
dependency has a version range, and falls back to the original range
values if the tree invocation fails.

Ref: fabric8-analytics/fabric8-analytics-vscode-extension#812

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 21, 2026

Reviewer's Guide

Adds Maven version range resolution for component analysis by invoking maven-dependency-plugin:tree, and adjusts the shared dependency-tree depth logic plus tests/fixtures to cover version ranges.

Sequence diagram for Maven version range resolution in component analysis

sequenceDiagram
    participant Java_maven
    participant Base_Java
    participant Maven

    Java_maven->>Java_maven: #getSbomForComponentAnalysis(manifestPath, opts)
    Java_maven->>Java_maven: #getDependencies(tmpEffectivePom)
    Java_maven->>Java_maven: #resolveVersionRanges(dependencies, manifestPath, opts)
    alt [dependency has version range]
        Java_maven->>Java_maven: selectToolBinary(manifestPath, opts)
        Java_maven->>Maven: _invokeCommand(mvn, maven-dependency-plugin:tree)
        Maven-->>Java_maven: mvn_deptree_ranges.txt
        Java_maven->>Java_maven: parseDep(line)
        Java_maven->>Base_Java: _getDepth(line)
        Base_Java-->>Java_maven: depth
        Java_maven->>Java_maven: #isVersionRange(dep.version)
        Java_maven->>Java_maven: replace dep.version with resolved version
    else [no version range or failure]
        Java_maven-->>Java_maven: return original dependencies
    end
    Java_maven->>Java_maven: toPurl(groupId, artifactId, version)
    Java_maven-->>Java_maven: sbom
Loading

File-Level Changes

Change Details Files
Resolve Maven version ranges in component analysis dependencies using maven-dependency-plugin:tree output.
  • Introduce private #isVersionRange helper to detect Maven version range syntax on dependency.version.
  • Add #resolveVersionRanges to run mvn dependency:tree, parse depth-1 entries via parseDep, and build a groupId:artifactId→version map.
  • Invoke #resolveVersionRanges in #getSbomForComponentAnalysis after filtering ignored dependencies, replacing range-valued versions with resolved concrete versions when available.
  • Handle mvn invocation failures by logging under TRUSTIFY_DA_DEBUG and falling back to original dependency versions, and clean up temp directories with fs.rmSync.
src/providers/java_maven.js
Relax and expose Maven dependency tree depth calculation for reuse and robustness.
  • Rename #getDepth to protected _getDepth so subclasses (Java_maven) can safely call it.
  • Change _getDepth to return -1 for undefined/empty/whitespace lines and 0 for root lines starting with a word character, avoiding crashes when parsing full dependency tree output.
  • Update parseDependencyTree callers to use _getDepth instead of the previous private method.
src/providers/base_java.js
Add regression coverage and fixtures for component analysis with Maven version ranges.
  • Extend java_maven provider test matrix with pom_deps_with_version_range scenario.
  • Add pom_deps_with_version_range Maven project fixture with a log4j dependency using a version range and a concrete snappy-java dependency.
  • Check that both stack and component analysis resolve the log4j range to a concrete version in the expected SBOMs and dependency tree outputs.
test/providers/java_maven.test.js
test/providers/tst_manifests/maven/pom_deps_with_version_range/effective-pom.xml
test/providers/tst_manifests/maven/pom_deps_with_version_range/pom.xml
test/providers/tst_manifests/maven/pom_deps_with_version_range/component_analysis_expected_sbom.json
test/providers/tst_manifests/maven/pom_deps_with_version_range/mvn_deptree.txt
test/providers/tst_manifests/maven/pom_deps_with_version_range/mvn_deptree_ranges.txt
test/providers/tst_manifests/maven/pom_deps_with_version_range/stack_analysis_expected_sbom.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Collaborator

@ruromero ruromero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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.

2 participants