diff --git a/go.mod b/go.mod index 82cea45b0ea..87692a0f38c 100644 --- a/go.mod +++ b/go.mod @@ -90,6 +90,7 @@ require ( github.com/BurntSushi/toml v1.4.0 github.com/adrg/xdg v0.5.0 github.com/magiconair/properties v1.8.7 + golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 ) require ( @@ -230,7 +231,6 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect diff --git a/syft/pkg/cataloger/java/archive_parser.go b/syft/pkg/cataloger/java/archive_parser.go index 134e8f18af3..2262d79fb7c 100644 --- a/syft/pkg/cataloger/java/archive_parser.go +++ b/syft/pkg/cataloger/java/archive_parser.go @@ -6,8 +6,11 @@ import ( "fmt" "os" "path" + "slices" "strings" + "golang.org/x/exp/maps" + intFile "github.com/anchore/syft/internal/file" "github.com/anchore/syft/internal/licenses" "github.com/anchore/syft/internal/log" @@ -298,7 +301,10 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo(ctx context.Co properties, _ := pomPropertiesByParentPath(j.archivePath, j.location, pomPropertyMatches) projects, _ := pomProjectByParentPath(j.archivePath, j.location, pomMatches) - for parentPath, propertiesObj := range properties { + parentPaths := maps.Keys(properties) + slices.Sort(parentPaths) + for _, parentPath := range parentPaths { + propertiesObj := properties[parentPath] if artifactIDMatchesFilename(propertiesObj.ArtifactID, j.fileInfo.name) { pomPropertiesObject = propertiesObj if proj, exists := projects[parentPath]; exists { diff --git a/syft/pkg/cataloger/java/archive_parser_test.go b/syft/pkg/cataloger/java/archive_parser_test.go index 7d7164196c3..968be857862 100644 --- a/syft/pkg/cataloger/java/archive_parser_test.go +++ b/syft/pkg/cataloger/java/archive_parser_test.go @@ -1386,6 +1386,44 @@ func Test_parseJavaArchive_regressions(t *testing.T) { } } +func Test_deterministicMatchingPomProperties(t *testing.T) { + tests := []struct { + fixture string + expectedName string + expectedVersion string + }{ + { + fixture: "multiple-matching-2.11.5", + expectedName: "multiple-matching-1", + expectedVersion: "2.11.5", + }, + } + + for _, test := range tests { + t.Run(test.fixture, func(t *testing.T) { + fixturePath := generateJavaMetadataJarFixture(t, test.fixture) + + for i := 0; i < 5; i++ { + func() { + fixture, err := os.Open(fixturePath) + require.NoError(t, err) + + parser, cleanupFn, err := newJavaArchiveParser(file.LocationReadCloser{ + Location: file.NewLocation(fixture.Name()), + ReadCloser: fixture, + }, false, ArchiveCatalogerConfig{UseNetwork: false}) + defer cleanupFn() + require.NoError(t, err) + + name, version, _ := parser.guessMainPackageNameAndVersionFromPomInfo(context.TODO()) + require.Equal(t, test.expectedName, name) + require.Equal(t, test.expectedVersion, version) + }() + } + }) + } +} + func assignParent(parent *pkg.Package, childPackages ...pkg.Package) { for i, jp := range childPackages { if v, ok := jp.Metadata.(pkg.JavaArchive); ok { diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile index b6533f1471c..c5d3c52a3af 100644 --- a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile @@ -6,6 +6,7 @@ SBT_JACKSON_CORE = com.fasterxml.jackson.core.jackson-core-2.15.2 OPENSAML_CORE = opensaml-core-3.4.6 API_ALL_SOURCES = api-all-2.0.0-sources SPRING_INSTRUMENTATION = spring-instrumentation-4.3.0-1.0 +MULTIPLE_MATCHING = multiple-matching-2.11.5 $(CACHE_DIR): mkdir -p $(CACHE_DIR) @@ -24,3 +25,6 @@ $(CACHE_DIR)/$(API_ALL_SOURCES).jar: $(CACHE_DIR) $(CACHE_DIR)/$(SPRING_INSTRUMENTATION).jar: $(CACHE_DIR) cd $(SPRING_INSTRUMENTATION) && zip -r $(CACHE_PATH)/$(SPRING_INSTRUMENTATION).jar . + +$(CACHE_DIR)/$(MULTIPLE_MATCHING).jar: $(CACHE_DIR) + cd $(MULTIPLE_MATCHING) && zip -r $(CACHE_PATH)/$(MULTIPLE_MATCHING).jar . diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/MANIFEST.MF b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..525109c7337 --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Created-By: Multi diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.properties new file mode 100644 index 00000000000..43e0d811b73 --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.properties @@ -0,0 +1,3 @@ +version=2.11.5 +groupId=org.multiple +artifactId=multiple-matching-1 diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.xml new file mode 100644 index 00000000000..1c359dd9aa2 --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-1/pom.xml @@ -0,0 +1,8 @@ + + + 4.0.0 + + org.multiple + multiple-matching-1 + 2.11.5 + diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.properties new file mode 100644 index 00000000000..6be2acfbd13 --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.properties @@ -0,0 +1,3 @@ +version=2.11.5 +groupId=org.multiple +artifactId=multiple-matching-2 \ No newline at end of file diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.xml new file mode 100644 index 00000000000..343c49d303d --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-2/pom.xml @@ -0,0 +1,8 @@ + + + 4.0.0 + + org.multiple + multiple-matching-2 + 2.11.5 + diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.properties new file mode 100644 index 00000000000..187215b293d --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.properties @@ -0,0 +1,3 @@ +version=2.11.5 +groupId=org.multiple +artifactId=multiple-matching-3 diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.xml new file mode 100644 index 00000000000..b428bd69bbd --- /dev/null +++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/multiple-matching-2.11.5/META-INF/maven/org.multiple/multiple-matching-3/pom.xml @@ -0,0 +1,8 @@ + + + 4.0.0 + + org.multiple + multiple-matching-3 + 2.11.5 +