diff --git a/syft/pkg/cataloger/java/archive_parser.go b/syft/pkg/cataloger/java/archive_parser.go
index 026b7af4c..6653738db 100644
--- a/syft/pkg/cataloger/java/archive_parser.go
+++ b/syft/pkg/cataloger/java/archive_parser.go
@@ -263,21 +263,21 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (name, versi
pomMatches := j.fileManifest.GlobMatch(false, pomXMLGlob)
var pomPropertiesObject pkg.JavaPomProperties
var pomProjectObject *parsedPomProject
- if len(pomPropertyMatches) == 1 || len(pomMatches) == 1 {
- // we have exactly 1 pom.properties or pom.xml in the archive; assume it represents the
- // package we're scanning if the names seem like a plausible match
- properties, _ := pomPropertiesByParentPath(j.archivePath, j.location, pomPropertyMatches)
- projects, _ := pomProjectByParentPath(j.archivePath, j.location, pomMatches)
- for parentPath, propertiesObj := range properties {
- if artifactIDMatchesFilename(propertiesObj.ArtifactID, j.fileInfo.name) {
- pomPropertiesObject = propertiesObj
- if proj, exists := projects[parentPath]; exists {
- pomProjectObject = proj
- }
+ // Find the pom.properties/pom.xml if the names seem like a plausible match
+ properties, _ := pomPropertiesByParentPath(j.archivePath, j.location, pomPropertyMatches)
+ projects, _ := pomProjectByParentPath(j.archivePath, j.location, pomMatches)
+
+ for parentPath, propertiesObj := range properties {
+ if artifactIDMatchesFilename(propertiesObj.ArtifactID, j.fileInfo.name) {
+ pomPropertiesObject = propertiesObj
+ if proj, exists := projects[parentPath]; exists {
+ pomProjectObject = proj
+ break
}
}
}
+
name = pomPropertiesObject.ArtifactID
if name == "" && pomProjectObject != nil {
name = pomProjectObject.ArtifactID
diff --git a/syft/pkg/cataloger/java/archive_parser_test.go b/syft/pkg/cataloger/java/archive_parser_test.go
index 40927d213..3d05fb868 100644
--- a/syft/pkg/cataloger/java/archive_parser_test.go
+++ b/syft/pkg/cataloger/java/archive_parser_test.go
@@ -1036,6 +1036,7 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
fixtureName string
expectedPkgs []pkg.Package
expectedRelationships []artifact.Relationship
+ assignParent bool
want bool
}{
{
@@ -1146,10 +1147,74 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
},
},
},
+ {
+ name: "multiple pom for parent selection regression (pr 2231)",
+ fixtureName: "api-all-2.0.0-sources",
+ assignParent: true,
+ expectedPkgs: []pkg.Package{
+ {
+ Name: "api-all",
+ Version: "2.0.0",
+ Type: pkg.JavaPkg,
+ Language: pkg.Java,
+ PURL: "pkg:maven/org.apache.directory.api/api-all@2.0.0",
+ Locations: file.NewLocationSet(file.NewLocation("test-fixtures/jar-metadata/cache/api-all-2.0.0-sources.jar")),
+ Metadata: pkg.JavaArchive{
+ VirtualPath: "test-fixtures/jar-metadata/cache/api-all-2.0.0-sources.jar",
+ Manifest: &pkg.JavaManifest{
+ Main: map[string]string{
+ "Build-Jdk": "1.8.0_191",
+ "Built-By": "elecharny",
+ "Created-By": "Apache Maven 3.6.0",
+ "Manifest-Version": "1.0",
+ },
+ },
+ PomProperties: &pkg.JavaPomProperties{
+ Path: "META-INF/maven/org.apache.directory.api/api-all/pom.properties",
+ GroupID: "org.apache.directory.api",
+ ArtifactID: "api-all",
+ Version: "2.0.0",
+ },
+ },
+ },
+ {
+ Name: "api-asn1-api",
+ Version: "2.0.0",
+ PURL: "pkg:maven/org.apache.directory.api/api-asn1-api@2.0.0",
+ Locations: file.NewLocationSet(file.NewLocation("test-fixtures/jar-metadata/cache/api-all-2.0.0-sources.jar")),
+ Type: pkg.JavaPkg,
+ Language: pkg.Java,
+ Metadata: pkg.JavaArchive{
+ VirtualPath: "test-fixtures/jar-metadata/cache/api-all-2.0.0-sources.jar:org.apache.directory.api:api-asn1-api",
+ PomProperties: &pkg.JavaPomProperties{
+ Path: "META-INF/maven/org.apache.directory.api/api-asn1-api/pom.properties",
+ GroupID: "org.apache.directory.api",
+ ArtifactID: "api-asn1-api",
+ Version: "2.0.0",
+ },
+ PomProject: &pkg.JavaPomProject{
+ Path: "META-INF/maven/org.apache.directory.api/api-asn1-api/pom.xml",
+ ArtifactID: "api-asn1-api",
+ Name: "Apache Directory API ASN.1 API",
+ Description: "ASN.1 API",
+ Parent: &pkg.JavaPomParent{
+ GroupID: "org.apache.directory.api",
+ ArtifactID: "api-asn1-parent",
+ Version: "2.0.0",
+ },
+ },
+ Parent: nil,
+ },
+ },
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gap := newGenericArchiveParserAdapter(Config{})
+ if tt.assignParent {
+ assignParent(&tt.expectedPkgs[0], tt.expectedPkgs[1:]...)
+ }
pkgtest.NewCatalogTester().
FromFile(t, generateJavaMetadataJarFixture(t, tt.fixtureName)).
Expects(tt.expectedPkgs, tt.expectedRelationships).
@@ -1159,6 +1224,18 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
}
}
+func assignParent(parent *pkg.Package, childPackages ...pkg.Package) {
+ for i, jp := range childPackages {
+ if v, ok := jp.Metadata.(pkg.JavaArchive); ok {
+ parent := *parent
+ // PURL are not calculated after the fact for parent
+ parent.PURL = ""
+ v.Parent = &parent
+ childPackages[i].Metadata = v
+ }
+ }
+}
+
func generateJavaMetadataJarFixture(t *testing.T, fixtureName string) string {
fixturePath := filepath.Join("test-fixtures/jar-metadata/cache/", fixtureName+".jar")
if _, err := os.Stat(fixturePath); !os.IsNotExist(err) {
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
index 6f2398820..1fd78b446 100644
--- a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
@@ -3,6 +3,7 @@ CACHE_PATH = $(shell pwd)/cache
JACKSON_CORE = jackson-core-2.15.2
SBT_JACKSON_CORE = com.fasterxml.jackson.core.jackson-core-2.15.2
+API_ALL_SOURCES = api-all-2.0.0-sources
$(CACHE_DIR):
mkdir -p $(CACHE_DIR)
@@ -12,3 +13,6 @@ $(CACHE_DIR)/$(JACKSON_CORE).jar: $(CACHE_DIR)
$(CACHE_DIR)/$(SBT_JACKSON_CORE).jar: $(CACHE_DIR)
cd $(SBT_JACKSON_CORE) && zip -r $(CACHE_PATH)/$(SBT_JACKSON_CORE).jar .
+
+$(CACHE_DIR)/$(API_ALL_SOURCES).jar: $(CACHE_DIR)
+ cd $(API_ALL_SOURCES) && zip -r $(CACHE_PATH)/$(API_ALL_SOURCES).jar .
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/README.md b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/README.md
index dfb2a3489..c3e3fcc52 100644
--- a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/README.md
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/README.md
@@ -3,3 +3,11 @@
Each directory is the name of a jar to be created (simply a zip) based on the contents of the directory.
This prevents us from having to create real jars by hand or keep binaries in the repo. This also means we dont need the
entire jar, only the necessary metadata for testing.
+
+### api-all-2.0.0-sources
+This fixture is built to simulate the case where we have a jar with multiple pom files discovered when trying to determine the parent.
+This is a valid case, but not one that we covered before [PR 2231](https://github.com/anchore/syft/pull/2231)
+
+### jackson-core-2.15.2
+These two fixtures are built to simulate the case where we would have a duplicate jar
+regression as seen in [issue #2130](https://github.com/anchore/syft/issues/2130)
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/MANIFEST.MF b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..c303943c4
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Built-By: elecharny
+Created-By: Apache Maven 3.6.0
+Build-Jdk: 1.8.0_191
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.properties
new file mode 100644
index 000000000..a409e2fef
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.properties
@@ -0,0 +1,4 @@
+#Created by Apache Maven 3.6.0
+version=2.0.0
+groupId=org.apache.directory.api
+artifactId=api-all
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.xml
new file mode 100644
index 000000000..3726550be
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-all/pom.xml
@@ -0,0 +1,135 @@
+
+
+
+ 4.0.0
+
+ org.apache.directory.api
+ api-parent
+ 2.0.0
+
+
+ api-all
+ Apache Directory API All
+
+
+
+ ${project.groupId}
+ api-asn1-api
+
+
+ ${project.groupId}
+ api-asn1-ber
+
+
+ ${project.groupId}
+ api-dsml-engine
+
+
+ ${project.groupId}
+ api-dsml-parser
+
+
+ ${project.groupId}
+ api-i18n
+
+
+ ${project.groupId}
+ api-ldap-client-api
+
+
+ ${project.groupId}
+ api-ldap-codec-core
+
+
+ ${project.groupId}
+ api-ldap-codec-standalone
+
+
+ ${project.groupId}
+ api-ldap-extras-aci
+
+
+ ${project.groupId}
+ api-ldap-extras-codec
+
+
+ ${project.groupId}
+ api-ldap-extras-codec-api
+
+
+ ${project.groupId}
+ api-ldap-extras-sp
+
+
+ ${project.groupId}
+ api-ldap-extras-trigger
+
+
+ ${project.groupId}
+ api-ldap-extras-util
+
+
+ ${project.groupId}
+ api-ldap-model
+
+
+ ${project.groupId}
+ api-ldap-net-mina
+
+
+ ${project.groupId}
+ api-ldap-schema-converter
+
+
+ ${project.groupId}
+ api-ldap-schema-data
+
+
+ ${project.groupId}
+ api-util
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ ${project.groupId}
+
+
+ true
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.properties
new file mode 100644
index 000000000..ec2a06fa1
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.properties
@@ -0,0 +1,4 @@
+#Created by Apache Maven 3.6.0
+version=2.0.0
+groupId=org.apache.directory.api
+artifactId=api-asn1-api
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.xml
new file mode 100644
index 000000000..a57cda8e7
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/api-all-2.0.0-sources/META-INF/maven/org.apache.directory.api/api-asn1-api/pom.xml
@@ -0,0 +1,99 @@
+
+
+
+ 4.0.0
+
+ org.apache.directory.api
+ api-asn1-parent
+ 2.0.0
+
+
+ api-asn1-api
+ Apache Directory API ASN.1 API
+ bundle
+
+ ASN.1 API
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+ log4j
+ log4j
+ test
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ test
+
+
+
+ org.slf4j
+ slf4j-api
+ test
+
+
+
+ ${project.groupId}
+ api-i18n
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ META-INF/MANIFEST.MF
+ false
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+ true
+
+ META-INF
+
+ ${project.groupId}.asn1.api
+
+ org.apache.directory.api.asn1;version=${project.version};-noimport:=true,
+ org.apache.directory.api.asn1.util;version=${project.version};-noimport:=true
+
+
+ org.apache.directory.api.i18n;version=${project.version}
+
+
+
+
+
+
+