From 22413462a24ae281cf6d18e3a0cefd5e866482f2 Mon Sep 17 00:00:00 2001 From: Elias Lundell <36220731+LogFlames@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:41:50 +0200 Subject: [PATCH] sort components, dependencies, and dependsOn for CycloneDX BOM (#258) --- entities/buildinfo.go | 12 ++++++++++++ entities/buildinfo_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/entities/buildinfo.go b/entities/buildinfo.go index 6221dde3..f330ac54 100644 --- a/entities/buildinfo.go +++ b/entities/buildinfo.go @@ -6,6 +6,7 @@ import ( "golang.org/x/exp/maps" "golang.org/x/exp/slices" "regexp" + "sort" "strings" "time" @@ -200,13 +201,24 @@ func (targetBuildInfo *BuildInfo) ToCycloneDxBom() (*cdx.BOM, error) { } } + sort.Slice(components, func(i, j int) bool { + return components[i].BOMRef < components[j].BOMRef + }) + // Convert the map of dependencies to CycloneDX dependency objects var dependencies []cdx.Dependency for compRef, deps := range depMap { depsSlice := maps.Keys(deps) + sort.Slice(depsSlice, func(i, j int) bool { + return depsSlice[i] < depsSlice[j] + }) dependencies = append(dependencies, cdx.Dependency{Ref: compRef, Dependencies: &depsSlice}) } + sort.Slice(dependencies, func(i, j int) bool { + return dependencies[i].Ref < dependencies[j].Ref + }) + bom := cdx.NewBOM() bom.Components = &components bom.Dependencies = &dependencies diff --git a/entities/buildinfo_test.go b/entities/buildinfo_test.go index 8427e5da..c14945f4 100644 --- a/entities/buildinfo_test.go +++ b/entities/buildinfo_test.go @@ -2,6 +2,7 @@ package entities import ( "reflect" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -239,3 +240,36 @@ func TestAppend(t *testing.T) { assert.NoError(t, err) assert.True(t, results) } + +func TestToCycloneDxBOM(t *testing.T) { + dependencyA := Dependency{Id: "dependency-a", Checksum: Checksum{Sha1: "dependency-a-sha"}, RequestedBy: [][]string{{"dependency-c"}}} + dependencyB := Dependency{Id: "dependency-b", Checksum: Checksum{Sha1: "dependency-b-sha"}, RequestedBy: [][]string{{"dependency-b"}, {"dependency-c"}}} + dependencyC := Dependency{Id: "dependency-c", Checksum: Checksum{Sha1: "dependency-c-sha"}} + + buildInfo := BuildInfo{ + Modules: []Module{{ + Id: "module-id1", + Dependencies: []Dependency{dependencyC, dependencyB, dependencyA}, + }}, + } + + cdxBom, err := buildInfo.ToCycloneDxBom() + assert.NoError(t, err) + + componentsIsSorted := sort.SliceIsSorted(*cdxBom.Components, func(i, j int) bool { + return (*cdxBom.Components)[i].BOMRef < (*cdxBom.Components)[j].BOMRef + }) + assert.True(t, componentsIsSorted) + + dependenciesIsSorted := sort.SliceIsSorted(*cdxBom.Dependencies, func(i, j int) bool { + return (*cdxBom.Dependencies)[i].Ref < (*cdxBom.Dependencies)[j].Ref + }) + assert.True(t, dependenciesIsSorted) + + for _, dep := range *cdxBom.Dependencies { + dependsOnIsSorted := sort.SliceIsSorted(*dep.Dependencies, func(i, j int) bool { + return (*dep.Dependencies)[i] < (*dep.Dependencies)[j] + }) + assert.True(t, dependsOnIsSorted) + } +}