From 73a0018cb3b371af026a22a00a64e48eb9811e51 Mon Sep 17 00:00:00 2001 From: afdesk Date: Wed, 14 Aug 2024 16:58:57 +0600 Subject: [PATCH 01/18] fix(sbom): export bom-ref --- pkg/sbom/io/encode.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 0be0bf361280..2658617aaf3c 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -377,8 +377,9 @@ func (*Encoder) component(result types.Result, pkg ftypes.Package) *core.Compone SrcVersion: utils.FormatSrcVersion(pkg), SrcFile: srcFile, PkgIdentifier: ftypes.PkgIdentifier{ - UID: pkg.Identifier.UID, - PURL: pkg.Identifier.PURL, + UID: pkg.Identifier.UID, + PURL: pkg.Identifier.PURL, + BOMRef: pkg.Identifier.BOMRef, }, Supplier: pkg.Maintainer, Licenses: pkg.Licenses, From f22f6b4974567d0ddc2e98072c216d7d3d7cc9b8 Mon Sep 17 00:00:00 2001 From: afdesk Date: Wed, 14 Aug 2024 17:41:59 +0600 Subject: [PATCH 02/18] fix tests --- pkg/sbom/cyclonedx/marshal_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index e778b803619c..a4c68bd1b93d 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -1557,7 +1557,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { }, Components: &[]cdx.Component{ { - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", Type: cdx.ComponentTypeLibrary, Group: "com.fasterxml.jackson.core", Name: "jackson-databind", @@ -1607,7 +1607,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { Updated: "2022-12-20T10:15:00+00:00", Affects: &[]cdx.Affects{ { - Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", Range: &[]cdx.AffectedVersions{ { Version: "2.13.4.1", @@ -1622,11 +1622,11 @@ func TestMarshaler_MarshalReport(t *testing.T) { { Ref: "aff65b54-6009-4c32-968d-748949ef46e8", Dependencies: &[]string{ - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", }, }, { - Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", Dependencies: lo.ToPtr([]string{}), }, }, From 0eebb2ac14ddfb12499948a2249d12ef3ca23a7f Mon Sep 17 00:00:00 2001 From: amf Date: Thu, 15 Aug 2024 17:34:05 +0600 Subject: [PATCH 03/18] remove file path --- pkg/sbom/cyclonedx/marshal_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index a4c68bd1b93d..8b88c4ec762a 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -1462,7 +1462,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { Name: "com.fasterxml.jackson.core:jackson-databind", Version: "2.13.4.1", Identifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", UID: "9A5066570222D04C", PURL: &packageurl.PackageURL{ Type: packageurl.TypeMaven, @@ -1480,7 +1480,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { PkgName: "com.fasterxml.jackson.core:jackson-databind", PkgPath: "jackson-databind-2.13.4.1.jar", PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", UID: "9A5066570222D04C", PURL: &packageurl.PackageURL{ Type: packageurl.TypeMaven, @@ -1557,7 +1557,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { }, Components: &[]cdx.Component{ { - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", Type: cdx.ComponentTypeLibrary, Group: "com.fasterxml.jackson.core", Name: "jackson-databind", @@ -1607,7 +1607,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { Updated: "2022-12-20T10:15:00+00:00", Affects: &[]cdx.Affects{ { - Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", Range: &[]cdx.AffectedVersions{ { Version: "2.13.4.1", @@ -1622,11 +1622,11 @@ func TestMarshaler_MarshalReport(t *testing.T) { { Ref: "aff65b54-6009-4c32-968d-748949ef46e8", Dependencies: &[]string{ - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", }, }, { - Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + Ref: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", Dependencies: lo.ToPtr([]string{}), }, }, From 46e10ac6458358071f0a29683ebb0f2bd6d08c4f Mon Sep 17 00:00:00 2001 From: afdesk Date: Sat, 17 Aug 2024 23:22:12 +0600 Subject: [PATCH 04/18] add test case --- integration/integration_test.go | 1 - integration/sbom_test.go | 12 ++ .../fixtures/sbom/pywin32-cyclonedx.json | 116 +++++++++++++++++ .../pywin32-cyclonedx.cdx.json.golden | 121 ++++++++++++++++++ 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 integration/testdata/fixtures/sbom/pywin32-cyclonedx.json create mode 100644 integration/testdata/pywin32-cyclonedx.cdx.json.golden diff --git a/integration/integration_test.go b/integration/integration_test.go index c263ec2fc51e..96c8f54a67e9 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -186,7 +186,6 @@ func readCycloneDX(t *testing.T, filePath string) *cdx.BOM { return (*bom.Components)[i].Name < (*bom.Components)[j].Name }) for i := range *bom.Components { - (*bom.Components)[i].BOMRef = "" sort.Slice(*(*bom.Components)[i].Properties, func(ii, jj int) bool { return (*(*bom.Components)[i].Properties)[ii].Name < (*(*bom.Components)[i].Properties)[jj].Name }) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index e3ee5b89cc3d..1dc77672eccd 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -25,6 +25,7 @@ func TestSBOM(t *testing.T) { name string args args golden string + fakeUUID string override OverrideFunc }{ { @@ -57,6 +58,16 @@ func TestSBOM(t *testing.T) { }, golden: "testdata/fluentd-multiple-lockfiles.json.golden", }, + { + name: "scan SBOM into SBOM", + args: args{ + input: "testdata/fixtures/sbom/pywin32-cyclonedx.json", + format: "cyclonedx", + artifactType: "cyclonedx", + }, + fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", + golden: "testdata/pywin32-cyclonedx.cdx.json.golden", + }, { name: "minikube KBOM", args: args{ @@ -165,6 +176,7 @@ func TestSBOM(t *testing.T) { // Run "trivy sbom" runTest(t, osArgs, tt.golden, outputFile, types.Format(tt.args.format), runOptions{ override: overrideFuncs(overrideSBOMReport, overrideUID, tt.override), + fakeUUID: tt.fakeUUID, }) }) } diff --git a/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json b/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json new file mode 100644 index 000000000000..2f539df74217 --- /dev/null +++ b/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json @@ -0,0 +1,116 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:b61985f0-720e-4ece-81cc-71f49db503b5", + "version": 1, + "metadata": { + "timestamp": "2024-08-01T19:19:56+00:00", + "tools": { + "components": [ + { + "type": "application", + "group": "aquasecurity", + "name": "trivy", + "version": "dev" + } + ] + }, + "component": { + "bom-ref": "d5461c73-cabf-4634-a4ef-489698717e3d", + "type": "application", + "name": ".", + "properties": [ + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + } + ] + } + }, + "components": [ + { + "bom-ref": "469bcf7c-b085-40cf-8932-d581cb91f11b", + "type": "application", + "name": "poetry.lock", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "poetry" + } + ] + }, + { + "bom-ref": "pkg:pypi/pywin32@227", + "type": "library", + "name": "pywin32", + "version": "227", + "purl": "pkg:pypi/pywin32@227", + "licenses": [ + { + "expression": "MIT" + } + ], + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "pywin32@227" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "poetry" + } + ] + }, + { + "bom-ref": "de3ojve0eoj0j0je", + "type": "library", + "name": "pywin32", + "version": "227", + "purl": "pkg:pypi/pywin32@227", + "licenses": [ + { + "expression": "MIT" + } + ], + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "pywin32@227" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "poetry" + } + ] + } + ], + "dependencies": [ + { + "ref": "469bcf7c-b085-40cf-8932-d581cb91f11b", + "dependsOn": [ + "pkg:pypi/pywin32@227", + "de3ojve0eoj0j0je" + ] + }, + { + "ref": "d5461c73-cabf-4634-a4ef-489698717e3d", + "dependsOn": [ + "469bcf7c-b085-40cf-8932-d581cb91f11b" + ] + }, + { + "ref": "pkg:pypi/pywin32@227", + "dependsOn": [] + }, + { + "ref": "de3ojve0eoj0j0je", + "dependsOn": [] + } + ], + "vulnerabilities": [] +} \ No newline at end of file diff --git a/integration/testdata/pywin32-cyclonedx.cdx.json.golden b/integration/testdata/pywin32-cyclonedx.cdx.json.golden new file mode 100644 index 000000000000..56dad65303ad --- /dev/null +++ b/integration/testdata/pywin32-cyclonedx.cdx.json.golden @@ -0,0 +1,121 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000008", + "version": 1, + "metadata": { + "timestamp": "2021-08-25T12:20:30+00:00", + "tools": { + "components": [ + { + "type": "application", + "group": "aquasecurity", + "name": "trivy", + "version": "dev" + } + ] + }, + "component": { + "bom-ref": "d5461c73-cabf-4634-a4ef-489698717e3d", + "type": "application", + "name": ".", + "purl": "pkg:/", + "properties": [ + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + } + ] + } + }, + "components": [ + { + "bom-ref": "3ff14136-e09f-4df9-80ea-000000000005", + "type": "application", + "name": "poetry.lock", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "poetry" + } + ] + }, + { + "bom-ref": "de3ojve0eoj0j0je", + "type": "library", + "name": "pywin32", + "version": "227", + "licenses": [ + { + "license": { + "name": "MIT" + } + } + ], + "purl": "pkg:pypi/pywin32@227", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "pywin32@227" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "poetry" + } + ] + }, + { + "bom-ref": "pkg:pypi/pywin32@227", + "type": "library", + "name": "pywin32", + "version": "227", + "licenses": [ + { + "license": { + "name": "MIT" + } + } + ], + "purl": "pkg:pypi/pywin32@227", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "pywin32@227" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "poetry" + } + ] + } + ], + "dependencies": [ + { + "ref": "3ff14136-e09f-4df9-80ea-000000000005", + "dependsOn": [ + "de3ojve0eoj0j0je", + "pkg:pypi/pywin32@227" + ] + }, + { + "ref": "d5461c73-cabf-4634-a4ef-489698717e3d", + "dependsOn": [ + "3ff14136-e09f-4df9-80ea-000000000005" + ] + }, + { + "ref": "de3ojve0eoj0j0je", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/pywin32@227", + "dependsOn": [] + } + ], + "vulnerabilities": [] +} From 5cb120b092092a8034183a3d15002a2c1cd0b7ea Mon Sep 17 00:00:00 2001 From: afdesk Date: Thu, 22 Aug 2024 00:27:47 +0600 Subject: [PATCH 05/18] fix: update test data --- integration/sbom_test.go | 4 +- .../fixtures/sbom/pywin32-cyclonedx.json | 116 ---- ...d-multiple-lockfiles-short.cdx.json.golden | 527 ++++++++++++++++++ .../pywin32-cyclonedx.cdx.json.golden | 121 ---- 4 files changed, 529 insertions(+), 239 deletions(-) delete mode 100644 integration/testdata/fixtures/sbom/pywin32-cyclonedx.json create mode 100644 integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden delete mode 100644 integration/testdata/pywin32-cyclonedx.cdx.json.golden diff --git a/integration/sbom_test.go b/integration/sbom_test.go index 1dc77672eccd..e887f1520e68 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -61,12 +61,12 @@ func TestSBOM(t *testing.T) { { name: "scan SBOM into SBOM", args: args{ - input: "testdata/fixtures/sbom/pywin32-cyclonedx.json", + input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json", format: "cyclonedx", artifactType: "cyclonedx", }, fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", - golden: "testdata/pywin32-cyclonedx.cdx.json.golden", + golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", }, { name: "minikube KBOM", diff --git a/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json b/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json deleted file mode 100644 index 2f539df74217..000000000000 --- a/integration/testdata/fixtures/sbom/pywin32-cyclonedx.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", - "bomFormat": "CycloneDX", - "specVersion": "1.6", - "serialNumber": "urn:uuid:b61985f0-720e-4ece-81cc-71f49db503b5", - "version": 1, - "metadata": { - "timestamp": "2024-08-01T19:19:56+00:00", - "tools": { - "components": [ - { - "type": "application", - "group": "aquasecurity", - "name": "trivy", - "version": "dev" - } - ] - }, - "component": { - "bom-ref": "d5461c73-cabf-4634-a4ef-489698717e3d", - "type": "application", - "name": ".", - "properties": [ - { - "name": "aquasecurity:trivy:SchemaVersion", - "value": "2" - } - ] - } - }, - "components": [ - { - "bom-ref": "469bcf7c-b085-40cf-8932-d581cb91f11b", - "type": "application", - "name": "poetry.lock", - "properties": [ - { - "name": "aquasecurity:trivy:Class", - "value": "lang-pkgs" - }, - { - "name": "aquasecurity:trivy:Type", - "value": "poetry" - } - ] - }, - { - "bom-ref": "pkg:pypi/pywin32@227", - "type": "library", - "name": "pywin32", - "version": "227", - "purl": "pkg:pypi/pywin32@227", - "licenses": [ - { - "expression": "MIT" - } - ], - "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "pywin32@227" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "poetry" - } - ] - }, - { - "bom-ref": "de3ojve0eoj0j0je", - "type": "library", - "name": "pywin32", - "version": "227", - "purl": "pkg:pypi/pywin32@227", - "licenses": [ - { - "expression": "MIT" - } - ], - "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "pywin32@227" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "poetry" - } - ] - } - ], - "dependencies": [ - { - "ref": "469bcf7c-b085-40cf-8932-d581cb91f11b", - "dependsOn": [ - "pkg:pypi/pywin32@227", - "de3ojve0eoj0j0je" - ] - }, - { - "ref": "d5461c73-cabf-4634-a4ef-489698717e3d", - "dependsOn": [ - "469bcf7c-b085-40cf-8932-d581cb91f11b" - ] - }, - { - "ref": "pkg:pypi/pywin32@227", - "dependsOn": [] - }, - { - "ref": "de3ojve0eoj0j0je", - "dependsOn": [] - } - ], - "vulnerabilities": [] -} \ No newline at end of file diff --git a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden new file mode 100644 index 000000000000..89f40d3e3c52 --- /dev/null +++ b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden @@ -0,0 +1,527 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000010", + "version": 1, + "metadata": { + "timestamp": "2021-08-25T12:20:30+00:00", + "tools": { + "components": [ + { + "type": "application", + "group": "aquasecurity", + "name": "trivy", + "version": "dev" + } + ] + }, + "component": { + "bom-ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", + "type": "container", + "name": "integration/testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz", + "purl": "pkg:/", + "properties": [ + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:02874b2b269dea8dde0f7edb4c9906904dfe38a09de1a214f20c650cfb15c60e" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:25165eb51d15842f870f97873e0a58409d5e860e6108e3dd829bd10e484c0065" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:3752e1f6fd759c795c13aff2c93c081529366e27635ba6621e849b0f9cfc77f0" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:788c00e2cfc8f2a018ae4344ccf0b2c226ebd756d7effd1ce50eea1a4252cd89" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" + }, + { + "name": "aquasecurity:trivy:ImageID", + "value": "sha256:5a992077baba51b97f27591a10d54d2f2723dc9c81a3fe419e261023f2554933" + }, + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + } + ] + } + }, + "components": [ + { + "bom-ref": "3ff14136-e09f-4df9-80ea-000000000006", + "type": "operating-system", + "name": "debian", + "version": "10.2", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "debian" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "type": "library", + "name": "bash", + "version": "5.0-4", + "purl": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "bash@5.0-4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "bash" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "5.0-4" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "type": "library", + "name": "libidn2-0", + "version": "2.0.5-1", + "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "libidn2-0@2.0.5-1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "libidn2" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2.0.5-1" + } + ] + }, + { + "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "type": "library", + "name": "activesupport", + "version": "6.0.2.1", + "licenses": [ + { + "license": { + "name": "MIT" + } + } + ], + "purl": "pkg:gem/activesupport@6.0.2.1", + "properties": [ + { + "name": "aquasecurity:trivy:FilePath", + "value": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "activesupport@6.0.2.1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gemspec" + } + ] + } + ], + "dependencies": [ + { + "ref": "3ff14136-e09f-4df9-80ea-000000000006", + "dependsOn": [ + "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2" + ] + }, + { + "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", + "dependsOn": [ + "3ff14136-e09f-4df9-80ea-000000000006", + "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" + ] + }, + { + "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "dependsOn": [] + } + ], + "vulnerabilities": [ + { + "id": "CVE-2019-18224", + "source": { + "name": "debian", + "url": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "ratings": [ + { + "source": { + "name": "amazon" + }, + "severity": "medium" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.5, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P" + }, + { + "source": { + "name": "nvd" + }, + "score": 9.8, + "severity": "critical", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "redhat" + }, + "score": 5.6, + "severity": "medium", + "method": "CVSSv3", + "vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L" + }, + { + "source": { + "name": "ubuntu" + }, + "severity": "medium" + } + ], + "cwes": [ + 787 + ], + "description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.", + "recommendation": "Upgrade libidn2-0 to version 2.0.5-1+deb10u1", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2019-18224" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2019-18224" + }, + { + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420" + }, + { + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224" + }, + { + "url": "https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c" + }, + { + "url": "https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1" + }, + { + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/" + }, + { + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/" + }, + { + "url": "https://seclists.org/bugtraq/2020/Feb/4" + }, + { + "url": "https://security.gentoo.org/glsa/202003-63" + }, + { + "url": "https://ubuntu.com/security/notices/USN-4168-1" + }, + { + "url": "https://usn.ubuntu.com/4168-1/" + }, + { + "url": "https://www.debian.org/security/2020/dsa-4613" + } + ], + "published": "2019-10-21T17:15:00+00:00", + "updated": "2019-10-29T19:15:00+00:00", + "affects": [ + { + "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "versions": [ + { + "version": "2.0.5-1", + "status": "affected" + } + ] + } + ] + }, + { + "id": "CVE-2019-18276", + "source": { + "name": "debian", + "url": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "ratings": [ + { + "source": { + "name": "cbl-mariner" + }, + "severity": "high" + }, + { + "source": { + "name": "debian" + }, + "severity": "low" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.2, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.8, + "severity": "high", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "oracle-oval" + }, + "severity": "low" + }, + { + "source": { + "name": "photon" + }, + "severity": "high" + }, + { + "source": { + "name": "redhat" + }, + "score": 7.8, + "severity": "low", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "ubuntu" + }, + "severity": "low" + } + ], + "cwes": [ + 273 + ], + "description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2019-18276" + }, + { + "url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2019-18276" + }, + { + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276" + }, + { + "url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff" + }, + { + "url": "https://linux.oracle.com/cve/CVE-2019-18276.html" + }, + { + "url": "https://linux.oracle.com/errata/ELSA-2021-1679.html" + }, + { + "url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E" + }, + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276" + }, + { + "url": "https://security.gentoo.org/glsa/202105-34" + }, + { + "url": "https://security.netapp.com/advisory/ntap-20200430-0003/" + }, + { + "url": "https://www.youtube.com/watch?v=-wGtxJ8opa8" + } + ], + "published": "2019-11-28T01:15:00+00:00", + "updated": "2021-05-26T12:15:00+00:00", + "affects": [ + { + "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "versions": [ + { + "version": "5.0-4", + "status": "affected" + } + ] + } + ] + }, + { + "id": "CVE-2020-8165", + "source": { + "name": "ghsa", + "url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems" + }, + "ratings": [ + { + "source": { + "name": "ghsa" + }, + "severity": "high" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.5, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P" + }, + { + "source": { + "name": "nvd" + }, + "score": 9.8, + "severity": "critical", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "redhat" + }, + "score": 9.8, + "severity": "high", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "cwes": [ + 502 + ], + "description": "A deserialization of untrusted data vulnerability exists in rails < 5.2.4.3, rails < 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.", + "recommendation": "Upgrade activesupport to version 6.0.3.1, 5.2.4.3", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2020-8165" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2020-8165" + }, + { + "url": "https://github.com/advisories/GHSA-2p68-f74v-9wc6" + }, + { + "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml" + }, + { + "url": "https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ" + }, + { + "url": "https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c" + }, + { + "url": "https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c" + }, + { + "url": "https://hackerone.com/reports/413388" + }, + { + "url": "https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html" + }, + { + "url": "https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html" + }, + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-8165" + }, + { + "url": "https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/" + }, + { + "url": "https://www.debian.org/security/2020/dsa-4766" + } + ], + "published": "2020-06-19T18:15:00+00:00", + "updated": "2020-10-17T12:15:00+00:00", + "affects": [ + { + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "versions": [ + { + "version": "6.0.2.1", + "status": "affected" + } + ] + } + ] + } + ] +} diff --git a/integration/testdata/pywin32-cyclonedx.cdx.json.golden b/integration/testdata/pywin32-cyclonedx.cdx.json.golden deleted file mode 100644 index 56dad65303ad..000000000000 --- a/integration/testdata/pywin32-cyclonedx.cdx.json.golden +++ /dev/null @@ -1,121 +0,0 @@ -{ - "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", - "bomFormat": "CycloneDX", - "specVersion": "1.6", - "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000008", - "version": 1, - "metadata": { - "timestamp": "2021-08-25T12:20:30+00:00", - "tools": { - "components": [ - { - "type": "application", - "group": "aquasecurity", - "name": "trivy", - "version": "dev" - } - ] - }, - "component": { - "bom-ref": "d5461c73-cabf-4634-a4ef-489698717e3d", - "type": "application", - "name": ".", - "purl": "pkg:/", - "properties": [ - { - "name": "aquasecurity:trivy:SchemaVersion", - "value": "2" - } - ] - } - }, - "components": [ - { - "bom-ref": "3ff14136-e09f-4df9-80ea-000000000005", - "type": "application", - "name": "poetry.lock", - "properties": [ - { - "name": "aquasecurity:trivy:Class", - "value": "lang-pkgs" - }, - { - "name": "aquasecurity:trivy:Type", - "value": "poetry" - } - ] - }, - { - "bom-ref": "de3ojve0eoj0j0je", - "type": "library", - "name": "pywin32", - "version": "227", - "licenses": [ - { - "license": { - "name": "MIT" - } - } - ], - "purl": "pkg:pypi/pywin32@227", - "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "pywin32@227" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "poetry" - } - ] - }, - { - "bom-ref": "pkg:pypi/pywin32@227", - "type": "library", - "name": "pywin32", - "version": "227", - "licenses": [ - { - "license": { - "name": "MIT" - } - } - ], - "purl": "pkg:pypi/pywin32@227", - "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "pywin32@227" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "poetry" - } - ] - } - ], - "dependencies": [ - { - "ref": "3ff14136-e09f-4df9-80ea-000000000005", - "dependsOn": [ - "de3ojve0eoj0j0je", - "pkg:pypi/pywin32@227" - ] - }, - { - "ref": "d5461c73-cabf-4634-a4ef-489698717e3d", - "dependsOn": [ - "3ff14136-e09f-4df9-80ea-000000000005" - ] - }, - { - "ref": "de3ojve0eoj0j0je", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/pywin32@227", - "dependsOn": [] - } - ], - "vulnerabilities": [] -} From 4e42d28a8b34c5a9d20d82961d8dd9ec6690a7e6 Mon Sep 17 00:00:00 2001 From: afdesk Date: Thu, 29 Aug 2024 12:42:48 +0600 Subject: [PATCH 06/18] test: keep the same uid --- integration/sbom_test.go | 5 +---- .../fluentd-multiple-lockfiles-short.cdx.json.golden | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index e887f1520e68..2a3f51bf2d09 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -25,7 +25,6 @@ func TestSBOM(t *testing.T) { name string args args golden string - fakeUUID string override OverrideFunc }{ { @@ -65,8 +64,7 @@ func TestSBOM(t *testing.T) { format: "cyclonedx", artifactType: "cyclonedx", }, - fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", - golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", + golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", }, { name: "minikube KBOM", @@ -176,7 +174,6 @@ func TestSBOM(t *testing.T) { // Run "trivy sbom" runTest(t, osArgs, tt.golden, outputFile, types.Format(tt.args.format), runOptions{ override: overrideFuncs(overrideSBOMReport, overrideUID, tt.override), - fakeUUID: tt.fakeUUID, }) }) } diff --git a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden index 89f40d3e3c52..169270c7100d 100644 --- a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden @@ -59,7 +59,7 @@ }, "components": [ { - "bom-ref": "3ff14136-e09f-4df9-80ea-000000000006", + "bom-ref": "353f2470-9c8b-4647-9d0d-96d893838dc8", "type": "operating-system", "name": "debian", "version": "10.2", From 61486f3a56a569e0ffd20e73ba56399b3c3d872f Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 30 Aug 2024 13:51:37 +0600 Subject: [PATCH 07/18] fix: keep existing BOM-ref --- integration/sbom_test.go | 5 ++++- ...td-multiple-lockfiles-short.cdx.json.golden | 5 ++--- pkg/sbom/cyclonedx/unmarshal.go | 7 ++++--- pkg/sbom/io/encode.go | 18 ++++++++++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index 2a3f51bf2d09..e887f1520e68 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -25,6 +25,7 @@ func TestSBOM(t *testing.T) { name string args args golden string + fakeUUID string override OverrideFunc }{ { @@ -64,7 +65,8 @@ func TestSBOM(t *testing.T) { format: "cyclonedx", artifactType: "cyclonedx", }, - golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", + fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", + golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", }, { name: "minikube KBOM", @@ -174,6 +176,7 @@ func TestSBOM(t *testing.T) { // Run "trivy sbom" runTest(t, osArgs, tt.golden, outputFile, types.Format(tt.args.format), runOptions{ override: overrideFuncs(overrideSBOMReport, overrideUID, tt.override), + fakeUUID: tt.fakeUUID, }) }) } diff --git a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden index 169270c7100d..496ca8ae3110 100644 --- a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden @@ -20,7 +20,6 @@ "bom-ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "type": "container", "name": "integration/testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz", - "purl": "pkg:/", "properties": [ { "name": "aquasecurity:trivy:DiffID", @@ -155,7 +154,7 @@ ], "dependencies": [ { - "ref": "3ff14136-e09f-4df9-80ea-000000000006", + "ref": "353f2470-9c8b-4647-9d0d-96d893838dc8", "dependsOn": [ "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2" @@ -164,7 +163,7 @@ { "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "dependsOn": [ - "3ff14136-e09f-4df9-80ea-000000000006", + "353f2470-9c8b-4647-9d0d-96d893838dc8", "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" ] }, diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index 71a0ee27b640..7b49dc0f580e 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -129,9 +129,10 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { } // Parse PURL - var purl packageurl.PackageURL + var purl *packageurl.PackageURL if c.PackageURL != "" { - purl, err = packageurl.FromString(c.PackageURL) + purl = &packageurl.PackageURL{} + *purl, err = packageurl.FromString(c.PackageURL) if err != nil { return nil, xerrors.Errorf("failed to parse PURL: %w", err) } @@ -149,7 +150,7 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { }, }, PkgIdentifier: ftypes.PkgIdentifier{ - PURL: &purl, + PURL: purl, BOMRef: c.BOMRef, }, Supplier: b.unmarshalSupplier(c.Supplier), diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 2658617aaf3c..642bf239e7c9 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -5,6 +5,7 @@ import ( "slices" "strconv" + "github.com/google/uuid" "github.com/package-url/packageurl-go" "github.com/samber/lo" "golang.org/x/xerrors" @@ -19,8 +20,9 @@ import ( ) type Encoder struct { - bom *core.BOM - opts core.Options + bom *core.BOM + opts core.Options + components map[uuid.UUID]*core.Component } func NewEncoder(opts core.Options) *Encoder { @@ -28,6 +30,9 @@ func NewEncoder(opts core.Options) *Encoder { } func (e *Encoder) Encode(report types.Report) (*core.BOM, error) { + if report.BOM != nil { + e.components = report.BOM.Components() + } // Metadata component root, err := e.rootComponent(report) if err != nil { @@ -283,6 +288,15 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound component.Type = core.TypeApplication } + // try to look for BOM-ref for this component + for _, c := range e.components { + if c.Name == component.Name { + component.PkgIdentifier = + c.PkgIdentifier + break + } + } + e.bom.AddRelationship(root, component, core.RelationshipContains) return component } From 6067d5f573dbca96a898181efa21913444b1a039 Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 30 Aug 2024 13:55:16 +0600 Subject: [PATCH 08/18] add: a check --- pkg/sbom/io/encode.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 642bf239e7c9..5fc3489606dd 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -290,9 +290,8 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound // try to look for BOM-ref for this component for _, c := range e.components { - if c.Name == component.Name { - component.PkgIdentifier = - c.PkgIdentifier + if c.Name == component.Name && c.Type == component.Type { + component.PkgIdentifier = c.PkgIdentifier break } } From 0a5090f1751bda44bf0c7bc45b9634e76c394888 Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 30 Aug 2024 16:30:20 +0600 Subject: [PATCH 09/18] refactor: look for SBOM ref only for Os and App layers --- pkg/sbom/io/encode.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 5fc3489606dd..975b98d40b10 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -262,6 +262,16 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { } } +// existedPkgIdentifier tries to look for package identifier (BOM-ref, PURL) by component name and component type +func (e *Encoder) existedPkgIdentifier(name string, componentType core.ComponentType) ftypes.PkgIdentifier { + for _, c := range e.components { + if c.Name == name && c.Type == componentType { + return c.PkgIdentifier + } + } + return ftypes.PkgIdentifier{} +} + func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound *ftypes.OS) *core.Component { component := &core.Component{ Name: r.Target, @@ -284,16 +294,10 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound component.Version = osFound.Name } component.Type = core.TypeOS + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) case types.ClassLangPkg: component.Type = core.TypeApplication - } - - // try to look for BOM-ref for this component - for _, c := range e.components { - if c.Name == component.Name && c.Type == component.Type { - component.PkgIdentifier = c.PkgIdentifier - break - } + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) } e.bom.AddRelationship(root, component, core.RelationshipContains) From eaaf98b9d607fbc7d171b9d76f2a29015e482f34 Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 30 Aug 2024 16:50:19 +0600 Subject: [PATCH 10/18] refactor --- pkg/sbom/cyclonedx/unmarshal.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index 7b49dc0f580e..efa47a65f6a9 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -128,14 +128,17 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { return nil, xerrors.Errorf("failed to unmarshal component type: %w", err) } + identifier := ftypes.PkgIdentifier{ + BOMRef: c.BOMRef, + } + // Parse PURL - var purl *packageurl.PackageURL if c.PackageURL != "" { - purl = &packageurl.PackageURL{} - *purl, err = packageurl.FromString(c.PackageURL) + purl, err := packageurl.FromString(c.PackageURL) if err != nil { return nil, xerrors.Errorf("failed to parse PURL: %w", err) } + identifier.PURL = &purl } component := &core.Component{ @@ -149,12 +152,9 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { Digests: b.unmarshalHashes(c.Hashes), }, }, - PkgIdentifier: ftypes.PkgIdentifier{ - PURL: purl, - BOMRef: c.BOMRef, - }, - Supplier: b.unmarshalSupplier(c.Supplier), - Properties: b.unmarshalProperties(c.Properties), + PkgIdentifier: identifier, + Supplier: b.unmarshalSupplier(c.Supplier), + Properties: b.unmarshalProperties(c.Properties), } return component, nil From 418100c2f525773e95193a6e1f8b32b4d12bfe7b Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Fri, 13 Sep 2024 12:00:07 +0400 Subject: [PATCH 11/18] refactor: reuse the parsed SBOM Signed-off-by: knqyf263 --- pkg/sbom/core/bom.go | 8 ++++++++ pkg/sbom/io/encode.go | 39 +++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/pkg/sbom/core/bom.go b/pkg/sbom/core/bom.go index c0a082d013b5..d6ee429a0576 100644 --- a/pkg/sbom/core/bom.go +++ b/pkg/sbom/core/bom.go @@ -269,6 +269,10 @@ func (b *BOM) AddRelationship(parent, child *Component, relationshipType Relatio } } +func (b *BOM) AddVulnerability(c *Component, vuln Vulnerability) { + b.vulnerabilities[c.id] = append(b.vulnerabilities[c.id], vuln) +} + func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { if c.id == uuid.Nil { b.AddComponent(c) @@ -279,6 +283,10 @@ func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { b.vulnerabilities[c.id] = vulns } +func (b *BOM) ClearVulnerabilities() { + b.vulnerabilities = make(map[uuid.UUID][]Vulnerability) +} + func (b *BOM) Root() *Component { root, ok := b.components[b.rootID] if !ok { diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 975b98d40b10..a91ae2965036 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -20,9 +20,8 @@ import ( ) type Encoder struct { - bom *core.BOM - opts core.Options - components map[uuid.UUID]*core.Component + bom *core.BOM + opts core.Options } func NewEncoder(opts core.Options) *Encoder { @@ -31,7 +30,7 @@ func NewEncoder(opts core.Options) *Encoder { func (e *Encoder) Encode(report types.Report) (*core.BOM, error) { if report.BOM != nil { - e.components = report.BOM.Components() + return e.reuseBOM(report) } // Metadata component root, err := e.rootComponent(report) @@ -262,16 +261,6 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { } } -// existedPkgIdentifier tries to look for package identifier (BOM-ref, PURL) by component name and component type -func (e *Encoder) existedPkgIdentifier(name string, componentType core.ComponentType) ftypes.PkgIdentifier { - for _, c := range e.components { - if c.Name == name && c.Type == componentType { - return c.PkgIdentifier - } - } - return ftypes.PkgIdentifier{} -} - func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound *ftypes.OS) *core.Component { component := &core.Component{ Name: r.Target, @@ -294,10 +283,8 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound component.Version = osFound.Name } component.Type = core.TypeOS - component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) case types.ClassLangPkg: component.Type = core.TypeApplication - component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) } e.bom.AddRelationship(root, component, core.RelationshipContains) @@ -446,6 +433,26 @@ func (*Encoder) belongToParent(pkg ftypes.Package, parents map[string]ftypes.Pac } } +func (e *Encoder) reuseBOM(report types.Report) (*core.BOM, error) { + report.BOM.ClearVulnerabilities() + + // Group components by BOM-Ref + components := lo.MapKeys(report.BOM.Components(), func(value *core.Component, _ uuid.UUID) string { + return value.PkgIdentifier.BOMRef + }) + + for _, result := range report.Results { + for _, vuln := range result.Vulnerabilities { + c, ok := components[vuln.PkgIdentifier.BOMRef] + if !ok || c == nil { + continue + } + report.BOM.AddVulnerability(c, e.vulnerability(vuln)) + } + } + return report.BOM, nil +} + func filterProperties(props []core.Property) []core.Property { return lo.Filter(props, func(property core.Property, _ int) bool { return !(property.Value == "" || (property.Name == core.PropertySrcEpoch && property.Value == "0")) From 0bb63875c419f12e50f6b2135b54cfe3b91ac791 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Fri, 13 Sep 2024 12:00:56 +0400 Subject: [PATCH 12/18] test: add appropriate parsed BOMs Signed-off-by: knqyf263 --- integration/sbom_test.go | 4 +- .../fluentd-multiple-lockfiles-cyclonedx.json | 6 +- ...multiple-lockfiles-reused.cdx.json.golden} | 64 +++---- .../fluentd-multiple-lockfiles.json.golden | 2 +- pkg/sbom/cyclonedx/marshal_test.go | 160 +++++++++++------- pkg/sbom/io/encode_test.go | 82 +++++---- pkg/vex/vex_test.go | 34 ++-- 7 files changed, 197 insertions(+), 155 deletions(-) rename integration/testdata/{fluentd-multiple-lockfiles-short.cdx.json.golden => fluentd-multiple-lockfiles-reused.cdx.json.golden} (91%) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index e887f1520e68..1d39ca0d254b 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -59,14 +59,14 @@ func TestSBOM(t *testing.T) { golden: "testdata/fluentd-multiple-lockfiles.json.golden", }, { - name: "scan SBOM into SBOM", + name: "scan CycloneDX into CycloneDX", args: args{ input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json", format: "cyclonedx", artifactType: "cyclonedx", }, fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", - golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", + golden: "testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden", }, { name: "minikube KBOM", diff --git a/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json b/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json index f5db904207d1..82d711cd909c 100644 --- a/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json +++ b/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json @@ -120,7 +120,7 @@ ] }, { - "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "bom-ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", "type": "library", "name": "activesupport", "version": "6.0.2.1", @@ -163,8 +163,8 @@ { "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "dependsOn": [ - "353f2470-9c8b-4647-9d0d-96d893838dc8", - "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" + "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", + "353f2470-9c8b-4647-9d0d-96d893838dc8" ] } ] diff --git a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden similarity index 91% rename from integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden rename to integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden index 496ca8ae3110..c45912c976d3 100644 --- a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden @@ -2,7 +2,7 @@ "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.6", - "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000010", + "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000006", "version": 1, "metadata": { "timestamp": "2021-08-25T12:20:30+00:00", @@ -80,14 +80,6 @@ "version": "5.0-4", "purl": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "bash@5.0-4" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "debian" - }, { "name": "aquasecurity:trivy:SrcName", "value": "bash" @@ -95,6 +87,14 @@ { "name": "aquasecurity:trivy:SrcVersion", "value": "5.0-4" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c" + }, + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" } ] }, @@ -105,14 +105,6 @@ "version": "2.0.5-1", "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", "properties": [ - { - "name": "aquasecurity:trivy:PkgID", - "value": "libidn2-0@2.0.5-1" - }, - { - "name": "aquasecurity:trivy:PkgType", - "value": "debian" - }, { "name": "aquasecurity:trivy:SrcName", "value": "libidn2" @@ -120,11 +112,19 @@ { "name": "aquasecurity:trivy:SrcVersion", "value": "2.0.5-1" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c" + }, + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" } ] }, { - "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "bom-ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", "type": "library", "name": "activesupport", "version": "6.0.2.1", @@ -142,11 +142,15 @@ "value": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec" }, { - "name": "aquasecurity:trivy:PkgID", - "value": "activesupport@6.0.2.1" + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:a8877cad19f14a7044524a145ce33170085441a7922458017db1631dcd5f7602" + }, + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9" }, { - "name": "aquasecurity:trivy:PkgType", + "name": "aquasecurity:trivy:Type", "value": "gemspec" } ] @@ -163,21 +167,9 @@ { "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "dependsOn": [ - "353f2470-9c8b-4647-9d0d-96d893838dc8", - "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" + "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", + "353f2470-9c8b-4647-9d0d-96d893838dc8" ] - }, - { - "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", - "dependsOn": [] - }, - { - "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", - "dependsOn": [] - }, - { - "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", - "dependsOn": [] } ], "vulnerabilities": [ @@ -512,7 +504,7 @@ "updated": "2020-10-17T12:15:00+00:00", "affects": [ { - "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", "versions": [ { "version": "6.0.2.1", diff --git a/integration/testdata/fluentd-multiple-lockfiles.json.golden b/integration/testdata/fluentd-multiple-lockfiles.json.golden index fec0e1a39a0d..82241f14b60e 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.json.golden @@ -168,7 +168,7 @@ "PkgIdentifier": { "PURL": "pkg:gem/activesupport@6.0.2.1", "UID": "66a6de64809697cd", - "BOMRef": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" + "BOMRef": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b" }, "InstalledVersion": "6.0.2.1", "FixedVersion": "6.0.3.1, 5.2.4.3", diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index 8b88c4ec762a..396f1aa05fcf 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -65,21 +65,6 @@ var ( ) func TestMarshaler_MarshalReport(t *testing.T) { - testSBOM := core.NewBOM(core.Options{GenerateBOMRef: true}) - testSBOM.AddComponent(&core.Component{ - Root: true, - Type: core.TypeApplication, - Name: "jackson-databind-2.13.4.1.jar", - PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8", - }, - Properties: []core.Property{ - { - Name: "SchemaVersion", - Value: "2", - }, - }, - }) tests := []struct { name string @@ -1475,61 +1460,18 @@ func TestMarshaler_MarshalReport(t *testing.T) { }, }, Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2022-42003", - PkgName: "com.fasterxml.jackson.core:jackson-databind", - PkgPath: "jackson-databind-2.13.4.1.jar", - PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", - UID: "9A5066570222D04C", - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeMaven, - Namespace: "com.fasterxml.jackson.core", - Name: "jackson-databind", - Version: "2.13.4.1", - }, - }, - InstalledVersion: "2.13.4.1", - FixedVersion: "2.12.7.1, 2.13.4.2", - Status: dtypes.StatusFixed, - SeveritySource: "ghsa", - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2022-42003", - DataSource: &dtypes.DataSource{ - ID: vulnerability.GHSA, - Name: "GitHub Security Advisory Maven", - URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven", - }, - Vulnerability: dtypes.Vulnerability{ - Title: "jackson-databind: deep wrapper array nesting wrt UNWRAP_SINGLE_VALUE_ARRAYS", - Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.", - Severity: dtypes.SeverityHigh.String(), - VendorSeverity: dtypes.VendorSeverity{ - vulnerability.GHSA: dtypes.SeverityHigh, - }, - CVSS: dtypes.VendorCVSS{ - vulnerability.GHSA: dtypes.CVSS{ - V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - V3Score: 7.5, - }, - }, - References: []string{ - "https://access.redhat.com/security/cve/CVE-2022-42003", - }, - PublishedDate: lo.ToPtr(time.Date(2022, 10, 02, 05, 15, 0, 0, time.UTC)), - LastModifiedDate: lo.ToPtr(time.Date(2022, 12, 20, 10, 15, 0, 0, time.UTC)), - }, - }, + vuln1, }, }, }, - BOM: testSBOM, + BOM: testSBOM(), }, want: &cdx.BOM{ XMLNS: "http://cyclonedx.org/schema/bom/1.6", BOMFormat: "CycloneDX", SpecVersion: cdx.SpecVersion1_6, JSONSchema: "http://cyclonedx.org/schema/bom-1.6.schema.json", - SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000002", + SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000001", Version: 1, Metadata: &cdx.Metadata{ Timestamp: "2021-08-25T12:20:30+00:00", @@ -2110,3 +2052,99 @@ func TestMarshaler_MarshalReport(t *testing.T) { }) } } + +var ( + vuln1 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2022-42003", + PkgName: "com.fasterxml.jackson.core:jackson-databind", + PkgPath: "jackson-databind-2.13.4.1.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + UID: "9A5066570222D04C", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.13.4.1", + }, + }, + InstalledVersion: "2.13.4.1", + FixedVersion: "2.12.7.1, 2.13.4.2", + Status: dtypes.StatusFixed, + SeveritySource: "ghsa", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2022-42003", + DataSource: &dtypes.DataSource{ + ID: vulnerability.GHSA, + Name: "GitHub Security Advisory Maven", + URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven", + }, + Vulnerability: dtypes.Vulnerability{ + Title: "jackson-databind: deep wrapper array nesting wrt UNWRAP_SINGLE_VALUE_ARRAYS", + Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.", + Severity: dtypes.SeverityHigh.String(), + VendorSeverity: dtypes.VendorSeverity{ + vulnerability.GHSA: dtypes.SeverityHigh, + }, + CVSS: dtypes.VendorCVSS{ + vulnerability.GHSA: dtypes.CVSS{ + V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + V3Score: 7.5, + }, + }, + References: []string{ + "https://access.redhat.com/security/cve/CVE-2022-42003", + }, + PublishedDate: lo.ToPtr(time.Date(2022, 10, 02, 05, 15, 0, 0, time.UTC)), + LastModifiedDate: lo.ToPtr(time.Date(2022, 12, 20, 10, 15, 0, 0, time.UTC)), + }, + } +) + +func testSBOM() *core.BOM { + bom := core.NewBOM(core.Options{GenerateBOMRef: true}) + appComponent := &core.Component{ + Root: true, + Type: core.TypeApplication, + Name: "jackson-databind-2.13.4.1.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8", + }, + Properties: []core.Property{ + { + Name: "SchemaVersion", + Value: "2", + }, + }, + } + libComponent := &core.Component{ + Type: core.TypeLibrary, + Name: "jackson-databind", + Group: "com.fasterxml.jackson.core", + Version: "2.13.4.1", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + UID: "9A5066570222D04C", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.13.4.1", + }, + }, + Properties: []core.Property{ + { + Name: "FilePath", + Value: "jackson-databind-2.13.4.1.jar", + }, + { + Name: "PkgType", + Value: "jar", + }, + }, + } + bom.AddComponent(appComponent) + bom.AddComponent(libComponent) + bom.AddRelationship(appComponent, libComponent, core.RelationshipContains) + bom.AddRelationship(libComponent, nil, core.RelationshipDependsOn) + return bom +} diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 52fbed415933..223fb0027e11 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -5,6 +5,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/package-url/packageurl-go" + "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -703,22 +704,22 @@ func TestEncoder_Encode(t *testing.T) { BOM: newTestBOM(t), }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse("2ff14136-e09f-4df9-80ea-000000000001"): appComponent, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): libComponent, + uuid.MustParse(id1): &appComponent, + uuid.MustParse(id2): &libComponent, }, wantRels: map[uuid.UUID][]core.Relationship{ - uuid.MustParse("2ff14136-e09f-4df9-80ea-000000000001"): { + uuid.MustParse(id1): { { - Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"), + Dependency: uuid.MustParse(id2), Type: core.RelationshipContains, }, }, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): nil, + uuid.MustParse(id2): nil, }, wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, { - name: "SBOM file without root component", + name: "fill vulnerabilities in SBOM being scanned", report: types.Report{ SchemaVersion: 2, ArtifactName: "report.cdx.json", @@ -728,21 +729,12 @@ func TestEncoder_Encode(t *testing.T) { Target: "Java", Type: ftypes.Jar, Class: types.ClassLangPkg, - Packages: []ftypes.Package{ + Vulnerabilities: []types.DetectedVulnerability{ { - ID: "org.apache.logging.log4j:log4j-core:2.23.1", - Name: "org.apache.logging.log4j:log4j-core", - Version: "2.23.1", - Identifier: ftypes.PkgIdentifier{ - UID: "6C0AE96901617503", - 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", + VulnerabilityID: "CVE-2021-44228", + PkgName: libComponent.Name, + InstalledVersion: libComponent.Version, + PkgIdentifier: libComponent.PkgIdentifier, }, }, }, @@ -750,19 +742,18 @@ func TestEncoder_Encode(t *testing.T) { BOM: newTestBOM2(t), }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): fsComponent, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, + uuid.MustParse(id1): &libComponent, }, - wantRels: map[uuid.UUID][]core.Relationship{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + wantRels: map[uuid.UUID][]core.Relationship{}, + wantVulns: map[uuid.UUID][]core.Vulnerability{ + uuid.MustParse(id1): { { - Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"), - Type: core.RelationshipContains, + ID: "CVE-2021-44228", + PkgName: libComponent.Name, + InstalledVersion: libComponent.Version, }, }, - 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)", @@ -796,8 +787,8 @@ func TestEncoder_Encode(t *testing.T) { }, }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): fsComponent, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, + 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"): { @@ -847,7 +838,9 @@ func TestEncoder_Encode(t *testing.T) { require.Len(t, got.Components(), len(tt.wantComponents)) for id, want := range tt.wantComponents { - assert.EqualExportedValues(t, *want, *got.Components()[id], id) + gotComponent, ok := got.Components()[id] + require.True(t, ok, id) + assert.EqualExportedValues(t, *want, *gotComponent, id) } assert.Equal(t, tt.wantRels, got.Relationships()) @@ -856,13 +849,18 @@ func TestEncoder_Encode(t *testing.T) { } } +const ( + id1 = "2ff14136-e09f-4df9-80ea-000000000001" + id2 = "2ff14136-e09f-4df9-80ea-000000000002" +) + var ( - appComponent = &core.Component{ + appComponent = core.Component{ Root: true, Type: core.TypeApplication, Name: "log4j-core-2.23.1.jar", } - fsComponent = &core.Component{ + fsComponent = core.Component{ Root: true, Type: core.TypeFilesystem, Name: "report.cdx.json", @@ -876,7 +874,7 @@ var ( }, }, } - libComponent = &core.Component{ + libComponent = core.Component{ Type: core.TypeLibrary, Name: "log4j-core", Group: "org.apache.logging.log4j", @@ -915,15 +913,27 @@ var ( func newTestBOM(t *testing.T) *core.BOM { uuid.SetFakeUUID(t, "2ff14136-e09f-4df9-80ea-%012d") + + // Copy components + app := lo.ToPtr(appComponent) + lib := lo.ToPtr(libComponent) + bom := core.NewBOM(core.Options{}) - bom.AddComponent(appComponent) + bom.AddComponent(app) + bom.AddComponent(lib) + bom.AddRelationship(app, lib, core.RelationshipContains) + bom.AddRelationship(lib, nil, core.RelationshipDependsOn) return bom } // BOM without root component func newTestBOM2(t *testing.T) *core.BOM { uuid.SetFakeUUID(t, "2ff14136-e09f-4df9-80ea-%012d") + + // Copy components + lib := lo.ToPtr(libComponent) + bom := core.NewBOM(core.Options{}) - bom.AddComponent(libComponent) + bom.AddComponent(lib) return bom } diff --git a/pkg/vex/vex_test.go b/pkg/vex/vex_test.go index 4a9686972a5e..c989c608fccd 100644 --- a/pkg/vex/vex_test.go +++ b/pkg/vex/vex_test.go @@ -331,10 +331,7 @@ func TestFilter(t *testing.T) { args: args{ report: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: &core.BOM{ - SerialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", - Version: 1, - }, + BOM: cdxBOM("urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"), Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -352,10 +349,6 @@ func TestFilter(t *testing.T) { }, want: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: &core.BOM{ - SerialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", - Version: 1, - }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{}, @@ -369,10 +362,7 @@ func TestFilter(t *testing.T) { args: args{ report: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: &core.BOM{ - SerialNumber: "urn:uuid:wrong", - Version: 1, - }, + BOM: cdxBOM("urn:uuid:wrong"), Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -390,10 +380,6 @@ func TestFilter(t *testing.T) { }, want: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: &core.BOM{ - SerialNumber: "urn:uuid:wrong", - Version: 1, - }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -573,6 +559,7 @@ repositories: return } require.NoError(t, err) + tt.args.report.BOM = nil // Ignore BOM for comparison assert.Equal(t, tt.want, tt.args.report) }) } @@ -692,6 +679,21 @@ func goMultiPathResult(result types.Result) types.Result { return result } +func cdxBOM(serialNumber string) *core.BOM { + bom := core.NewBOM(core.Options{GenerateBOMRef: true}) + bom.SerialNumber = serialNumber + bom.Version = 1 + c := &core.Component{ + Type: core.TypeLibrary, + Root: true, + Name: springPackage.Name, + Version: springPackage.Version, + PkgIdentifier: springPackage.Identifier, + } + bom.AddComponent(c) + return bom +} + func modifiedFinding(vuln types.DetectedVulnerability, statement, source string) types.ModifiedFinding { return types.ModifiedFinding{ Type: types.FindingTypeVulnerability, From 8b333099c454c1aa11296c0c910a15317814adb6 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Fri, 13 Sep 2024 12:21:05 +0400 Subject: [PATCH 13/18] fix: linter error Signed-off-by: knqyf263 --- pkg/sbom/io/encode_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 223fb0027e11..56dd0116bbdd 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -744,7 +744,7 @@ func TestEncoder_Encode(t *testing.T) { wantComponents: map[uuid.UUID]*core.Component{ uuid.MustParse(id1): &libComponent, }, - wantRels: map[uuid.UUID][]core.Relationship{}, + wantRels: make(map[uuid.UUID][]core.Relationship), wantVulns: map[uuid.UUID][]core.Vulnerability{ uuid.MustParse(id1): { { From 67961d7e7488e8292f43a5a1fabc41ad93aa7fad Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 16 Sep 2024 09:55:26 +0400 Subject: [PATCH 14/18] refactor: rename AddVulnerabilities to SetVulnerabilities Signed-off-by: knqyf263 --- pkg/sbom/core/bom.go | 2 +- pkg/sbom/io/encode.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/core/bom.go b/pkg/sbom/core/bom.go index d6ee429a0576..632bc37123b1 100644 --- a/pkg/sbom/core/bom.go +++ b/pkg/sbom/core/bom.go @@ -273,7 +273,7 @@ func (b *BOM) AddVulnerability(c *Component, vuln Vulnerability) { b.vulnerabilities[c.id] = append(b.vulnerabilities[c.id], vuln) } -func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { +func (b *BOM) SetVulnerabilities(c *Component, vulns []Vulnerability) { if c.id == uuid.Nil { b.AddComponent(c) } diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index a91ae2965036..11d37455538c 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -219,7 +219,7 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { // Add vulnerabilities if vv := vulns[pkg.Identifier.UID]; vv != nil { - e.bom.AddVulnerabilities(c, vv) + e.bom.SetVulnerabilities(c, vv) } // Handle a root package From 13b0ff40c15f45520a5abc0acd0b0b1a195134a3 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 18 Sep 2024 14:44:13 +0400 Subject: [PATCH 15/18] Revert "refactor: rename AddVulnerabilities to SetVulnerabilities" This reverts commit 67961d7e7488e8292f43a5a1fabc41ad93aa7fad. --- pkg/sbom/core/bom.go | 2 +- pkg/sbom/io/encode.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/core/bom.go b/pkg/sbom/core/bom.go index 632bc37123b1..d6ee429a0576 100644 --- a/pkg/sbom/core/bom.go +++ b/pkg/sbom/core/bom.go @@ -273,7 +273,7 @@ func (b *BOM) AddVulnerability(c *Component, vuln Vulnerability) { b.vulnerabilities[c.id] = append(b.vulnerabilities[c.id], vuln) } -func (b *BOM) SetVulnerabilities(c *Component, vulns []Vulnerability) { +func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { if c.id == uuid.Nil { b.AddComponent(c) } diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 11d37455538c..a91ae2965036 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -219,7 +219,7 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { // Add vulnerabilities if vv := vulns[pkg.Identifier.UID]; vv != nil { - e.bom.SetVulnerabilities(c, vv) + e.bom.AddVulnerabilities(c, vv) } // Handle a root package From e67a91ee7409cc69b65549874dab87c82b277cfa Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 18 Sep 2024 14:44:22 +0400 Subject: [PATCH 16/18] Revert "fix: linter error" This reverts commit 8b333099c454c1aa11296c0c910a15317814adb6. --- pkg/sbom/io/encode_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 56dd0116bbdd..223fb0027e11 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -744,7 +744,7 @@ func TestEncoder_Encode(t *testing.T) { wantComponents: map[uuid.UUID]*core.Component{ uuid.MustParse(id1): &libComponent, }, - wantRels: make(map[uuid.UUID][]core.Relationship), + wantRels: map[uuid.UUID][]core.Relationship{}, wantVulns: map[uuid.UUID][]core.Vulnerability{ uuid.MustParse(id1): { { From 28c45d89e9c1e3b8897a98841bb1c85905f6196d Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 18 Sep 2024 14:44:31 +0400 Subject: [PATCH 17/18] Revert "test: add appropriate parsed BOMs" This reverts commit 0bb63875c419f12e50f6b2135b54cfe3b91ac791. --- integration/sbom_test.go | 4 +- .../fluentd-multiple-lockfiles-cyclonedx.json | 6 +- ...-multiple-lockfiles-short.cdx.json.golden} | 64 ++++--- .../fluentd-multiple-lockfiles.json.golden | 2 +- pkg/sbom/cyclonedx/marshal_test.go | 160 +++++++----------- pkg/sbom/io/encode_test.go | 82 ++++----- pkg/vex/vex_test.go | 34 ++-- 7 files changed, 155 insertions(+), 197 deletions(-) rename integration/testdata/{fluentd-multiple-lockfiles-reused.cdx.json.golden => fluentd-multiple-lockfiles-short.cdx.json.golden} (91%) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index 1d39ca0d254b..e887f1520e68 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -59,14 +59,14 @@ func TestSBOM(t *testing.T) { golden: "testdata/fluentd-multiple-lockfiles.json.golden", }, { - name: "scan CycloneDX into CycloneDX", + name: "scan SBOM into SBOM", args: args{ input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json", format: "cyclonedx", artifactType: "cyclonedx", }, fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", - golden: "testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden", + golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", }, { name: "minikube KBOM", diff --git a/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json b/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json index 82d711cd909c..f5db904207d1 100644 --- a/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json +++ b/integration/testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json @@ -120,7 +120,7 @@ ] }, { - "bom-ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", + "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", "type": "library", "name": "activesupport", "version": "6.0.2.1", @@ -163,8 +163,8 @@ { "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "dependsOn": [ - "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", - "353f2470-9c8b-4647-9d0d-96d893838dc8" + "353f2470-9c8b-4647-9d0d-96d893838dc8", + "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" ] } ] diff --git a/integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden similarity index 91% rename from integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden rename to integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden index c45912c976d3..496ca8ae3110 100644 --- a/integration/testdata/fluentd-multiple-lockfiles-reused.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden @@ -2,7 +2,7 @@ "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.6", - "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000006", + "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000010", "version": 1, "metadata": { "timestamp": "2021-08-25T12:20:30+00:00", @@ -81,20 +81,20 @@ "purl": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", "properties": [ { - "name": "aquasecurity:trivy:SrcName", - "value": "bash" + "name": "aquasecurity:trivy:PkgID", + "value": "bash@5.0-4" }, { - "name": "aquasecurity:trivy:SrcVersion", - "value": "5.0-4" + "name": "aquasecurity:trivy:PkgType", + "value": "debian" }, { - "name": "aquasecurity:trivy:LayerDigest", - "value": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c" + "name": "aquasecurity:trivy:SrcName", + "value": "bash" }, { - "name": "aquasecurity:trivy:LayerDiffID", - "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" + "name": "aquasecurity:trivy:SrcVersion", + "value": "5.0-4" } ] }, @@ -106,25 +106,25 @@ "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", "properties": [ { - "name": "aquasecurity:trivy:SrcName", - "value": "libidn2" + "name": "aquasecurity:trivy:PkgID", + "value": "libidn2-0@2.0.5-1" }, { - "name": "aquasecurity:trivy:SrcVersion", - "value": "2.0.5-1" + "name": "aquasecurity:trivy:PkgType", + "value": "debian" }, { - "name": "aquasecurity:trivy:LayerDigest", - "value": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c" + "name": "aquasecurity:trivy:SrcName", + "value": "libidn2" }, { - "name": "aquasecurity:trivy:LayerDiffID", - "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" + "name": "aquasecurity:trivy:SrcVersion", + "value": "2.0.5-1" } ] }, { - "bom-ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", + "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", "type": "library", "name": "activesupport", "version": "6.0.2.1", @@ -142,15 +142,11 @@ "value": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec" }, { - "name": "aquasecurity:trivy:LayerDigest", - "value": "sha256:a8877cad19f14a7044524a145ce33170085441a7922458017db1631dcd5f7602" - }, - { - "name": "aquasecurity:trivy:LayerDiffID", - "value": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9" + "name": "aquasecurity:trivy:PkgID", + "value": "activesupport@6.0.2.1" }, { - "name": "aquasecurity:trivy:Type", + "name": "aquasecurity:trivy:PkgType", "value": "gemspec" } ] @@ -167,9 +163,21 @@ { "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", "dependsOn": [ - "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", - "353f2470-9c8b-4647-9d0d-96d893838dc8" + "353f2470-9c8b-4647-9d0d-96d893838dc8", + "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" ] + }, + { + "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "dependsOn": [] } ], "vulnerabilities": [ @@ -504,7 +512,7 @@ "updated": "2020-10-17T12:15:00+00:00", "affects": [ { - "ref": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b", + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", "versions": [ { "version": "6.0.2.1", diff --git a/integration/testdata/fluentd-multiple-lockfiles.json.golden b/integration/testdata/fluentd-multiple-lockfiles.json.golden index 82241f14b60e..fec0e1a39a0d 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.json.golden @@ -168,7 +168,7 @@ "PkgIdentifier": { "PURL": "pkg:gem/activesupport@6.0.2.1", "UID": "66a6de64809697cd", - "BOMRef": "179eaea5-d48e-4dd3-a53d-c87c3f6e9e5b" + "BOMRef": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" }, "InstalledVersion": "6.0.2.1", "FixedVersion": "6.0.3.1, 5.2.4.3", diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index 396f1aa05fcf..8b88c4ec762a 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -65,6 +65,21 @@ var ( ) func TestMarshaler_MarshalReport(t *testing.T) { + testSBOM := core.NewBOM(core.Options{GenerateBOMRef: true}) + testSBOM.AddComponent(&core.Component{ + Root: true, + Type: core.TypeApplication, + Name: "jackson-databind-2.13.4.1.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8", + }, + Properties: []core.Property{ + { + Name: "SchemaVersion", + Value: "2", + }, + }, + }) tests := []struct { name string @@ -1460,18 +1475,61 @@ func TestMarshaler_MarshalReport(t *testing.T) { }, }, Vulnerabilities: []types.DetectedVulnerability{ - vuln1, + { + VulnerabilityID: "CVE-2022-42003", + PkgName: "com.fasterxml.jackson.core:jackson-databind", + PkgPath: "jackson-databind-2.13.4.1.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", + UID: "9A5066570222D04C", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.13.4.1", + }, + }, + InstalledVersion: "2.13.4.1", + FixedVersion: "2.12.7.1, 2.13.4.2", + Status: dtypes.StatusFixed, + SeveritySource: "ghsa", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2022-42003", + DataSource: &dtypes.DataSource{ + ID: vulnerability.GHSA, + Name: "GitHub Security Advisory Maven", + URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven", + }, + Vulnerability: dtypes.Vulnerability{ + Title: "jackson-databind: deep wrapper array nesting wrt UNWRAP_SINGLE_VALUE_ARRAYS", + Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.", + Severity: dtypes.SeverityHigh.String(), + VendorSeverity: dtypes.VendorSeverity{ + vulnerability.GHSA: dtypes.SeverityHigh, + }, + CVSS: dtypes.VendorCVSS{ + vulnerability.GHSA: dtypes.CVSS{ + V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + V3Score: 7.5, + }, + }, + References: []string{ + "https://access.redhat.com/security/cve/CVE-2022-42003", + }, + PublishedDate: lo.ToPtr(time.Date(2022, 10, 02, 05, 15, 0, 0, time.UTC)), + LastModifiedDate: lo.ToPtr(time.Date(2022, 12, 20, 10, 15, 0, 0, time.UTC)), + }, + }, }, }, }, - BOM: testSBOM(), + BOM: testSBOM, }, want: &cdx.BOM{ XMLNS: "http://cyclonedx.org/schema/bom/1.6", BOMFormat: "CycloneDX", SpecVersion: cdx.SpecVersion1_6, JSONSchema: "http://cyclonedx.org/schema/bom-1.6.schema.json", - SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000001", + SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000002", Version: 1, Metadata: &cdx.Metadata{ Timestamp: "2021-08-25T12:20:30+00:00", @@ -2052,99 +2110,3 @@ func TestMarshaler_MarshalReport(t *testing.T) { }) } } - -var ( - vuln1 = types.DetectedVulnerability{ - VulnerabilityID: "CVE-2022-42003", - PkgName: "com.fasterxml.jackson.core:jackson-databind", - PkgPath: "jackson-databind-2.13.4.1.jar", - PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", - UID: "9A5066570222D04C", - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeMaven, - Namespace: "com.fasterxml.jackson.core", - Name: "jackson-databind", - Version: "2.13.4.1", - }, - }, - InstalledVersion: "2.13.4.1", - FixedVersion: "2.12.7.1, 2.13.4.2", - Status: dtypes.StatusFixed, - SeveritySource: "ghsa", - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2022-42003", - DataSource: &dtypes.DataSource{ - ID: vulnerability.GHSA, - Name: "GitHub Security Advisory Maven", - URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven", - }, - Vulnerability: dtypes.Vulnerability{ - Title: "jackson-databind: deep wrapper array nesting wrt UNWRAP_SINGLE_VALUE_ARRAYS", - Description: "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.", - Severity: dtypes.SeverityHigh.String(), - VendorSeverity: dtypes.VendorSeverity{ - vulnerability.GHSA: dtypes.SeverityHigh, - }, - CVSS: dtypes.VendorCVSS{ - vulnerability.GHSA: dtypes.CVSS{ - V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - V3Score: 7.5, - }, - }, - References: []string{ - "https://access.redhat.com/security/cve/CVE-2022-42003", - }, - PublishedDate: lo.ToPtr(time.Date(2022, 10, 02, 05, 15, 0, 0, time.UTC)), - LastModifiedDate: lo.ToPtr(time.Date(2022, 12, 20, 10, 15, 0, 0, time.UTC)), - }, - } -) - -func testSBOM() *core.BOM { - bom := core.NewBOM(core.Options{GenerateBOMRef: true}) - appComponent := &core.Component{ - Root: true, - Type: core.TypeApplication, - Name: "jackson-databind-2.13.4.1.jar", - PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8", - }, - Properties: []core.Property{ - { - Name: "SchemaVersion", - Value: "2", - }, - }, - } - libComponent := &core.Component{ - Type: core.TypeLibrary, - Name: "jackson-databind", - Group: "com.fasterxml.jackson.core", - Version: "2.13.4.1", - PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", - UID: "9A5066570222D04C", - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeMaven, - Namespace: "com.fasterxml.jackson.core", - Name: "jackson-databind", - Version: "2.13.4.1", - }, - }, - Properties: []core.Property{ - { - Name: "FilePath", - Value: "jackson-databind-2.13.4.1.jar", - }, - { - Name: "PkgType", - Value: "jar", - }, - }, - } - bom.AddComponent(appComponent) - bom.AddComponent(libComponent) - bom.AddRelationship(appComponent, libComponent, core.RelationshipContains) - bom.AddRelationship(libComponent, nil, core.RelationshipDependsOn) - return bom -} diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 223fb0027e11..52fbed415933 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -5,7 +5,6 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/package-url/packageurl-go" - "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -704,22 +703,22 @@ func TestEncoder_Encode(t *testing.T) { BOM: newTestBOM(t), }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse(id1): &appComponent, - uuid.MustParse(id2): &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(id1): { + uuid.MustParse("2ff14136-e09f-4df9-80ea-000000000001"): { { - Dependency: uuid.MustParse(id2), + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"), Type: core.RelationshipContains, }, }, - uuid.MustParse(id2): nil, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): nil, }, wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, { - name: "fill vulnerabilities in SBOM being scanned", + name: "SBOM file without root component", report: types.Report{ SchemaVersion: 2, ArtifactName: "report.cdx.json", @@ -729,12 +728,21 @@ func TestEncoder_Encode(t *testing.T) { Target: "Java", Type: ftypes.Jar, Class: types.ClassLangPkg, - Vulnerabilities: []types.DetectedVulnerability{ + Packages: []ftypes.Package{ { - VulnerabilityID: "CVE-2021-44228", - PkgName: libComponent.Name, - InstalledVersion: libComponent.Version, - PkgIdentifier: libComponent.PkgIdentifier, + ID: "org.apache.logging.log4j:log4j-core:2.23.1", + Name: "org.apache.logging.log4j:log4j-core", + Version: "2.23.1", + Identifier: ftypes.PkgIdentifier{ + UID: "6C0AE96901617503", + 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", }, }, }, @@ -742,18 +750,19 @@ func TestEncoder_Encode(t *testing.T) { BOM: newTestBOM2(t), }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse(id1): &libComponent, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): fsComponent, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): libComponent, }, - wantRels: map[uuid.UUID][]core.Relationship{}, - wantVulns: map[uuid.UUID][]core.Vulnerability{ - uuid.MustParse(id1): { + wantRels: map[uuid.UUID][]core.Relationship{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { { - ID: "CVE-2021-44228", - PkgName: libComponent.Name, - InstalledVersion: libComponent.Version, + 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)", @@ -787,8 +796,8 @@ func TestEncoder_Encode(t *testing.T) { }, }, wantComponents: map[uuid.UUID]*core.Component{ - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): &fsComponent, - uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): &libComponent, + 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"): { @@ -838,9 +847,7 @@ func TestEncoder_Encode(t *testing.T) { require.Len(t, got.Components(), len(tt.wantComponents)) for id, want := range tt.wantComponents { - gotComponent, ok := got.Components()[id] - require.True(t, ok, id) - assert.EqualExportedValues(t, *want, *gotComponent, id) + assert.EqualExportedValues(t, *want, *got.Components()[id], id) } assert.Equal(t, tt.wantRels, got.Relationships()) @@ -849,18 +856,13 @@ func TestEncoder_Encode(t *testing.T) { } } -const ( - id1 = "2ff14136-e09f-4df9-80ea-000000000001" - id2 = "2ff14136-e09f-4df9-80ea-000000000002" -) - var ( - appComponent = core.Component{ + appComponent = &core.Component{ Root: true, Type: core.TypeApplication, Name: "log4j-core-2.23.1.jar", } - fsComponent = core.Component{ + fsComponent = &core.Component{ Root: true, Type: core.TypeFilesystem, Name: "report.cdx.json", @@ -874,7 +876,7 @@ var ( }, }, } - libComponent = core.Component{ + libComponent = &core.Component{ Type: core.TypeLibrary, Name: "log4j-core", Group: "org.apache.logging.log4j", @@ -913,27 +915,15 @@ var ( func newTestBOM(t *testing.T) *core.BOM { uuid.SetFakeUUID(t, "2ff14136-e09f-4df9-80ea-%012d") - - // Copy components - app := lo.ToPtr(appComponent) - lib := lo.ToPtr(libComponent) - bom := core.NewBOM(core.Options{}) - bom.AddComponent(app) - bom.AddComponent(lib) - bom.AddRelationship(app, lib, core.RelationshipContains) - bom.AddRelationship(lib, nil, core.RelationshipDependsOn) + bom.AddComponent(appComponent) return bom } // BOM without root component func newTestBOM2(t *testing.T) *core.BOM { uuid.SetFakeUUID(t, "2ff14136-e09f-4df9-80ea-%012d") - - // Copy components - lib := lo.ToPtr(libComponent) - bom := core.NewBOM(core.Options{}) - bom.AddComponent(lib) + bom.AddComponent(libComponent) return bom } diff --git a/pkg/vex/vex_test.go b/pkg/vex/vex_test.go index c989c608fccd..4a9686972a5e 100644 --- a/pkg/vex/vex_test.go +++ b/pkg/vex/vex_test.go @@ -331,7 +331,10 @@ func TestFilter(t *testing.T) { args: args{ report: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: cdxBOM("urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"), + BOM: &core.BOM{ + SerialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", + Version: 1, + }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -349,6 +352,10 @@ func TestFilter(t *testing.T) { }, want: &types.Report{ ArtifactType: artifact.TypeCycloneDX, + BOM: &core.BOM{ + SerialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", + Version: 1, + }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{}, @@ -362,7 +369,10 @@ func TestFilter(t *testing.T) { args: args{ report: &types.Report{ ArtifactType: artifact.TypeCycloneDX, - BOM: cdxBOM("urn:uuid:wrong"), + BOM: &core.BOM{ + SerialNumber: "urn:uuid:wrong", + Version: 1, + }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -380,6 +390,10 @@ func TestFilter(t *testing.T) { }, want: &types.Report{ ArtifactType: artifact.TypeCycloneDX, + BOM: &core.BOM{ + SerialNumber: "urn:uuid:wrong", + Version: 1, + }, Results: []types.Result{ springResult(types.Result{ Vulnerabilities: []types.DetectedVulnerability{vuln1}, @@ -559,7 +573,6 @@ repositories: return } require.NoError(t, err) - tt.args.report.BOM = nil // Ignore BOM for comparison assert.Equal(t, tt.want, tt.args.report) }) } @@ -679,21 +692,6 @@ func goMultiPathResult(result types.Result) types.Result { return result } -func cdxBOM(serialNumber string) *core.BOM { - bom := core.NewBOM(core.Options{GenerateBOMRef: true}) - bom.SerialNumber = serialNumber - bom.Version = 1 - c := &core.Component{ - Type: core.TypeLibrary, - Root: true, - Name: springPackage.Name, - Version: springPackage.Version, - PkgIdentifier: springPackage.Identifier, - } - bom.AddComponent(c) - return bom -} - func modifiedFinding(vuln types.DetectedVulnerability, statement, source string) types.ModifiedFinding { return types.ModifiedFinding{ Type: types.FindingTypeVulnerability, From f4478c0b6be76e86dd17eb2cf7410144b24a40d4 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 18 Sep 2024 14:44:40 +0400 Subject: [PATCH 18/18] Revert "refactor: reuse the parsed SBOM" This reverts commit 418100c2f525773e95193a6e1f8b32b4d12bfe7b. --- pkg/sbom/core/bom.go | 8 -------- pkg/sbom/io/encode.go | 39 ++++++++++++++++----------------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/pkg/sbom/core/bom.go b/pkg/sbom/core/bom.go index d6ee429a0576..c0a082d013b5 100644 --- a/pkg/sbom/core/bom.go +++ b/pkg/sbom/core/bom.go @@ -269,10 +269,6 @@ func (b *BOM) AddRelationship(parent, child *Component, relationshipType Relatio } } -func (b *BOM) AddVulnerability(c *Component, vuln Vulnerability) { - b.vulnerabilities[c.id] = append(b.vulnerabilities[c.id], vuln) -} - func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { if c.id == uuid.Nil { b.AddComponent(c) @@ -283,10 +279,6 @@ func (b *BOM) AddVulnerabilities(c *Component, vulns []Vulnerability) { b.vulnerabilities[c.id] = vulns } -func (b *BOM) ClearVulnerabilities() { - b.vulnerabilities = make(map[uuid.UUID][]Vulnerability) -} - func (b *BOM) Root() *Component { root, ok := b.components[b.rootID] if !ok { diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index a91ae2965036..975b98d40b10 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -20,8 +20,9 @@ import ( ) type Encoder struct { - bom *core.BOM - opts core.Options + bom *core.BOM + opts core.Options + components map[uuid.UUID]*core.Component } func NewEncoder(opts core.Options) *Encoder { @@ -30,7 +31,7 @@ func NewEncoder(opts core.Options) *Encoder { func (e *Encoder) Encode(report types.Report) (*core.BOM, error) { if report.BOM != nil { - return e.reuseBOM(report) + e.components = report.BOM.Components() } // Metadata component root, err := e.rootComponent(report) @@ -261,6 +262,16 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { } } +// existedPkgIdentifier tries to look for package identifier (BOM-ref, PURL) by component name and component type +func (e *Encoder) existedPkgIdentifier(name string, componentType core.ComponentType) ftypes.PkgIdentifier { + for _, c := range e.components { + if c.Name == name && c.Type == componentType { + return c.PkgIdentifier + } + } + return ftypes.PkgIdentifier{} +} + func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound *ftypes.OS) *core.Component { component := &core.Component{ Name: r.Target, @@ -283,8 +294,10 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound component.Version = osFound.Name } component.Type = core.TypeOS + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) case types.ClassLangPkg: component.Type = core.TypeApplication + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) } e.bom.AddRelationship(root, component, core.RelationshipContains) @@ -433,26 +446,6 @@ func (*Encoder) belongToParent(pkg ftypes.Package, parents map[string]ftypes.Pac } } -func (e *Encoder) reuseBOM(report types.Report) (*core.BOM, error) { - report.BOM.ClearVulnerabilities() - - // Group components by BOM-Ref - components := lo.MapKeys(report.BOM.Components(), func(value *core.Component, _ uuid.UUID) string { - return value.PkgIdentifier.BOMRef - }) - - for _, result := range report.Results { - for _, vuln := range result.Vulnerabilities { - c, ok := components[vuln.PkgIdentifier.BOMRef] - if !ok || c == nil { - continue - } - report.BOM.AddVulnerability(c, e.vulnerability(vuln)) - } - } - return report.BOM, nil -} - func filterProperties(props []core.Property) []core.Property { return lo.Filter(props, func(property core.Property, _ int) bool { return !(property.Value == "" || (property.Name == core.PropertySrcEpoch && property.Value == "0"))