Skip to content

Maven: report declared dependencies as direct in static analysis - #1768

Closed
spatten wants to merge 2 commits into
masterfrom
maven-static-direct-deps
Closed

Maven: report declared dependencies as direct in static analysis#1768
spatten wants to merge 2 commits into
masterfrom
maven-static-direct-deps

Conversation

@spatten

@spatten spatten commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Overview

Static Maven analysis reported the project itself as the only direct dependency, and everything the project declared as transitive. In a multi-module project the root pom and every submodule were reported as dependencies too. Analysis using mvn was already correct, so this only showed up without mvn on PATH, under --static-only-analysis, and in container scanning.

The dynamic tactics already handle this: Plugin.buildGraph marks the project's own packages direct and shrinkRoots removes them. Static analysis never got the equivalent step — the TODO marking it as unfinished was deleted in #1331, a week before #1339 added shrinkRoots to the dynamic path. This takes the same two steps in getStaticAnalysis.

Both steps are needed. shrinkRoots alone removes only the root pom and would promote the submodules to direct dependencies rather than dropping them. A shrink alone leaves a submodule-filtered graph with no direct dependencies at all, because submodule filtering deletes the root pom's node without rewiring the edges through it — which is a second bug this fixes.

Acceptance criteria

  • A Maven project analyzed without mvn reports the dependencies it declares as direct, and does not report itself.
  • A multi-module project reports no first-party module as a dependency.
  • --only-target 'maven@./:group:module' under static analysis reports that module's dependencies as direct, instead of reporting none.
  • Analysis with mvn present is unchanged.

Testing plan

Given a pom.xml declaring junit:junit:4.13.2 and org.apache.commons:commons-lang3:3.12.0:

  1. fossa analyze -o --static-only-analysis and read sourceUnits[0].Build.Imports.
  2. Before: ["mvn+com.example:demo$1.0"] — the project itself. After: the two declared dependencies.
  3. fossa analyze -o with mvn on PATH gives the same two, before and after.

For the multi-module case, add two submodules each declaring one dependency. Before, Imports is the root pom alone and the graph carries all three first-party coordinates; after, Imports is the three declared dependencies and no first-party coordinate appears.

cabal test unit-tests --test-options='--match "static analysis of a"' covers all of the above against real pom fixtures. All five fail on master with the symptoms described.

Risks

This changes what FOSSA reports for existing projects. Dependencies that were transitive become direct, and the user's own modules stop being reported as dependencies. That is the correction, but it will show as a diff on any project analyzed statically.

The same bug exists in Strategy/Scala.hs:200, where analyzeWithPoms calls Pom.analyze' with no shrink. Scala's intent matches Maven's — its dynamic tactics do call shrinkRoots — so its pom fallback is the odd one out there too. Left for a separate PR: it needs an sbt fixture to verify, and the sbt closure's notion of the project's own packages is not closureSubmodules.

Dynamic submodule filtering looks separately broken on master: on a two-module fixture, --only-target for one module returns every dependency and for the other returns none. Untouched here.

Metrics

No.

References

Reported internally; no ticket.

Checklist

  • I added tests for this PR's change (or explained in the PR description why tests don't make sense).
  • If this PR introduced a user-visible change, I added documentation into docs/.
  • If this PR added docs, I added links as appropriate to the user manual's ToC in docs/README.ms and gave consideration to how discoverable or not my documentation is.
  • If this change is externally visible, I updated Changelog.md. If this PR did not mark a release, I added my changes into an ## Unreleased section at the top.
  • If I made changes to .fossa.yml or fossa-deps.{json.yml}, I updated docs/references/files/*.schema.json AND I have updated example files used by fossa init command. You may also need to update these if you have added/removed new dependency type (e.g. pip) or analysis target type (e.g. poetry).
  • If I made changes to a subcommand's options, I updated docs/references/subcommands/<subcommand>.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QrDtxeRNysKQz4NWXixRzU

spatten and others added 2 commits September 2, 2026 16:59
The pom tactic builds its graph rooted at the project itself, so the
project was the only direct dependency and everything it declared was
reported as transitive. In a multi-module project the root pom and every
submodule were reported as dependencies too.

The dynamic tactics already avoid this: Plugin.buildGraph marks the
project's own packages direct and shrinkRoots removes them. Static
analysis never got the equivalent step, and the TODO marking it as
unfinished was dropped in #1331 a week before #1339 added shrinkRoots to
the dynamic path.

Take the same two steps here. Both are needed: shrinkRoots alone would
remove only the root pom and promote the submodules to direct, and a
shrink alone would leave a submodule-filtered graph with no direct
dependencies at all, because submodule filtering deletes the root pom
node without rewiring the edges through it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrDtxeRNysKQz4NWXixRzU
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrDtxeRNysKQz4NWXixRzU
@spatten

spatten commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Closing, as this is implemented and merged in #1770

@spatten spatten closed this Sep 9, 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.

1 participant