mirror of
https://github.com/aquasecurity/trivy.git
synced 2026-01-31 13:53:14 +08:00
fix(java): add hash of GAV+root pom file path for pkgID for packages from pom.xml files (#9880)
Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
This commit is contained in:
@@ -57,7 +57,7 @@
|
|||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:PkgID",
|
"name": "aquasecurity:trivy:PkgID",
|
||||||
"value": "com.example:log4shell:1.0-SNAPSHOT"
|
"value": "com.example:log4shell:1.0-SNAPSHOT::b21b31f8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:PkgType",
|
"name": "aquasecurity:trivy:PkgType",
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:PkgID",
|
"name": "aquasecurity:trivy:PkgID",
|
||||||
"value": "com.fasterxml.jackson.core:jackson-databind:2.9.1"
|
"value": "com.fasterxml.jackson.core:jackson-databind:2.9.1::6a9e9547"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:PkgType",
|
"name": "aquasecurity:trivy:PkgType",
|
||||||
|
|||||||
12
integration/testdata/pom.json.golden
vendored
12
integration/testdata/pom.json.golden
vendored
@@ -12,11 +12,11 @@
|
|||||||
"Vulnerabilities": [
|
"Vulnerabilities": [
|
||||||
{
|
{
|
||||||
"VulnerabilityID": "CVE-2020-9548",
|
"VulnerabilityID": "CVE-2020-9548",
|
||||||
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
|
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1::6a9e9547",
|
||||||
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
|
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
|
||||||
"PkgIdentifier": {
|
"PkgIdentifier": {
|
||||||
"PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
|
"PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
|
||||||
"UID": "9c69fdeffb7ee6d4"
|
"UID": "375da330ae4fb009"
|
||||||
},
|
},
|
||||||
"InstalledVersion": "2.9.1",
|
"InstalledVersion": "2.9.1",
|
||||||
"FixedVersion": "2.9.10.4",
|
"FixedVersion": "2.9.10.4",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"Name": "GitHub Security Advisory Maven",
|
"Name": "GitHub Security Advisory Maven",
|
||||||
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven"
|
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven"
|
||||||
},
|
},
|
||||||
"Fingerprint": "sha256:68e4f9ccb3a897341f76048401e88a22f2d9251a88eef44abdf7b9c2af70f2e4",
|
"Fingerprint": "sha256:e8090470bc38669d0a9a73e684105597938cc3890b6e77f6cfda6e73b98c2f08",
|
||||||
"Title": "jackson-databind: Serialization gadgets in anteros-core",
|
"Title": "jackson-databind: Serialization gadgets in anteros-core",
|
||||||
"Description": "FasterXML jackson-databind 2.x before 2.9.10.4 mishandles the interaction between serialization gadgets and typing, related to br.com.anteros.dbcp.AnterosDBCPConfig (aka anteros-core).",
|
"Description": "FasterXML jackson-databind 2.x before 2.9.10.4 mishandles the interaction between serialization gadgets and typing, related to br.com.anteros.dbcp.AnterosDBCPConfig (aka anteros-core).",
|
||||||
"Severity": "CRITICAL",
|
"Severity": "CRITICAL",
|
||||||
@@ -78,11 +78,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"VulnerabilityID": "CVE-2021-20190",
|
"VulnerabilityID": "CVE-2021-20190",
|
||||||
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
|
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1::6a9e9547",
|
||||||
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
|
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
|
||||||
"PkgIdentifier": {
|
"PkgIdentifier": {
|
||||||
"PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
|
"PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1",
|
||||||
"UID": "9c69fdeffb7ee6d4"
|
"UID": "375da330ae4fb009"
|
||||||
},
|
},
|
||||||
"InstalledVersion": "2.9.1",
|
"InstalledVersion": "2.9.1",
|
||||||
"FixedVersion": "2.9.10.7",
|
"FixedVersion": "2.9.10.7",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
"Name": "GitLab Advisory Database Community",
|
"Name": "GitLab Advisory Database Community",
|
||||||
"URL": "https://gitlab.com/gitlab-org/advisories-community"
|
"URL": "https://gitlab.com/gitlab-org/advisories-community"
|
||||||
},
|
},
|
||||||
"Fingerprint": "sha256:b7e077da6366be5eebc967119b377ac75bf9c1f0b0fb63f07ee1cfdec931506e",
|
"Fingerprint": "sha256:bceb5c9900547204285dff59a40c785acbcffbece6b4bc9fc31055352809ba0a",
|
||||||
"Title": "jackson-databind: mishandles the interaction between serialization gadgets and typing, related to javax.swing",
|
"Title": "jackson-databind: mishandles the interaction between serialization gadgets and typing, related to javax.swing",
|
||||||
"Description": "A flaw was found in jackson-databind before 2.9.10.7. FasterXML mishandles the interaction between serialization gadgets and typing. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.",
|
"Description": "A flaw was found in jackson-databind before 2.9.10.7. FasterXML mishandles the interaction between serialization gadgets and typing. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.",
|
||||||
"Severity": "HIGH",
|
"Severity": "HIGH",
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ type artifact struct {
|
|||||||
Relationship ftypes.Relationship
|
Relationship ftypes.Relationship
|
||||||
|
|
||||||
Locations ftypes.Locations
|
Locations ftypes.Locations
|
||||||
|
|
||||||
|
// For correctly calculation package ID (hash),
|
||||||
|
// We need to store the file paths for root or module artifacts.
|
||||||
|
// For other artifacts, it will be empty.
|
||||||
|
RootFilePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArtifact(groupID, artifactID, version string, licenses []string, props map[string]string) artifact {
|
func newArtifact(groupID, artifactID, version string, licenses []string, props map[string]string) artifact {
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ func (c pomCache) get(art artifact) *analysisResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c pomCache) key(art artifact) string {
|
func (c pomCache) key(art artifact) string {
|
||||||
return fmt.Sprintf("%s:%s", art.Name(), art.Version)
|
return fmt.Sprintf("%s:%s:%s", art.Name(), art.Version, art.RootFilePath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/mitchellh/hashstructure/v2"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"golang.org/x/net/html/charset"
|
"golang.org/x/net/html/charset"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@@ -124,7 +126,9 @@ func (p *Parser) Parse(ctx context.Context, r xio.ReadSeekerAt) ([]ftypes.Packag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Analyze root POM
|
// Analyze root POM
|
||||||
result, err := p.analyze(ctx, root, analysisOptions{})
|
result, err := p.analyze(ctx, root, analysisOptions{
|
||||||
|
rootFilePath: p.rootPath,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("analyze error (%s): %w", p.rootPath, err)
|
return nil, nil, xerrors.Errorf("analyze error (%s): %w", p.rootPath, err)
|
||||||
}
|
}
|
||||||
@@ -134,12 +138,17 @@ func (p *Parser) Parse(ctx context.Context, r xio.ReadSeekerAt) ([]ftypes.Packag
|
|||||||
|
|
||||||
rootArt := root.artifact()
|
rootArt := root.artifact()
|
||||||
rootArt.Relationship = ftypes.RelationshipRoot
|
rootArt.Relationship = ftypes.RelationshipRoot
|
||||||
|
rootArt.RootFilePath = p.rootPath
|
||||||
|
|
||||||
return p.parseRoot(ctx, rootArt, set.New[string]())
|
return p.parseRoot(ctx, rootArt, set.New[string]())
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: gocyclo
|
// nolint: gocyclo
|
||||||
func (p *Parser) parseRoot(ctx context.Context, root artifact, uniqModules set.Set[string]) ([]ftypes.Package, []ftypes.Dependency, error) {
|
func (p *Parser) parseRoot(ctx context.Context, root artifact, uniqModules set.Set[string]) ([]ftypes.Package, []ftypes.Dependency, error) {
|
||||||
|
if root.RootFilePath == "" {
|
||||||
|
return nil, nil, xerrors.New("root file path is required for package ID generation")
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare a queue for dependencies
|
// Prepare a queue for dependencies
|
||||||
queue := newArtifactQueue()
|
queue := newArtifactQueue()
|
||||||
|
|
||||||
@@ -162,10 +171,11 @@ func (p *Parser) parseRoot(ctx context.Context, root artifact, uniqModules set.S
|
|||||||
// Modules should be handled separately so that they can have independent dependencies.
|
// Modules should be handled separately so that they can have independent dependencies.
|
||||||
// It means multi-module allows for duplicate dependencies.
|
// It means multi-module allows for duplicate dependencies.
|
||||||
if art.Module {
|
if art.Module {
|
||||||
if uniqModules.Contains(art.String()) {
|
id := packageID(art.Name(), art.Version.String(), art.RootFilePath)
|
||||||
|
if uniqModules.Contains(id) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
uniqModules.Append(art.String())
|
uniqModules.Append(id)
|
||||||
|
|
||||||
modulePkgs, moduleDeps, err := p.parseRoot(ctx, art, uniqModules)
|
modulePkgs, moduleDeps, err := p.parseRoot(ctx, art, uniqModules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -246,14 +256,14 @@ func (p *Parser) parseRoot(ctx context.Context, root artifact, uniqModules set.S
|
|||||||
dependsOn := xslices.Map(result.dependencies, func(a artifact) string {
|
dependsOn := xslices.Map(result.dependencies, func(a artifact) string {
|
||||||
return a.Name()
|
return a.Name()
|
||||||
})
|
})
|
||||||
uniqDeps[packageID(art.Name(), art.Version.String())] = dependsOn
|
uniqDeps[packageID(art.Name(), art.Version.String(), root.RootFilePath)] = dependsOn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to []ftypes.Package and []ftypes.Dependency
|
// Convert to []ftypes.Package and []ftypes.Dependency
|
||||||
for name, art := range uniqArtifacts {
|
for name, art := range uniqArtifacts {
|
||||||
pkg := ftypes.Package{
|
pkg := ftypes.Package{
|
||||||
ID: packageID(name, art.Version.String()),
|
ID: packageID(name, art.Version.String(), root.RootFilePath),
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: art.Version.String(),
|
Version: art.Version.String(),
|
||||||
Licenses: art.Licenses,
|
Licenses: art.Licenses,
|
||||||
@@ -265,7 +275,7 @@ func (p *Parser) parseRoot(ctx context.Context, root artifact, uniqModules set.S
|
|||||||
// Convert dependency names into dependency IDs
|
// Convert dependency names into dependency IDs
|
||||||
dependsOn := lo.FilterMap(uniqDeps[pkg.ID], func(dependOnName string, _ int) (string, bool) {
|
dependsOn := lo.FilterMap(uniqDeps[pkg.ID], func(dependOnName string, _ int) (string, bool) {
|
||||||
ver := depVersion(dependOnName, uniqArtifacts)
|
ver := depVersion(dependOnName, uniqArtifacts)
|
||||||
return packageID(dependOnName, ver), ver != ""
|
return packageID(dependOnName, ver, root.RootFilePath), ver != ""
|
||||||
})
|
})
|
||||||
|
|
||||||
// `mvn` shows modules separately from the root package and does not show module nesting.
|
// `mvn` shows modules separately from the root package and does not show module nesting.
|
||||||
@@ -304,13 +314,16 @@ func (p *Parser) parseModule(ctx context.Context, currentPath, relativePath stri
|
|||||||
return artifact{}, xerrors.Errorf("unable to open the relative path: %w", err)
|
return artifact{}, xerrors.Errorf("unable to open the relative path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := p.analyze(ctx, module, analysisOptions{})
|
result, err := p.analyze(ctx, module, analysisOptions{
|
||||||
|
rootFilePath: module.filePath,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return artifact{}, xerrors.Errorf("analyze error: %w", err)
|
return artifact{}, xerrors.Errorf("analyze error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleArtifact := module.artifact()
|
moduleArtifact := module.artifact()
|
||||||
moduleArtifact.Module = true
|
moduleArtifact.Module = true
|
||||||
|
moduleArtifact.RootFilePath = module.filePath
|
||||||
moduleArtifact.Relationship = ftypes.RelationshipWorkspace
|
moduleArtifact.Relationship = ftypes.RelationshipWorkspace
|
||||||
|
|
||||||
p.cache.put(moduleArtifact, result)
|
p.cache.put(moduleArtifact, result)
|
||||||
@@ -344,6 +357,7 @@ func (p *Parser) resolve(ctx context.Context, art artifact, rootDepManagement []
|
|||||||
result, err := p.analyze(ctx, pomContent, analysisOptions{
|
result, err := p.analyze(ctx, pomContent, analysisOptions{
|
||||||
exclusions: art.Exclusions,
|
exclusions: art.Exclusions,
|
||||||
depManagement: rootDepManagement,
|
depManagement: rootDepManagement,
|
||||||
|
rootFilePath: art.RootFilePath,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return analysisResult{}, xerrors.Errorf("analyze error: %w", err)
|
return analysisResult{}, xerrors.Errorf("analyze error: %w", err)
|
||||||
@@ -365,6 +379,7 @@ type analysisResult struct {
|
|||||||
type analysisOptions struct {
|
type analysisOptions struct {
|
||||||
exclusions set.Set[string]
|
exclusions set.Set[string]
|
||||||
depManagement []pomDependency // from the root POM
|
depManagement []pomDependency // from the root POM
|
||||||
|
rootFilePath string // File path of the root POM or module POM
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) analyze(ctx context.Context, pom *pom, opts analysisOptions) (analysisResult, error) {
|
func (p *Parser) analyze(ctx context.Context, pom *pom, opts analysisOptions) (analysisResult, error) {
|
||||||
@@ -394,9 +409,12 @@ func (p *Parser) analyze(ctx context.Context, pom *pom, opts analysisOptions) (a
|
|||||||
}
|
}
|
||||||
deps = p.filterDependencies(deps, opts.exclusions)
|
deps = p.filterDependencies(deps, opts.exclusions)
|
||||||
|
|
||||||
|
art := pom.artifact()
|
||||||
|
art.RootFilePath = opts.rootFilePath
|
||||||
|
|
||||||
return analysisResult{
|
return analysisResult{
|
||||||
filePath: pom.filePath,
|
filePath: pom.filePath,
|
||||||
artifact: pom.artifact(),
|
artifact: art,
|
||||||
dependencies: deps,
|
dependencies: deps,
|
||||||
dependencyManagement: depManagement,
|
dependencyManagement: depManagement,
|
||||||
properties: props,
|
properties: props,
|
||||||
@@ -876,8 +894,22 @@ func parseMavenMetadata(r io.Reader) (*Metadata, error) {
|
|||||||
return parsed, nil
|
return parsed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func packageID(name, version string) string {
|
func packageID(name, version, pomFilePath string) string {
|
||||||
return dependency.ID(ftypes.Pom, name, version)
|
gav := dependency.ID(ftypes.Pom, name, version)
|
||||||
|
v := map[string]any{
|
||||||
|
"gav": gav,
|
||||||
|
"path": filepath.ToSlash(pomFilePath),
|
||||||
|
}
|
||||||
|
h, err := hashstructure.Hash(v, hashstructure.FormatV2, &hashstructure.HashOptions{
|
||||||
|
ZeroNil: true,
|
||||||
|
IgnoreZeroValue: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Failed to calculate hash", log.Err(err))
|
||||||
|
return gav // fallback to GAV only
|
||||||
|
}
|
||||||
|
// Append 8-character hash suffix
|
||||||
|
return fmt.Sprintf("%s::%s", gav, strconv.FormatUint(h, 16)[:8])
|
||||||
}
|
}
|
||||||
|
|
||||||
// cf. https://github.com/apache/maven/blob/259404701402230299fe05ee889ecdf1c9dae816/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java#L482-L486
|
// cf. https://github.com/apache/maven/blob/259404701402230299fe05ee889ecdf1c9dae816/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java#L482-L486
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -285,6 +285,7 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact {
|
|||||||
Exclusions: exclusions,
|
Exclusions: exclusions,
|
||||||
Locations: locations,
|
Locations: locations,
|
||||||
Relationship: ftypes.RelationshipIndirect, // default
|
Relationship: ftypes.RelationshipIndirect, // default
|
||||||
|
RootFilePath: opts.rootFilePath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>module1</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-api</artifactId>
|
||||||
|
<version>1.7.30</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-dependency</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>module2</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-api</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-dependency</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>root</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>module1</module>
|
||||||
|
<module>module2</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/module1/pom.xml
vendored
Normal file
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/module1/pom.xml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>module1</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-api</artifactId>
|
||||||
|
<version>1.7.30</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/module2/pom.xml
vendored
Normal file
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/module2/pom.xml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>module2</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-api</artifactId>
|
||||||
|
<version>1.7.30</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/pom.xml
vendored
Normal file
16
pkg/dependency/parser/java/pom/testdata/multiple-modules-with-deps-with-same-gav/pom.xml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>root</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>module1</module>
|
||||||
|
<module>module2</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-dependency</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>Example API Dependency</name>
|
||||||
|
<description>The example API</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>example-api</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -30,17 +30,17 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
|||||||
FilePath: "testdata/happy/pom.xml",
|
FilePath: "testdata/happy/pom.xml",
|
||||||
Packages: types.Packages{
|
Packages: types.Packages{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:1.0.0",
|
ID: "com.example:example:1.0.0::775be61e",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Licenses: []string{"Apache 2.0"},
|
Licenses: []string{"Apache 2.0"},
|
||||||
Relationship: types.RelationshipRoot,
|
Relationship: types.RelationshipRoot,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"com.example:example-api:2.0.0",
|
"com.example:example-api:2.0.0::3f5226c1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "com.example:example-api:2.0.0",
|
ID: "com.example:example-api:2.0.0::3f5226c1",
|
||||||
Name: "com.example:example-api",
|
Name: "com.example:example-api",
|
||||||
Version: "2.0.0",
|
Version: "2.0.0",
|
||||||
Relationship: types.RelationshipDirect,
|
Relationship: types.RelationshipDirect,
|
||||||
@@ -67,17 +67,17 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
|||||||
FilePath: "pom.xml",
|
FilePath: "pom.xml",
|
||||||
Packages: types.Packages{
|
Packages: types.Packages{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:1.0.0",
|
ID: "com.example:example:1.0.0::775be61e",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Relationship: types.RelationshipRoot,
|
Relationship: types.RelationshipRoot,
|
||||||
Licenses: []string{"Apache 2.0"},
|
Licenses: []string{"Apache 2.0"},
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"com.example:example-api:2.0.0",
|
"com.example:example-api:2.0.0::3f5226c1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "com.example:example-api:2.0.0",
|
ID: "com.example:example-api:2.0.0::3f5226c1",
|
||||||
Name: "com.example:example-api",
|
Name: "com.example:example-api",
|
||||||
Version: "2.0.0",
|
Version: "2.0.0",
|
||||||
Relationship: types.RelationshipDirect,
|
Relationship: types.RelationshipDirect,
|
||||||
@@ -103,18 +103,18 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
|||||||
FilePath: "testdata/mark-as-dev/src/it/example/pom.xml",
|
FilePath: "testdata/mark-as-dev/src/it/example/pom.xml",
|
||||||
Packages: types.Packages{
|
Packages: types.Packages{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:1.0.0",
|
ID: "com.example:example:1.0.0::c6140fc9",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Licenses: []string{"Apache 2.0"},
|
Licenses: []string{"Apache 2.0"},
|
||||||
Relationship: types.RelationshipRoot,
|
Relationship: types.RelationshipRoot,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"com.example:example-api:@example.version@",
|
"com.example:example-api:@example.version@::ea8c6bb9",
|
||||||
},
|
},
|
||||||
Dev: true,
|
Dev: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "com.example:example-api:@example.version@",
|
ID: "com.example:example-api:@example.version@::ea8c6bb9",
|
||||||
Name: "com.example:example-api",
|
Name: "com.example:example-api",
|
||||||
Version: "@example.version@",
|
Version: "@example.version@",
|
||||||
Relationship: types.RelationshipDirect,
|
Relationship: types.RelationshipDirect,
|
||||||
@@ -141,14 +141,14 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
|||||||
FilePath: "testdata/requirements/pom.xml",
|
FilePath: "testdata/requirements/pom.xml",
|
||||||
Packages: types.Packages{
|
Packages: types.Packages{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:2.0.0",
|
ID: "com.example:example:2.0.0::729d323a",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "2.0.0",
|
Version: "2.0.0",
|
||||||
Licenses: []string{"Apache 2.0"},
|
Licenses: []string{"Apache 2.0"},
|
||||||
Relationship: types.RelationshipRoot,
|
Relationship: types.RelationshipRoot,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "org.example:example-api",
|
ID: "org.example:example-api::fc45c739",
|
||||||
Name: "org.example:example-api",
|
Name: "org.example:example-api",
|
||||||
Relationship: types.RelationshipDirect,
|
Relationship: types.RelationshipDirect,
|
||||||
Locations: []types.Location{
|
Locations: []types.Location{
|
||||||
|
|||||||
@@ -497,6 +497,156 @@ Suppressed Vulnerabilities (Total: 1)
|
|||||||
├─────────┼───────────────┼──────────┼─────────┼─────────────────┼───────────────────┤
|
├─────────┼───────────────┼──────────┼─────────┼─────────────────┼───────────────────┤
|
||||||
│ foo │ CVE-2020-0001 │ MEDIUM │ ignored │ Not exploitable │ .trivyignore.yaml │
|
│ foo │ CVE-2020-0001 │ MEDIUM │ ignored │ Not exploitable │ .trivyignore.yaml │
|
||||||
└─────────┴───────────────┴──────────┴─────────┴─────────────────┴───────────────────┘
|
└─────────┴───────────────┴──────────┴─────────┴─────────────────┴───────────────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with vulnerability origin graph for pom.xml file with modules",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "pom.xml",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Type: "pom",
|
||||||
|
Packages: []ftypes.Package{
|
||||||
|
{
|
||||||
|
ID: "com.example:root:0.0.1::abcdef1234567001",
|
||||||
|
Name: "com.example:root",
|
||||||
|
Version: "0.0.1",
|
||||||
|
Relationship: ftypes.RelationshipRoot,
|
||||||
|
DependsOn: []string{
|
||||||
|
"org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567003",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "com.example:module1:1.0.0::abcdef1234567002",
|
||||||
|
Name: "com.example:module1",
|
||||||
|
Version: "1.0.0",
|
||||||
|
Relationship: ftypes.RelationshipWorkspace,
|
||||||
|
DependsOn: []string{
|
||||||
|
"org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567003",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567003",
|
||||||
|
Name: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Version: "2.6.1",
|
||||||
|
Relationship: ftypes.RelationshipDirect,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "com.example:module2:2.0.0::abcdef1234567004",
|
||||||
|
Name: "com.example:module2",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Relationship: ftypes.RelationshipRoot,
|
||||||
|
DependsOn: []string{
|
||||||
|
"com.example:example-dependency:2.0.0::abcdef1234567005",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "com.example:example-dependency:2.0.0::abcdef1234567005",
|
||||||
|
Name: "com.example:example-dependency",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Relationship: ftypes.RelationshipDirect,
|
||||||
|
DependsOn: []string{
|
||||||
|
"org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567006",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567006",
|
||||||
|
Name: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Version: "2.6.1",
|
||||||
|
Relationship: ftypes.RelationshipIndirect,
|
||||||
|
},
|
||||||
|
// Root pkg
|
||||||
|
{
|
||||||
|
ID: "com.example:example-nested-dependency:2.0.0::abcdef1234567007",
|
||||||
|
Name: "com.example:example-nested-dependency",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Relationship: ftypes.RelationshipDirect,
|
||||||
|
DependsOn: []string{
|
||||||
|
"com.example:example-dependency:2.0.0::abcdef1234567008",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "com.example:example-dependency:2.0.0::abcdef1234567008",
|
||||||
|
Name: "com.example:example-dependency",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Relationship: ftypes.RelationshipIndirect,
|
||||||
|
DependsOn: []string{
|
||||||
|
"org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567009",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567009",
|
||||||
|
Name: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Version: "2.6.1",
|
||||||
|
Relationship: ftypes.RelationshipIndirect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2017-5645",
|
||||||
|
PkgID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567003",
|
||||||
|
PkgName: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
InstalledVersion: "2.6.1",
|
||||||
|
FixedVersion: "2.8.2",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2017-5645",
|
||||||
|
PkgID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567006",
|
||||||
|
PkgName: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
InstalledVersion: "2.6.1",
|
||||||
|
FixedVersion: "2.8.2",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2017-5645",
|
||||||
|
PkgID: "org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567009",
|
||||||
|
PkgName: "org.apache.logging.log4j:log4j-core",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
InstalledVersion: "2.6.1",
|
||||||
|
FixedVersion: "2.8.2",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
pom.xml (pom)
|
||||||
|
=============
|
||||||
|
Total: 3 (MEDIUM: 0, HIGH: 3)
|
||||||
|
|
||||||
|
┌─────────────────────────────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────────────────────────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
||||||
|
│ org.apache.logging.log4j:log4j-core │ CVE-2017-5645 │ HIGH │ fixed │ 2.6.1 │ 2.8.2 │ foobar │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
└─────────────────────────────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
||||||
|
|
||||||
|
Dependency Origin Tree (Reversed)
|
||||||
|
=================================
|
||||||
|
pom.xml
|
||||||
|
├── org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567003, (MEDIUM: 0, HIGH: 1)
|
||||||
|
├── org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567006, (MEDIUM: 0, HIGH: 1)
|
||||||
|
│ └── com.example:example-dependency:2.0.0::abcdef1234567005
|
||||||
|
└── org.apache.logging.log4j:log4j-core:2.6.1::abcdef1234567009, (MEDIUM: 0, HIGH: 1)
|
||||||
|
└── ...(omitted)...
|
||||||
|
└── com.example:example-nested-dependency:2.0.0::abcdef1234567007
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is a duplicate vulnerability
|
// Check if there is a duplicate vulnerability
|
||||||
key := fmt.Sprintf("%s/%s/%s/%s", vuln.VulnerabilityID, vuln.PkgName, vuln.InstalledVersion, vuln.PkgPath)
|
key := fmt.Sprintf("%s/%s/%s/%s/%s", vuln.VulnerabilityID, vuln.PkgID, vuln.PkgName, vuln.InstalledVersion, vuln.PkgPath)
|
||||||
if old, ok := uniqVulns[key]; ok && !shouldOverwrite(old, vuln) {
|
if old, ok := uniqVulns[key]; ok && !shouldOverwrite(old, vuln) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1118,6 +1118,102 @@ func TestFilter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with duplicates and different package IDs",
|
||||||
|
args: args{
|
||||||
|
report: types.Report{
|
||||||
|
Results: types.Results{
|
||||||
|
{
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0001",
|
||||||
|
PkgID: "foo:1.2.3::abcdef1234567001",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0001",
|
||||||
|
PkgID: "foo:1.2.3::abcdef1234567002",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0002",
|
||||||
|
PkgID: "bar@1.2.3",
|
||||||
|
PkgName: "bar",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0002",
|
||||||
|
PkgID: "bar@1.2.3",
|
||||||
|
PkgName: "bar",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
severities: []dbTypes.Severity{
|
||||||
|
dbTypes.SeverityCritical,
|
||||||
|
dbTypes.SeverityHigh,
|
||||||
|
dbTypes.SeverityUnknown,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: types.Report{
|
||||||
|
Results: types.Results{
|
||||||
|
{
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0002",
|
||||||
|
PkgID: "bar@1.2.3",
|
||||||
|
PkgName: "bar",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0001",
|
||||||
|
PkgID: "foo:1.2.3::abcdef1234567001",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2019-0001",
|
||||||
|
PkgID: "foo:1.2.3::abcdef1234567002",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -1247,7 +1247,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Class: types.ClassLangPkg,
|
Class: types.ClassLangPkg,
|
||||||
Packages: []ftypes.Package{
|
Packages: []ftypes.Package{
|
||||||
{
|
{
|
||||||
ID: "com.example:root:1.0.0",
|
ID: "com.example:root:1.0.0::abcdef1234567001",
|
||||||
Name: "com.example:root",
|
Name: "com.example:root",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1261,12 +1261,12 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Relationship: ftypes.RelationshipRoot,
|
Relationship: ftypes.RelationshipRoot,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"com.example:module1:1.0.0",
|
"com.example:module1:1.0.0::abcdef1234567002",
|
||||||
"com.example:module2:2.0.0",
|
"com.example:module2:2.0.0::abcdef1234567003",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "com.example:module1:1.0.0",
|
ID: "com.example:module1:1.0.0::abcdef1234567002",
|
||||||
Name: "com.example:module1",
|
Name: "com.example:module1",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1280,11 +1280,11 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Relationship: ftypes.RelationshipWorkspace,
|
Relationship: ftypes.RelationshipWorkspace,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"org.example:example-api:1.1.1",
|
"org.example:example-api:1.1.1::abcdef1234567003",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "com.example:module2:2.0.0",
|
ID: "com.example:module2:2.0.0::abcdef1234567003",
|
||||||
Name: "com.example:module2",
|
Name: "com.example:module2",
|
||||||
Version: "2.0.0",
|
Version: "2.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1298,11 +1298,11 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Relationship: ftypes.RelationshipWorkspace,
|
Relationship: ftypes.RelationshipWorkspace,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"org.example:example-dependency:1.2.3",
|
"org.example:example-dependency:1.2.3::abcdef1234567005",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "org.example:example-api:1.1.1",
|
ID: "org.example:example-api:1.1.1::abcdef1234567003",
|
||||||
Name: "org.example:example-api",
|
Name: "org.example:example-api",
|
||||||
Version: "1.1.1",
|
Version: "1.1.1",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1317,7 +1317,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Relationship: ftypes.RelationshipDirect,
|
Relationship: ftypes.RelationshipDirect,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "org.example:example-dependency:1.2.3",
|
ID: "org.example:example-dependency:1.2.3::abcdef1234567005",
|
||||||
Name: "org.example:example-dependency",
|
Name: "org.example:example-dependency",
|
||||||
Version: "1.2.3",
|
Version: "1.2.3",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1331,11 +1331,11 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Relationship: ftypes.RelationshipDirect,
|
Relationship: ftypes.RelationshipDirect,
|
||||||
DependsOn: []string{
|
DependsOn: []string{
|
||||||
"org.example:example-api:2.0.0",
|
"org.example:example-api:2.0.0::abcdef1234567006",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "org.example:example-api:2.0.0",
|
ID: "org.example:example-api:2.0.0::abcdef1234567006",
|
||||||
Name: "org.example:example-api",
|
Name: "org.example:example-api",
|
||||||
Version: "2.0.0",
|
Version: "2.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -1394,7 +1394,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "com.example:root:1.0.0",
|
Value: "com.example:root:1.0.0::abcdef1234567001",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
@@ -1421,7 +1421,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "com.example:module1:1.0.0",
|
Value: "com.example:module1:1.0.0::abcdef1234567002",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
@@ -1448,7 +1448,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "com.example:module2:2.0.0",
|
Value: "com.example:module2:2.0.0::abcdef1234567003",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
@@ -1475,7 +1475,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "org.example:example-api:1.1.1",
|
Value: "org.example:example-api:1.1.1::abcdef1234567003",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
@@ -1502,7 +1502,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "org.example:example-dependency:1.2.3",
|
Value: "org.example:example-dependency:1.2.3::abcdef1234567005",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
@@ -1529,7 +1529,7 @@ func TestEncoder_Encode(t *testing.T) {
|
|||||||
Properties: []core.Property{
|
Properties: []core.Property{
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgID,
|
Name: core.PropertyPkgID,
|
||||||
Value: "org.example:example-api:2.0.0",
|
Value: "org.example:example-api:2.0.0::abcdef1234567006",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: core.PropertyPkgType,
|
Name: core.PropertyPkgType,
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
Type: ftypes.Pom,
|
Type: ftypes.Pom,
|
||||||
Packages: []ftypes.Package{
|
Packages: []ftypes.Package{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:1.0.0",
|
ID: "com.example:example:1.0.0::abcdef1234567001",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -798,7 +798,7 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
|
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
|
||||||
PackageSourceInfo: "package found in: pom.xml",
|
PackageSourceInfo: "package found in: pom.xml",
|
||||||
Annotations: []spdx.Annotation{
|
Annotations: []spdx.Annotation{
|
||||||
annotation(t, "PkgID: com.example:example:1.0.0"),
|
annotation(t, "PkgID: com.example:example:1.0.0::abcdef1234567001"),
|
||||||
annotation(t, "PkgType: pom"),
|
annotation(t, "PkgType: pom"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -854,7 +854,7 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
Type: ftypes.Pom,
|
Type: ftypes.Pom,
|
||||||
Packages: []ftypes.Package{
|
Packages: []ftypes.Package{
|
||||||
{
|
{
|
||||||
ID: "com.example:example:1.0.0",
|
ID: "com.example:example:1.0.0::abcdef1234567001",
|
||||||
Name: "com.example:example",
|
Name: "com.example:example",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
Identifier: ftypes.PkgIdentifier{
|
Identifier: ftypes.PkgIdentifier{
|
||||||
@@ -926,7 +926,7 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
|
PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion},
|
||||||
PackageSourceInfo: "package found in: pom.xml",
|
PackageSourceInfo: "package found in: pom.xml",
|
||||||
Annotations: []spdx.Annotation{
|
Annotations: []spdx.Annotation{
|
||||||
annotation(t, "PkgID: com.example:example:1.0.0"),
|
annotation(t, "PkgID: com.example:example:1.0.0::abcdef1234567001"),
|
||||||
annotation(t, "PkgType: pom"),
|
annotation(t, "PkgType: pom"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,13 +42,19 @@ type BySeverity []DetectedVulnerability
|
|||||||
// Len returns the length of DetectedVulnerabilities
|
// Len returns the length of DetectedVulnerabilities
|
||||||
func (v BySeverity) Len() int { return len(v) }
|
func (v BySeverity) Len() int { return len(v) }
|
||||||
|
|
||||||
// Less compares 2 DetectedVulnerabilities based on package name, severity, vulnerabilityID and package path
|
// Less compares 2 DetectedVulnerabilities based on package name, ID, severity, vulnerabilityID and package path
|
||||||
func (v BySeverity) Less(i, j int) bool {
|
func (v BySeverity) Less(i, j int) bool {
|
||||||
if v[i].PkgName != v[j].PkgName {
|
switch {
|
||||||
|
case v[i].PkgName != v[j].PkgName:
|
||||||
return v[i].PkgName < v[j].PkgName
|
return v[i].PkgName < v[j].PkgName
|
||||||
} else if v[i].InstalledVersion != v[j].InstalledVersion {
|
case v[i].PkgID != v[j].PkgID:
|
||||||
|
// For cases where there are different pkgIDs but the same pkgName.
|
||||||
|
// e.g. same packages from different maven module.
|
||||||
|
return v[i].PkgID < v[j].PkgID
|
||||||
|
case v[i].InstalledVersion != v[j].InstalledVersion:
|
||||||
return v[i].InstalledVersion < v[j].InstalledVersion
|
return v[i].InstalledVersion < v[j].InstalledVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := types.CompareSeverityString(
|
ret := types.CompareSeverityString(
|
||||||
v[j].Severity, v[i].Severity,
|
v[j].Severity, v[i].Severity,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user