diff --git a/internal/relationship/by_file_ownership_test.go b/internal/relationship/by_file_ownership_test.go index 1e83a2c76..ed8282eb9 100644 --- a/internal/relationship/by_file_ownership_test.go +++ b/internal/relationship/by_file_ownership_test.go @@ -103,7 +103,9 @@ func TestOwnershipByFilesRelationship(t *testing.T) { }, }, { - name: "top-level-owner-of-an-archive-owns-packages-within-it", + // the archive's own package (when it has one) is found by its path; what is inside it is + // linked to that package by CONTAINS, not owned by whoever owns the archive file + name: "top-level-owner-of-an-archive-does-not-own-packages-within-it", setup: func(t testing.TB) ([]pkg.Package, []artifact.Relationship) { parent := pkg.Package{ Locations: file.NewLocationSet(file.NewLocation("/var/lib/rpm/Packages")), @@ -123,14 +125,7 @@ func TestOwnershipByFilesRelationship(t *testing.T) { } child.SetID() - relationship := artifact.Relationship{ - From: parent, - To: child, - Type: artifact.OwnershipByFileOverlapRelationship, - Data: ownershipByFilesMetadata{Files: []string{"/opt/bundle.tar"}}, - } - - return []pkg.Package{parent, child}, []artifact.Relationship{relationship} + return []pkg.Package{parent, child}, nil }, }, { diff --git a/syft/pkg/collection.go b/syft/pkg/collection.go index b808edf56..a566869c8 100644 --- a/syft/pkg/collection.go +++ b/syft/pkg/collection.go @@ -62,7 +62,7 @@ func (c *Collection) Package(id artifact.ID) *Package { } // PackagesByPath returns all packages that were discovered from the given path: a file's full path or -// access path, or the top path of an archive, which answers with every package found within it. +// access path. A package found within an archive is not returned for the archive's own path. func (c *Collection) PackagesByPath(path string) []Package { c.lock.RLock() defer c.lock.RUnlock() @@ -164,12 +164,12 @@ func (c *Collection) addPathsToIndex(p Package) { } } -// indexedPaths are the paths a package is found by: each location's full path and access path, and -// the top path of an archive it was found within. +// indexedPaths are the paths a package is found by: each location's full path and access path. The real +// path of a nested location is the outermost archive, so it is left out. func indexedPaths(p Package) []string { paths := strset.New() for _, l := range p.Locations.ToSlice() { - paths.Add(l.RealPath, l.AccessPath, l.FullNestedPath()) + paths.Add(l.AccessPath, l.FullNestedPath()) } paths.Remove("") return paths.List() diff --git a/syft/pkg/collection_test.go b/syft/pkg/collection_test.go index e1f08fd91..74bedc701 100644 --- a/syft/pkg/collection_test.go +++ b/syft/pkg/collection_test.go @@ -433,6 +433,23 @@ func TestCatalog_MergeRecords(t *testing.T) { } } +func TestCatalog_PackagesByPath_nestedPackagesAreNotFoundByTheOuterArchive(t *testing.T) { + jar := Package{Name: "jar", Type: JavaPkg, Locations: file.NewLocationSet(file.NewLocation("/opt/x.jar"))} + nested := file.Coordinates{RealPath: "/opt/x.jar", FullPath: "/opt/x.jar!/lib/a.so"} + so := Package{Name: "so", Type: BinaryPkg, Locations: file.NewLocationSet(file.NewLocationFromCoordinates(nested))} + c := NewCollection(jar, so) + + names := func(pkgs []Package) []string { + var out []string + for _, p := range pkgs { + out = append(out, p.Name) + } + return out + } + assert.Equal(t, []string{"jar"}, names(c.PackagesByPath("/opt/x.jar"))) + assert.Equal(t, []string{"so"}, names(c.PackagesByPath(nested.FullPath))) +} + func TestCatalog_EnumerateNilCatalog(t *testing.T) { var c *Collection assert.Empty(t, c.Enumerate())