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
+114 -1
View File
@@ -1,15 +1,17 @@
package file
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal/evidence"
"github.com/anchore/syft/syft/artifact"
)
func TestLocationSet(t *testing.T) {
func TestLocationSet_SortPaths(t *testing.T) {
etcHostsLinkVar := Location{
LocationData: LocationData{
@@ -93,6 +95,117 @@ func TestLocationSet(t *testing.T) {
}
}
func TestLocationSet_SortEvidence(t *testing.T) {
primaryEvidence := map[string]string{evidence.AnnotationKey: evidence.PrimaryAnnotation}
secondaryEvidence := map[string]string{evidence.AnnotationKey: evidence.SupportingAnnotation}
binPrimary := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/bin",
FileSystemID: "a",
},
AccessPath: "/usr/bin",
},
LocationMetadata: LocationMetadata{
Annotations: primaryEvidence,
},
}
binSecondary := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/bin",
FileSystemID: "a",
},
AccessPath: "/usr/bin",
},
LocationMetadata: LocationMetadata{
Annotations: secondaryEvidence,
},
}
binNoEvidence := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/bin",
FileSystemID: "a",
},
AccessPath: "/usr/bin",
},
}
etcHostsPrimary := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/etc/hosts",
FileSystemID: "a",
},
AccessPath: "/var/etc/hosts",
},
LocationMetadata: LocationMetadata{
Annotations: primaryEvidence,
},
}
etcHostsSecondary := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/etc/hosts",
FileSystemID: "a",
},
AccessPath: "/var/etc/hosts",
},
LocationMetadata: LocationMetadata{
Annotations: secondaryEvidence,
},
}
etcHostsNoEvidence := Location{
LocationData: LocationData{
Coordinates: Coordinates{
RealPath: "/etc/hosts",
FileSystemID: "a",
},
AccessPath: "/var/etc/hosts",
},
}
tests := []struct {
name string
input []Location
expected []Location
}{
{
name: "sort primary, secondary, tertiary, no evidence",
input: []Location{
binNoEvidence, binPrimary, binSecondary,
},
expected: []Location{
binPrimary, binSecondary, binNoEvidence,
},
},
{
name: "sort by evidence, then path",
input: []Location{
etcHostsNoEvidence, etcHostsSecondary,
binSecondary, binNoEvidence,
binPrimary, etcHostsPrimary,
},
expected: []Location{
binPrimary, etcHostsPrimary, binSecondary, etcHostsSecondary, binNoEvidence, etcHostsNoEvidence,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
sort.Sort(Locations(test.input))
assert.Equal(t, test.expected, test.input)
})
}
}
func TestLocationSet_Hash(t *testing.T) {
etcAlink := Location{
LocationData: LocationData{
+19 -5
View File
@@ -1,5 +1,7 @@
package file
import "github.com/anchore/syft/internal/evidence"
type Locations []Location
func (l Locations) Len() int {
@@ -7,13 +9,25 @@ func (l Locations) Len() int {
}
func (l Locations) Less(i, j int) bool {
if l[i].RealPath == l[j].RealPath {
if l[i].AccessPath == l[j].AccessPath {
return l[i].FileSystemID < l[j].FileSystemID
liEvidence := l[i].Annotations[evidence.AnnotationKey]
ljEvidence := l[j].Annotations[evidence.AnnotationKey]
if liEvidence == ljEvidence {
if l[i].RealPath == l[j].RealPath {
if l[i].AccessPath == l[j].AccessPath {
return l[i].FileSystemID < l[j].FileSystemID
}
return l[i].AccessPath < l[j].AccessPath
}
return l[i].AccessPath < l[j].AccessPath
return l[i].RealPath < l[j].RealPath
}
return l[i].RealPath < l[j].RealPath
if liEvidence == evidence.PrimaryAnnotation {
return true
}
if ljEvidence == evidence.PrimaryAnnotation {
return false
}
return liEvidence > ljEvidence
}
func (l Locations) Swap(i, j int) {