fix(maven) - Fix Maven CLI parser silent BOM corruption on maven-resolver INFO provenance lines - #1859
Conversation
There was a problem hiding this comment.
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.
| 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."); |
There was a problem hiding this comment.
fixed in the latest commit.
| } 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. | ||
| } |
There was a problem hiding this comment.
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.
| 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) { |
There was a problem hiding this comment.
fixed in the latest commit.
| } 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; |
There was a problem hiding this comment.
fixed in the latest commit.
|
Looks good. Could we also add a test case covering this change to prevent regressions? |
|
@bd-spratikbharti added in the latest commit |
What
Fixes silent Maven scan corruption on Maven 3.9.1+ when the local
~/.m2cache 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:treegoal header and the project GAV. The parser mistook it for the header and
produced one of two wrong results — both reported as SUCCESS:
Fix
In
MavenCodeLocationPackager:instead of tearing down parser state.
textToProject: exactly 4/5 colon-parts and nowhitespace/slashes/parens/brackets/braces/commas per part.
dependency:treeheader was seen but no project wasanchored, so this class of failure surfaces in logs going forward.
detect.maven.excluded.modulesbehavior.