Skip to content

fix(maven) - Fix Maven CLI parser silent BOM corruption on maven-resolver INFO provenance lines - #1859

Merged
bd-samratmuk merged 10 commits into
masterfrom
IDETECT-5287
Sep 1, 2026
Merged

fix(maven) - Fix Maven CLI parser silent BOM corruption on maven-resolver INFO provenance lines#1859
bd-samratmuk merged 10 commits into
masterfrom
IDETECT-5287

Conversation

@bd-samratmuk

Copy link
Copy Markdown
Contributor

What

Fixes silent Maven scan corruption on Maven 3.9.1+ when the local ~/.m2
cache holds artifacts recorded under repository IDs that aren't in the
active settings.xml (typical corporate Artifactory/Nexus mirror shape).

Symptom

Maven-resolver emits an INFO provenance line between the dependency:tree
goal header and the project GAV. The parser mistook it for the header and
produced one of two wrong results — both reported as SUCCESS:

  • BOM under a fabricated project name (few colons in the line)
  • Empty BOM under the correct project name (many colons in the line)

Fix

In MavenCodeLocationPackager:

  1. On an unrecognized header candidate, keep looking on the next line
    instead of tearing down parser state.
  2. Strict validation in textToProject: exactly 4/5 colon-parts and no
    whitespace/slashes/parens/brackets/braces/commas per part.
  3. WARN when a dependency:tree header was seen but no project was
    anchored, so this class of failure surfaces in logs going forward.
  4. Preserved existing detect.maven.excluded.modules behavior.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes Maven CLI parsing so resolver INFO lines are not mistaken for project coordinates.

Changes:

  • Adds strict project-coordinate validation and retry behavior.
  • Adds warnings for unanchored dependency trees.
  • Updates the project snapshot version.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 4 comments.

File Description
detectable/src/main/java/com/blackduck/integration/detectable/detectables/maven/cli/MavenCodeLocationPackager.java Updated as part of this pull request.
build.gradle Updated as part of this pull request.
Suppressed comments (1)

detectable/src/main/java/com/blackduck/integration/detectable/detectables/maven/cli/MavenCodeLocationPackager.java:440

  • The existing direct tests cover valid part counts, but there is no regression test for the new invalid-character filter together with the retry in extractCodeLocations. Add a fixture containing the resolver INFO/provenance line followed by a valid project header and assert the extracted project and dependency graph; that end-to-end case is the behavior this change is intended to protect.
        if (gavParts.length != 4 && gavParts.length != 5) {
            logger.debug(String.format(
                "%s does not look like a project header we can parse (colon-part count: %d)",
                componentText, gavParts.length));
            return null;
        }
        for (String part : gavParts) {
            if (PROJECT_COORDINATE_INVALID_CHARS.matcher(part).find()) {
                logger.debug(String.format(
                    "%s does not look like a project header we can parse (part '%s' contains characters not valid in a Maven coordinate)",
                    componentText, part));
                return null;
            }

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +138 to +143
if (treeHeaderEverSeen && codeLocations.isEmpty()) {
logger.warn(
"Maven dependency:tree output was scanned but no project could be extracted. "
+ "This can occur when Maven or maven-resolver emits unexpected INFO lines "
+ "between the tree header and the project header. "
+ "No components will be reported for this Maven detector run.");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in the latest commit.

Comment on lines +203 to 211
} else {
// (3) Candidate line was not a valid project GAV. Do NOT disarm —
// leave parsingProjectSection = true so the next non-noise line
// is retried as a header candidate.
logger.debug(String.format(
"Line following dependency:tree header did not parse as a project GAV; will retry with the next non-noise line. Line: %s",
line));
// Intentionally leave parsingProjectSection, dependencyParentStack, level untouched.
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The terminator branch isn't needed. For it to fire, a module would have to emit a dependency:tree header with no project GAV before the terminator, which I believe Maven doesn't do today in any version.

Comment on lines +419 to +428
String[] gavParts = componentText.split(":");

// Strict project-header validation. A valid project GAV is exactly
// G:A:type:V (4 parts) or G:A:type:classifier:V (5 parts). isGav()
// only enforces "at least 4 non-blank parts", which is too loose —
// log prose that happens to embed a coordinate and colon-heavy URLs
// (e.g. maven-resolver provenance INFO lines listing repository URLs
// with explicit :PORTs) can otherwise slip through and be
// misidentified as the project header.
if (gavParts.length != 4 && gavParts.length != 5) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in the latest commit.

Comment on lines +194 to 202
} else if (null != mavenProject) {
// (2) Excluded module: valid GAV, but filtered out. Disarm so
// subsequent tree body lines are skipped by shouldSkipLine's
// !parsingProjectSection gate.
logger.trace(String.format("Project %s excluded by modules filter", mavenProject.getProjectName()));
currentMavenProject = null;
dependencyParentStack.clear();
parsingProjectSection = false;
level = 0;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in the latest commit.

@bd-spratikbharti

Copy link
Copy Markdown
Collaborator

Looks good. Could we also add a test case covering this change to prevent regressions?

@bd-samratmuk

Copy link
Copy Markdown
Contributor Author

@bd-spratikbharti added in the latest commit

@bd-samratmuk
bd-samratmuk merged commit 298a8d7 into master Sep 1, 2026
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.

4 participants