Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(java): add empty versions if pom.xml dependency versions can't be detected #7520

Merged
11 changes: 11 additions & 0 deletions docs/docs/coverage/language/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ The vulnerability database will be downloaded anyway.
!!! Warning
Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed.

### empty dependency version
There are cases when Trivy cannot determine the version of dependencies:

- Unable to determine the version from the parent because the parent is not reachable;
- The dependency uses a [hard requirement][version-requirement] with more than one version.

In these cases, Trivy uses an empty version for the dependency.

!!! Warning
Trivy doesn't detect child dependencies for dependencies without a version.

### maven-invoker-plugin
Typically, the integration tests directory (`**/[src|target]/it/*/pom.xml`) of [maven-invoker-plugin][maven-invoker-plugin] doesn't contain actual `pom.xml` files and should be skipped to avoid noise.
Expand Down Expand Up @@ -120,3 +130,4 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
[sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock
[detection-priority]: ../../scanner/vulnerability.md#detection-priority
[version-requirement]: https://maven.apache.org/pom.html#dependency-version-requirement-specification
21 changes: 19 additions & 2 deletions pkg/dependency/parser/java/pom/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@ import (
"regexp"
"slices"
"strings"
"sync"

"github.com/samber/lo"

ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/version/doc"
)

var (
varRegexp = regexp.MustCompile(`\${(\S+?)}`)
varRegexp = regexp.MustCompile(`\${(\S+?)}`)
emptyVersionWarn = sync.OnceFunc(func() {
log.WithPrefix("pom").Warn("Dependency version cannot be determined. Child dependencies will not be found.",
// e.g. https://aquasecurity.github.io/trivy/latest/docs/coverage/language/java/#empty-dependency-version
log.String("details", doc.URL("/docs/coverage/language/java/", "empty-dependency-version")))
})
)

type artifact struct {
Expand Down Expand Up @@ -42,7 +49,17 @@ func newArtifact(groupID, artifactID, version string, licenses []string, props m
}

func (a artifact) IsEmpty() bool {
return a.GroupID == "" || a.ArtifactID == "" || a.Version.String() == ""
if a.GroupID == "" || a.ArtifactID == "" {
return true
}
if a.Version.String() == "" {
emptyVersionWarn()
Copy link
Collaborator

Choose a reason for hiding this comment

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

We may want to show warnings with group id and artifact id. Can it be overwhelming?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I decided to show the warning once to avoid spam in logs
do you think we should still show all dependencies without the version?

Copy link
Collaborator

Choose a reason for hiding this comment

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

One warning without dependency details and other debug logs with group id and artifact id may be a good compromise.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated in 9424f13

log.WithPrefix("pom").Debug("Dependency version cannot be determined.",
log.String("GroupID", a.GroupID),
log.String("ArtifactID", a.ArtifactID),
)
}
return false
}

func (a artifact) Equal(o artifact) bool {
Expand Down
8 changes: 8 additions & 0 deletions pkg/dependency/parser/java/pom/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,14 @@ func (p *Parser) resolve(art artifact, rootDepManagement []pomDependency) (analy
return *result, nil
}

// We can't resolve a dependency without a version.
// So let's just keep this dependency.
if art.Version.String() == "" {
return analysisResult{
artifact: art,
}, nil
}

p.logger.Debug("Resolving...", log.String("group_id", art.GroupID),
log.String("artifact_id", art.ArtifactID), log.String("version", art.Version.String()))
pomContent, err := p.tryRepository(art.GroupID, art.ArtifactID, art.Version.String())
Expand Down
35 changes: 35 additions & 0 deletions pkg/dependency/parser/java/pom/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,17 @@ func TestPom_Parse(t *testing.T) {
Licenses: []string{"Apache 2.0"},
Relationship: ftypes.RelationshipRoot,
},
{
ID: "org.example:example-api",
Name: "org.example:example-api",
Relationship: ftypes.RelationshipDirect,
Locations: []ftypes.Location{
{
StartLine: 28,
EndLine: 32,
},
},
},
},
},
{
Expand Down Expand Up @@ -1499,6 +1510,30 @@ func TestPom_Parse(t *testing.T) {
},
},
},
{
name: "dependency without version",
inputFile: filepath.Join("testdata", "dep-without-version", "pom.xml"),
local: true,
want: []ftypes.Package{
{
ID: "com.example:dep-without-version:1.0.0",
Name: "com.example:dep-without-version",
Version: "1.0.0",
Relationship: ftypes.RelationshipRoot,
},
{
ID: "org.example:example-api",
Name: "org.example:example-api",
Relationship: ftypes.RelationshipDirect,
Locations: ftypes.Locations{
{
StartLine: 19,
EndLine: 22,
},
},
},
},
},
// [INFO] com.example:root-depManagement-in-parent:jar:1.0.0
// [INFO] \- org.example:example-dependency:jar:2.0.0:compile
// [INFO] \- org.example:example-api:jar:1.0.1:compile
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<name>no-parent</name>
<description>Parent not found</description>

<parent>
<groupId>com.example</groupId>
<artifactId>wrong-parent</artifactId>
<version>1.0.0</version>
</parent>

<groupId>com.example</groupId>
<artifactId>dep-without-version</artifactId>
<version>1.0.0</version>

<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>example-api</artifactId>
</dependency>
</dependencies>
</project>
11 changes: 11 additions & 0 deletions pkg/fanal/analyzer/language/java/pom/pom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
Licenses: []string{"Apache-2.0"},
Relationship: types.RelationshipRoot,
},
{
ID: "org.example:example-api",
Name: "org.example:example-api",
Relationship: types.RelationshipDirect,
Locations: []types.Location{
{
StartLine: 21,
EndLine: 25,
},
},
},
},
},
},
Expand Down