fix: duplicate entries in cyclonedx dependency list (#2063)

Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
Keith Zantow 2023-08-25 12:19:01 -04:00 committed by GitHub
parent d08e2be768
commit 4ae94c37eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 36 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/CycloneDX/cyclonedx-go"
"github.com/google/uuid"
"golang.org/x/exp/slices"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
@ -139,7 +140,7 @@ func isExpressiblePackageRelationship(ty artifact.RelationshipType) bool {
}
func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependency {
result := make([]cyclonedx.Dependency, 0)
dependencies := map[string]*cyclonedx.Dependency{}
for _, r := range relationships {
exists := isExpressiblePackageRelationship(r.Type)
if !exists {
@ -160,15 +161,32 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
continue
}
// ind dep
toRef := deriveBomRef(toPkg)
dep := dependencies[toRef]
if dep == nil {
dep = &cyclonedx.Dependency{
Ref: toRef,
Dependencies: &[]string{},
}
dependencies[toRef] = dep
}
innerDeps := []string{}
innerDeps = append(innerDeps, deriveBomRef(fromPkg))
result = append(result, cyclonedx.Dependency{
Ref: deriveBomRef(toPkg),
Dependencies: &innerDeps,
})
fromRef := deriveBomRef(fromPkg)
if !slices.Contains(*dep.Dependencies, fromRef) {
*dep.Dependencies = append(*dep.Dependencies, fromRef)
}
}
result := make([]cyclonedx.Dependency, 0, len(dependencies))
for _, dep := range dependencies {
slices.Sort(*dep.Dependencies)
result = append(result, *dep)
}
slices.SortFunc(result, func(a, b cyclonedx.Dependency) bool {
return a.Ref < b.Ref
})
return result
}

View File

@ -1,6 +1,7 @@
package cyclonedxhelpers
import (
"fmt"
"testing"
"github.com/CycloneDX/cyclonedx-go"
@ -43,28 +44,34 @@ func Test_relationships(t *testing.T) {
p1 := pkg.Package{
Name: "p1",
}
p1.SetID()
p2 := pkg.Package{
Name: "p2",
}
p2.SetID()
p3 := pkg.Package{
Name: "p3",
}
p3.SetID()
p4 := pkg.Package{
Name: "p4",
}
for _, p := range []*pkg.Package{&p1, &p2, &p3, &p4} {
p.PURL = fmt.Sprintf("pkg:generic/%s@%s", p.Name, p.Name)
p.SetID()
}
tests := []struct {
name string
sbom sbom.SBOM
expected []string
expected *[]cyclonedx.Dependency
}{
{
name: "package dependencyOf relationships output as dependencies",
sbom: sbom.SBOM{
Artifacts: sbom.Artifacts{
Packages: pkg.NewCollection(p1, p2, p3),
Packages: pkg.NewCollection(p1, p2, p3, p4),
},
Relationships: []artifact.Relationship{
{
@ -77,9 +84,28 @@ func Test_relationships(t *testing.T) {
To: p1,
Type: artifact.DependencyOfRelationship,
},
{
From: p4,
To: p2,
Type: artifact.DependencyOfRelationship,
},
},
},
expected: &[]cyclonedx.Dependency{
{
Ref: deriveBomRef(p1),
Dependencies: &[]string{
deriveBomRef(p2),
deriveBomRef(p3),
},
},
{
Ref: deriveBomRef(p2),
Dependencies: &[]string{
deriveBomRef(p4),
},
},
},
expected: []string{p2.Name, p3.Name},
},
{
name: "package contains relationships not output",
@ -108,28 +134,7 @@ func Test_relationships(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
cdx := ToFormatModel(test.sbom)
got := cdx.Dependencies
var deps []string
if got != nil {
for _, r := range *got {
for _, d := range *r.Dependencies {
c := findComponent(cdx, d)
require.NotNil(t, c)
deps = append(deps, c.Name)
}
}
}
require.Equal(t, test.expected, deps)
require.Equal(t, test.expected, got)
})
}
}
func findComponent(cdx *cyclonedx.BOM, bomRef string) *cyclonedx.Component {
for _, c := range *cdx.Components {
if c.BOMRef == bomRef {
return &c
}
}
return nil
}