Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions syft/format/cyclonedxjson/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,38 @@ func TestDecoder_Decode(t *testing.T) {
}
}

func TestDecoder_DecodeEvidenceOccurrenceLocation(t *testing.T) {
reader := strings.NewReader(`{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"components": [
{
"type": "library",
"bom-ref": "example@1.0.0",
"name": "example",
"version": "1.0.0",
"evidence": {
"occurrences": [
{"location": "/usr/bin/example"}
]
}
}
]
}`)

bom, _, _, err := NewFormatDecoder().Decode(reader)
require.NoError(t, err)

packages := bom.Artifacts.Packages.Sorted()
require.Len(t, packages, 1)

locations := packages[0].Locations.ToSlice()
require.Len(t, locations, 1)
assert.Equal(t, "/usr/bin/example", locations[0].RealPath)
assert.Equal(t, "/usr/bin/example", locations[0].AccessPath)
}

func TestDecoder_Identify(t *testing.T) {
type testCase struct {
name string
Expand Down
18 changes: 15 additions & 3 deletions syft/format/internal/cyclonedxutil/helpers/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func decodeComponent(c *cyclonedx.Component) *pkg.Package {

p := &pkg.Package{
Version: c.Version,
Locations: decodeLocations(values),
Locations: decodeLocations(values, c.Evidence),
Licenses: pkg.NewLicenseSet(decodeLicenses(c)...),
CPEs: decodeCPEs(c),
}
Expand Down Expand Up @@ -204,13 +204,25 @@ func setPackageName(p *pkg.Package, c *cyclonedx.Component) {
p.Name = name
}

func decodeLocations(vals map[string]string) file.LocationSet {
func decodeLocations(vals map[string]string, evidence *cyclonedx.Evidence) file.LocationSet {
v := Decode(reflect.TypeFor[[]file.Location](), vals, "syft:location", CycloneDXFields)
out, ok := v.([]file.Location)
if !ok {
out = nil
}
return file.NewLocationSet(out...)

locations := file.NewLocationSet(out...)
if evidence == nil || evidence.Occurrences == nil {
return locations
}

for _, occurrence := range *evidence.Occurrences {
if occurrence.Location != "" {
locations.Add(file.NewLocation(occurrence.Location))
}
}

return locations
}

func decodePackageMetadata(vals map[string]string, c *cyclonedx.Component, typeName string) any {
Expand Down
66 changes: 66 additions & 0 deletions syft/format/internal/cyclonedxutil/helpers/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,72 @@ func Test_decodeComponent(t *testing.T) {
}
}

func Test_decodeComponentLocations(t *testing.T) {
tests := []struct {
name string
component cyclonedx.Component
wantPaths []string
}{
{
name: "decode CycloneDX evidence occurrences",
component: cyclonedx.Component{
Name: "example",
Evidence: evidenceWithOccurrences(
"/usr/bin/example",
"/opt/example",
),
},
wantPaths: []string{"/opt/example", "/usr/bin/example"},
},
{
name: "combine Syft properties and evidence occurrences",
component: cyclonedx.Component{
Name: "example",
Properties: &[]cyclonedx.Property{
{
Name: "syft:location:0:path",
Value: "/usr/lib/example",
},
},
Evidence: evidenceWithOccurrences("/usr/bin/example"),
},
wantPaths: []string{"/usr/bin/example", "/usr/lib/example"},
},
{
name: "ignore empty and duplicate evidence locations",
component: cyclonedx.Component{
Name: "example",
Evidence: evidenceWithOccurrences(
"/usr/bin/example",
"",
"/usr/bin/example",
),
},
wantPaths: []string{"/usr/bin/example"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := decodeComponent(&tt.component)
locations := p.Locations.ToSlice()
paths := make([]string, len(locations))
for i, location := range locations {
paths[i] = location.RealPath
}
assert.ElementsMatch(t, tt.wantPaths, paths)
})
}
}

func evidenceWithOccurrences(locations ...string) *cyclonedx.Evidence {
occurrences := make([]cyclonedx.EvidenceOccurrence, len(locations))
for i, location := range locations {
occurrences[i] = cyclonedx.EvidenceOccurrence{Location: location}
}
return &cyclonedx.Evidence{Occurrences: &occurrences}
}

func Test_setPackageName(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading