Location order on packages should consider evidence annotations when sorting (#3720)

* fix: sorting locations should consider pkg evidence

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* simplify location test options for comparison

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2025-03-11 10:34:37 -04:00
committed by GitHub
parent 04941c8b97
commit 34e5ff753f
13 changed files with 226 additions and 151 deletions
+11 -45
View File
@@ -8,11 +8,15 @@ import (
"github.com/anchore/syft/syft/pkg"
)
func DefaultCommonOptions() []cmp.Option {
return CommonOptions(nil, nil)
func DefaultOptions() []cmp.Option {
return BuildOptions(nil, nil)
}
func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cmp.Option {
func DefaultIgnoreLocationLayerOptions() []cmp.Option {
return BuildOptions(LicenseComparerWithoutLocationLayer, LocationComparerWithoutLayer)
}
func BuildOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cmp.Option {
if licenseCmp == nil {
licenseCmp = DefaultLicenseComparer
}
@@ -25,47 +29,9 @@ func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []c
cmpopts.IgnoreFields(pkg.Package{}, "id"), // note: ID is not deterministic for test purposes
cmpopts.SortSlices(pkg.Less),
cmpopts.SortSlices(DefaultRelationshipComparer),
cmp.Comparer(
func(x, y file.LocationSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()
if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !locationCmp(xe, ye) {
return false
}
}
return true
},
),
cmp.Comparer(
func(x, y pkg.LicenseSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()
if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !licenseCmp(xe, ye) {
return false
}
}
return true
},
),
cmp.Comparer(
locationCmp,
),
cmp.Comparer(
licenseCmp,
),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](locationCmp)),
cmp.Comparer(buildSetComparer[pkg.License, pkg.LicenseSet](licenseCmp)),
cmp.Comparer(locationCmp),
cmp.Comparer(licenseCmp),
}
}
+13 -16
View File
@@ -10,20 +10,17 @@ import (
type LicenseComparer func(x, y pkg.License) bool
func DefaultLicenseComparer(x, y pkg.License) bool {
return cmp.Equal(x, y, cmp.Comparer(DefaultLocationComparer), cmp.Comparer(
func(x, y file.LocationSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()
if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !DefaultLocationComparer(xe, ye) {
return false
}
}
return true
},
))
return cmp.Equal(
x, y,
cmp.Comparer(DefaultLocationComparer),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](DefaultLocationComparer)),
)
}
func LicenseComparerWithoutLocationLayer(x, y pkg.License) bool {
return cmp.Equal(
x, y,
cmp.Comparer(LocationComparerWithoutLayer),
cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](LocationComparerWithoutLayer)),
)
}
+4
View File
@@ -11,3 +11,7 @@ type LocationComparer func(x, y file.Location) bool
func DefaultLocationComparer(x, y file.Location) bool {
return cmp.Equal(x.Coordinates, y.Coordinates) && cmp.Equal(x.AccessPath, y.AccessPath)
}
func LocationComparerWithoutLayer(x, y file.Location) bool {
return cmp.Equal(x.Coordinates.RealPath, y.Coordinates.RealPath) && cmp.Equal(x.AccessPath, y.AccessPath)
}
+24
View File
@@ -0,0 +1,24 @@
package cmptest
type slicer[T any] interface {
ToSlice() []T
}
func buildSetComparer[T any, S slicer[T]](l func(x, y T) bool) func(x, y S) bool {
return func(x, y S) bool {
xs := x.ToSlice()
ys := y.ToSlice()
if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !l(xe, ye) {
return false
}
}
return true
}
}
+9
View File
@@ -0,0 +1,9 @@
package evidence
// this package exists so that the file package can reference package evidence in tests without creating a circular dependency.
const (
AnnotationKey = "evidence"
PrimaryAnnotation = "primary"
SupportingAnnotation = "supporting"
)
@@ -145,7 +145,7 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
assert.Len(t, relationships, len(expectedRelations))
for idx, expectedRelationship := range expectedRelations {
actualRelationship := relationships[idx]
if d := cmp.Diff(expectedRelationship, actualRelationship, cmptest.DefaultCommonOptions()...); d != "" {
if d := cmp.Diff(expectedRelationship, actualRelationship, cmptest.DefaultOptions()...); d != "" {
t.Errorf("unexpected relationship (-want, +got): %s", d)
}
}