From 89553d580ee2b0764a816db960c48cef69cdbd48 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 May 2024 13:26:12 +0600 Subject: [PATCH 1/3] fix(bom): use fs as root component if BOM doesn't exist --- pkg/sbom/io/encode.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index db9052f033dd..9672f1648dc6 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -83,8 +83,15 @@ func (e *Encoder) rootComponent(r types.Report) (*core.Component, error) { root.Type = core.TypeFilesystem case artifact.TypeRepository: root.Type = core.TypeRepository - case artifact.TypeCycloneDX: - return r.BOM.Root(), nil + case artifact.TypeCycloneDX, artifact.TypeSPDX: + // When we scan SBOM file + if r.BOM != nil { + return r.BOM.Root(), nil + } + // When we scan a `json` file (meaning a file in `json` format) which was created from the SBOM file. + // e.g. for use in `convert` mode. + // See https://github.com/aquasecurity/trivy/issues/6780 + root.Type = core.TypeFilesystem } if r.Metadata.Size != 0 { From 42e924a208134024083bc6a5d2ae62e41306ec73 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 May 2024 13:28:15 +0600 Subject: [PATCH 2/3] test(bom): add tests when BOM exists and doesn't exist --- pkg/sbom/io/encode_test.go | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index c6cc450da832..7951d847cd8a 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -20,6 +20,7 @@ func TestEncoder_Encode(t *testing.T) { tests := []struct { name string report types.Report + addBOMFunc func() *core.BOM wantComponents map[uuid.UUID]*core.Component wantRels map[uuid.UUID][]core.Relationship wantVulns map[uuid.UUID][]core.Vulnerability @@ -535,6 +536,97 @@ func TestEncoder_Encode(t *testing.T) { }, wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, + { + name: "SBOM file", + addBOMFunc: newTestBOM, + report: types.Report{ + SchemaVersion: 2, + ArtifactName: "report.cdx.json", + ArtifactType: artifact.TypeCycloneDX, + Results: []types.Result{ + { + Target: "Java", + Type: ftypes.Jar, + Class: types.ClassLangPkg, + Packages: []ftypes.Package{ + { + ID: "org.apache.logging.log4j:log4j-core:2.23.1", + Name: "org.apache.logging.log4j:log4j-core", + Version: "2.23.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.logging.log4j", + Name: "log4j-core", + Version: "2.23.1", + }, + }, + FilePath: "log4j-core-2.23.1.jar", + }, + }, + }, + }, + }, + wantComponents: map[uuid.UUID]*core.Component{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): appComponent, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, + }, + wantRels: map[uuid.UUID][]core.Relationship{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"), + Type: core.RelationshipContains, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): nil, + }, + wantVulns: make(map[uuid.UUID][]core.Vulnerability), + }, + { + name: "json file created from SBOM file (BOM is empty)", + report: types.Report{ + SchemaVersion: 2, + ArtifactName: "report.cdx.json", + ArtifactType: artifact.TypeCycloneDX, + Results: []types.Result{ + { + Target: "Java", + Type: ftypes.Jar, + Class: types.ClassLangPkg, + Packages: []ftypes.Package{ + { + ID: "org.apache.logging.log4j:log4j-core:2.23.1", + Name: "org.apache.logging.log4j:log4j-core", + Version: "2.23.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.logging.log4j", + Name: "log4j-core", + Version: "2.23.1", + }, + }, + FilePath: "log4j-core-2.23.1.jar", + }, + }, + }, + }, + }, + wantComponents: map[uuid.UUID]*core.Component{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): fsComponent, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, + }, + wantRels: map[uuid.UUID][]core.Relationship{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"), + Type: core.RelationshipContains, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): nil, + }, + wantVulns: make(map[uuid.UUID][]core.Vulnerability), + }, { name: "invalid digest", report: types.Report{ @@ -562,6 +654,9 @@ func TestEncoder_Encode(t *testing.T) { t.Run(tt.name, func(t *testing.T) { uuid.SetFakeUUID(t, "3ff14136-e09f-4df9-80ea-%012d") + if tt.addBOMFunc != nil { + tt.report.BOM = tt.addBOMFunc() + } opts := core.Options{GenerateBOMRef: true} got, err := sbomio.NewEncoder(opts).Encode(tt.report) if tt.wantErr != "" { @@ -580,3 +675,65 @@ func TestEncoder_Encode(t *testing.T) { }) } } + +var ( + appComponent = &core.Component{ + Root: true, + Type: core.TypeApplication, + Name: "log4j-core-2.23.1.jar", + } + fsComponent = &core.Component{ + Root: true, + Type: core.TypeFilesystem, + Name: "report.cdx.json", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "3ff14136-e09f-4df9-80ea-000000000001", + }, + Properties: core.Properties{ + { + Name: "SchemaVersion", + Value: "2", + }, + }, + } + libComponent = &core.Component{ + Type: core.TypeLibrary, + Name: "log4j-core", + Group: "org.apache.logging.log4j", + Version: "2.23.1", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "pkg:maven/org.apache.logging.log4j/log4j-core@2.23.1", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.logging.log4j", + Name: "log4j-core", + Version: "2.23.1", + }, + }, + Files: []core.File{ + { + Path: "log4j-core-2.23.1.jar", + }, + }, + Properties: core.Properties{ + { + Name: "FilePath", + Value: "log4j-core-2.23.1.jar", + }, + { + Name: "PkgID", + Value: "org.apache.logging.log4j:log4j-core:2.23.1", + }, + { + Name: "PkgType", + Value: "jar", + }, + }, + } +) + +func newTestBOM() *core.BOM { + bom := core.NewBOM(core.Options{}) + bom.AddComponent(appComponent) + return bom +} From 068b89048a50e53075546e18fef94104d5c710aa Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 30 May 2024 09:50:49 +0600 Subject: [PATCH 3/3] refactor(test): create one more `SetFakeUUID` to newTestBOM --- pkg/sbom/io/encode_test.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 7951d847cd8a..d165b64c3e80 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -20,7 +20,6 @@ func TestEncoder_Encode(t *testing.T) { tests := []struct { name string report types.Report - addBOMFunc func() *core.BOM wantComponents map[uuid.UUID]*core.Component wantRels map[uuid.UUID][]core.Relationship wantVulns map[uuid.UUID][]core.Vulnerability @@ -537,8 +536,7 @@ func TestEncoder_Encode(t *testing.T) { wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, { - name: "SBOM file", - addBOMFunc: newTestBOM, + name: "SBOM file", report: types.Report{ SchemaVersion: 2, ArtifactName: "report.cdx.json", @@ -566,19 +564,20 @@ func TestEncoder_Encode(t *testing.T) { }, }, }, + BOM: newTestBOM(t), }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): appComponent, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, + uuid.MustParse("2ff14136-e09f-4df9-80ea-000000000001"): appComponent, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): libComponent, }, wantRels: map[uuid.UUID][]core.Relationship{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + uuid.MustParse("2ff14136-e09f-4df9-80ea-000000000001"): { { - Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"), + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"), Type: core.RelationshipContains, }, }, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): nil, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): nil, }, wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, @@ -654,9 +653,6 @@ func TestEncoder_Encode(t *testing.T) { t.Run(tt.name, func(t *testing.T) { uuid.SetFakeUUID(t, "3ff14136-e09f-4df9-80ea-%012d") - if tt.addBOMFunc != nil { - tt.report.BOM = tt.addBOMFunc() - } opts := core.Options{GenerateBOMRef: true} got, err := sbomio.NewEncoder(opts).Encode(tt.report) if tt.wantErr != "" { @@ -732,7 +728,8 @@ var ( } ) -func newTestBOM() *core.BOM { +func newTestBOM(t *testing.T) *core.BOM { + uuid.SetFakeUUID(t, "2ff14136-e09f-4df9-80ea-%012d") bom := core.NewBOM(core.Options{}) bom.AddComponent(appComponent) return bom