From f81b213c578c363fefb56f7ef7970d0c10d0ee89 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 31 May 2023 13:19:35 +0600 Subject: [PATCH 1/4] update logic for work with files --- integration/testdata/conda-spdx.json.golden | 68 ++++++++------ pkg/sbom/spdx/marshal.go | 19 ++-- pkg/sbom/spdx/marshal_test.go | 73 +++++++++------ .../with-files-in-relationships-bom.json | 91 +++++++++++++++++++ .../testdata/happy/with-hasfiles-bom.json | 86 ++++++++++++++++++ pkg/sbom/spdx/unmarshal.go | 52 +++++++++-- pkg/sbom/spdx/unmarshal_test.go | 63 +++++++++++++ 7 files changed, 380 insertions(+), 72 deletions(-) create mode 100644 pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json create mode 100644 pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json diff --git a/integration/testdata/conda-spdx.json.golden b/integration/testdata/conda-spdx.json.golden index c0ea6ffe8777..1d60da5fa7df 100644 --- a/integration/testdata/conda-spdx.json.golden +++ b/integration/testdata/conda-spdx.json.golden @@ -3,14 +3,14 @@ "dataLicense": "CC0-1.0", "SPDXID": "SPDXRef-DOCUMENT", "name": "testdata/fixtures/fs/conda", - "documentNamespace": "http://aquasecurity.github.io/trivy/filesystem/testdata/fixtures/fs/conda-e854267f-30a6-497d-9183-2f45dee37b09", + "documentNamespace": "http://aquasecurity.github.io/trivy/filesystem/testdata/fixtures/fs/conda-8864fdf2-1c56-4e86-bc35-c89a0a4c22b9", "creationInfo": { "licenseListVersion": "", "creators": [ "Organization: aquasecurity", "Tool: trivy-dev" ], - "created": "2023-05-19T10:38:39Z" + "created": "2023-05-31T07:16:47Z" }, "packages": [ { @@ -37,20 +37,7 @@ "referenceLocator": "pkg:conda/openssl@1.1.1q" } ], - "primaryPackagePurpose": "LIBRARY", - "files": [ - { - "fileName": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json", - "SPDXID": "SPDXRef-File-600e5e0110a84891", - "checksums": [ - { - "algorithm": "SHA1", - "checksumValue": "237db0da53131e4548cb1181337fa0f420299e1f" - } - ], - "copyrightText": "" - } - ] + "primaryPackagePurpose": "LIBRARY" }, { "name": "pip", @@ -68,20 +55,7 @@ "referenceLocator": "pkg:conda/pip@22.2.2" } ], - "primaryPackagePurpose": "LIBRARY", - "files": [ - { - "fileName": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json", - "SPDXID": "SPDXRef-File-7eb62e2a3edddc0a", - "checksums": [ - { - "algorithm": "SHA1", - "checksumValue": "a6a2db7668f1ad541d704369fc66c96a4415aa24" - } - ], - "copyrightText": "" - } - ] + "primaryPackagePurpose": "LIBRARY" }, { "name": "testdata/fixtures/fs/conda", @@ -94,6 +68,30 @@ "primaryPackagePurpose": "SOURCE" } ], + "files": [ + { + "fileName": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json", + "SPDXID": "SPDXRef-File-600e5e0110a84891", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "237db0da53131e4548cb1181337fa0f420299e1f" + } + ], + "copyrightText": "" + }, + { + "fileName": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json", + "SPDXID": "SPDXRef-File-7eb62e2a3edddc0a", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "a6a2db7668f1ad541d704369fc66c96a4415aa24" + } + ], + "copyrightText": "" + } + ], "relationships": [ { "spdxElementId": "SPDXRef-DOCUMENT", @@ -110,10 +108,20 @@ "relatedSpdxElement": "SPDXRef-Package-b1088cb4090e3a55", "relationshipType": "CONTAINS" }, + { + "spdxElementId": "SPDXRef-Package-b1088cb4090e3a55", + "relatedSpdxElement": "SPDXRef-File-600e5e0110a84891", + "relationshipType": "CONTAINS" + }, { "spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125", "relatedSpdxElement": "SPDXRef-Package-6b677e82217fb5bd", "relationshipType": "CONTAINS" + }, + { + "spdxElementId": "SPDXRef-Package-6b677e82217fb5bd", + "relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a", + "relationshipType": "CONTAINS" } ] } \ No newline at end of file diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 8c11ffc4b4be..f91695f4674b 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -138,6 +138,8 @@ func (m *Marshaler) Marshal(r types.Report) (*spdx.Document, error) { relationShip(DocumentSPDXIdentifier, rootPkg.PackageSPDXIdentifier, RelationShipDescribe), ) + var spdxFiles []*spdx.File + for _, result := range r.Results { if len(result.Packages) == 0 { continue @@ -160,6 +162,16 @@ func (m *Marshaler) Marshal(r types.Report) (*spdx.Document, error) { relationShips = append(relationShips, relationShip(parentPackage.PackageSPDXIdentifier, spdxPackage.PackageSPDXIdentifier, RelationShipContains), ) + files, err := m.pkgFiles(pkg) + if err != nil { + return nil, xerrors.Errorf("package file error: %w", err) + } + spdxFiles = append(spdxFiles, files...) + for _, file := range files { + relationShips = append(relationShips, + relationShip(spdxPackage.PackageSPDXIdentifier, file.FileSPDXIdentifier, RelationShipContains), + ) + } } } @@ -184,6 +196,7 @@ func (m *Marshaler) Marshal(r types.Report) (*spdx.Document, error) { }, Packages: toPackages(packages), Relationships: relationShips, + Files: spdxFiles, }, nil } @@ -337,11 +350,6 @@ func (m *Marshaler) pkgToSpdxPackage(t, pkgDownloadLocation string, class types. attrTexts = appendAttributionText(attrTexts, PropertyLayerDigest, pkg.Layer.Digest) attrTexts = appendAttributionText(attrTexts, PropertyLayerDiffID, pkg.Layer.DiffID) - files, err := m.pkgFiles(pkg) - if err != nil { - return spdx.Package{}, xerrors.Errorf("package file error: %w", err) - } - supplier := &spdx.Supplier{Supplier: PackageSupplierNoAssertion} if pkg.Maintainer != "" { supplier = &spdx.Supplier{ @@ -373,7 +381,6 @@ func (m *Marshaler) pkgToSpdxPackage(t, pkgDownloadLocation string, class types. PrimaryPackagePurpose: PackagePurposeLibrary, PackageSupplier: supplier, PackageChecksums: checksum, - Files: files, }, nil } diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index 7af6ba75e489..ffc28ac06209 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -401,18 +401,6 @@ func TestMarshaler_Marshal(t *testing.T) { PackageAttributionTexts: []string{ "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, - Files: []*spdx.File{ - { - FileSPDXIdentifier: "File-fa42187221d0d0a8", - FileName: "tools/project-doe/specifications/actionpack.gemspec", - Checksums: []spdx.Checksum{ - { - Algorithm: spdx.SHA1, - Value: "413f98442c83808042b5d1d2611a346b999bdca5", - }, - }, - }, - }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, }, @@ -433,18 +421,6 @@ func TestMarshaler_Marshal(t *testing.T) { PackageAttributionTexts: []string{ "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, - Files: []*spdx.File{ - { - FileSPDXIdentifier: "File-6a540784b0dc6d55", - FileName: "tools/project-john/specifications/actionpack.gemspec", - Checksums: []spdx.Checksum{ - { - Algorithm: spdx.SHA1, - Value: "d2f9f9aed5161f6e4116a3f9573f41cd832f137c", - }, - }, - }, - }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, }, @@ -475,6 +451,28 @@ func TestMarshaler_Marshal(t *testing.T) { PrimaryPackagePurpose: tspdx.PackagePurposeApplication, }, }, + Files: []*spdx.File{ + { + FileSPDXIdentifier: "File-6a540784b0dc6d55", + FileName: "tools/project-john/specifications/actionpack.gemspec", + Checksums: []spdx.Checksum{ + { + Algorithm: spdx.SHA1, + Value: "d2f9f9aed5161f6e4116a3f9573f41cd832f137c", + }, + }, + }, + { + FileSPDXIdentifier: "File-fa42187221d0d0a8", + FileName: "tools/project-doe/specifications/actionpack.gemspec", + Checksums: []spdx.Checksum{ + { + Algorithm: spdx.SHA1, + Value: "413f98442c83808042b5d1d2611a346b999bdca5", + }, + }, + }, + }, Relationships: []*spdx.Relationship{ { RefA: spdx.DocElementID{ElementRefID: "DOCUMENT"}, @@ -501,11 +499,21 @@ func TestMarshaler_Marshal(t *testing.T) { RefB: spdx.DocElementID{ElementRefID: "Package-d5443dbcbba0dbd4"}, Relationship: "CONTAINS", }, + { + RefA: spdx.DocElementID{ElementRefID: "Package-d5443dbcbba0dbd4"}, + RefB: spdx.DocElementID{ElementRefID: "File-6a540784b0dc6d55"}, + Relationship: "CONTAINS", + }, { RefA: spdx.DocElementID{ElementRefID: "Application-441a648f2aeeee72"}, RefB: spdx.DocElementID{ElementRefID: "Package-13fe667a0805e6b7"}, Relationship: "CONTAINS", }, + { + RefA: spdx.DocElementID{ElementRefID: "Package-13fe667a0805e6b7"}, + RefB: spdx.DocElementID{ElementRefID: "File-fa42187221d0d0a8"}, + Relationship: "CONTAINS", + }, }, OtherLicenses: nil, @@ -684,16 +692,16 @@ func TestMarshaler_Marshal(t *testing.T) { PackageAttributionTexts: []string{ "LayerDiffID: sha256:661c3fd3cc16b34c070f3620ca6b03b6adac150f9a7e5d0e3c707a159990f88e", }, - Files: []*spdx.File{ - { - FileName: "usr/local/lib/ruby/gems/3.1.0/gems/typeprof-0.21.1/vscode/package.json", - FileSPDXIdentifier: "File-a52825a3e5bc6dfe", - }, - }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, }, }, + Files: []*spdx.File{ + { + FileName: "usr/local/lib/ruby/gems/3.1.0/gems/typeprof-0.21.1/vscode/package.json", + FileSPDXIdentifier: "File-a52825a3e5bc6dfe", + }, + }, Relationships: []*spdx.Relationship{ { RefA: spdx.DocElementID{ElementRefID: "DOCUMENT"}, @@ -710,6 +718,11 @@ func TestMarshaler_Marshal(t *testing.T) { RefB: spdx.DocElementID{ElementRefID: "Package-daedb173cfd43058"}, Relationship: "CONTAINS", }, + { + RefA: spdx.DocElementID{ElementRefID: "Package-daedb173cfd43058"}, + RefB: spdx.DocElementID{ElementRefID: "File-a52825a3e5bc6dfe"}, + Relationship: "CONTAINS", + }, }, }, }, diff --git a/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json b/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json new file mode 100644 index 000000000000..bea4ab4f746e --- /dev/null +++ b/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json @@ -0,0 +1,91 @@ +{ + "spdxVersion": "SPDX-2.3", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "name": "app", + "documentNamespace": "http://aquasecurity.github.io/trivy/filesystem/app-8e571278-2221-4dcd-bc56-0b256210fa91", + "creationInfo": { + "licenseListVersion": "", + "creators": [ + "Organization: aquasecurity", + "Tool: trivy-0.36.2-107-gb0c591ef" + ], + "created": "2023-05-31T05:58:45Z" + }, + "packages": [ + { + "name": "app", + "SPDXID": "SPDXRef-Filesystem-13b142ca391a006e", + "downloadLocation": "NONE", + "copyrightText": "", + "attributionTexts": [ + "SchemaVersion: 2" + ], + "primaryPackagePurpose": "SOURCE" + }, + { + "name": "node-pkg", + "SPDXID": "SPDXRef-Application-24f8a80152e2c0fc", + "downloadLocation": "NONE", + "sourceInfo": "Node.js", + "copyrightText": "", + "primaryPackagePurpose": "APPLICATION" + }, + { + "name": "yargs-parser", + "SPDXID": "SPDXRef-Package-c3508825bf3861d8", + "versionInfo": "21.1.1", + "supplier": "NOASSERTION", + "downloadLocation": "NONE", + "licenseConcluded": "ISC", + "licenseDeclared": "ISC", + "copyrightText": "", + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:npm/yargs-parser@21.1.1" + } + ], + "attributionTexts": [ + "PkgID: yargs-parser@21.1.1" + ], + "primaryPackagePurpose": "LIBRARY" + } + ], + "files": [ + { + "fileName": "node_modules/yargs-parser/package.json", + "SPDXID": "SPDXRef-File-51bb5f929ef68877", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "69e70ec702f9df4ff64024b5fdea4644f1ce6c97" + } + ], + "copyrightText": "" + } + ], + "relationships": [ + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relatedSpdxElement": "SPDXRef-Filesystem-13b142ca391a006e", + "relationshipType": "DESCRIBES" + }, + { + "spdxElementId": "SPDXRef-Filesystem-13b142ca391a006e", + "relatedSpdxElement": "SPDXRef-Application-24f8a80152e2c0fc", + "relationshipType": "CONTAINS" + }, + { + "spdxElementId": "SPDXRef-Application-24f8a80152e2c0fc", + "relatedSpdxElement": "SPDXRef-Package-c3508825bf3861d8", + "relationshipType": "CONTAINS" + }, + { + "spdxElementId": "SPDXRef-Package-c3508825bf3861d8", + "relatedSpdxElement": "SPDXRef-File-51bb5f929ef68877", + "relationshipType": "CONTAINS" + } + ] +} \ No newline at end of file diff --git a/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json b/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json new file mode 100644 index 000000000000..fdfe73df8a96 --- /dev/null +++ b/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json @@ -0,0 +1,86 @@ +{ + "SPDXID": "SPDXRef-DOCUMENT", + "creationInfo": { + "created": "2023-05-31T04:56:43Z", + "creators": [ + "Tool: trivy-0.40.0", + "Organization: aquasecurity" + ] + }, + "dataLicense": "CC0-1.0", + "documentDescribes": [ + "SPDXRef-Filesystem-13b142ca391a006e" + ], + "documentNamespace": "http://aquasecurity.github.io/trivy/filesystem/app-ab9e166e-7229-4d03-947e-8ffc9c60cf6f", + "files": [ + { + "SPDXID": "SPDXRef-File-51bb5f929ef68877", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "69e70ec702f9df4ff64024b5fdea4644f1ce6c97" + } + ], + "fileName": "node_modules/yargs-parser/package.json" + } + ], + "name": "app", + "packages": [ + { + "SPDXID": "SPDXRef-Application-24f8a80152e2c0fc", + "downloadLocation": "NONE", + "filesAnalyzed": false, + "name": "node-pkg", + "sourceInfo": "Node.js" + }, + { + "SPDXID": "SPDXRef-Filesystem-13b142ca391a006e", + "attributionTexts": [ + "SchemaVersion: 2" + ], + "downloadLocation": "NONE", + "filesAnalyzed": false, + "name": "app" + }, + { + "SPDXID": "SPDXRef-Package-c3508825bf3861d8", + "attributionTexts": [ + "PkgID: yargs-parser@21.1.1" + ], + "downloadLocation": "NONE", + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceLocator": "pkg:npm/yargs-parser@21.1.1", + "referenceType": "purl" + } + ], + "filesAnalyzed": false, + "hasFiles": [ + "SPDXRef-File-51bb5f929ef68877" + ], + "licenseConcluded": "ISC", + "licenseDeclared": "ISC", + "name": "yargs-parser", + "versionInfo": "21.1.1" + } + ], + "relationships": [ + { + "relatedSpdxElement": "SPDXRef-Filesystem-13b142ca391a006e", + "relationshipType": "DESCRIBES", + "spdxElementId": "SPDXRef-DOCUMENT" + }, + { + "relatedSpdxElement": "SPDXRef-Application-24f8a80152e2c0fc", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-Filesystem-13b142ca391a006e" + }, + { + "relatedSpdxElement": "SPDXRef-Package-c3508825bf3861d8", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-Application-24f8a80152e2c0fc" + } + ], + "spdxVersion": "SPDX-2.2" +} \ No newline at end of file diff --git a/pkg/sbom/spdx/unmarshal.go b/pkg/sbom/spdx/unmarshal.go index e83119f02639..8dca8603b555 100644 --- a/pkg/sbom/spdx/unmarshal.go +++ b/pkg/sbom/spdx/unmarshal.go @@ -69,6 +69,7 @@ func (s *SPDX) unmarshal(spdxDocument *spdx.Document) error { var osPkgs []ftypes.Package apps := map[common.ElementID]*ftypes.Application{} packageSPDXIdentifierMap := createPackageSPDXIdentifierMap(spdxDocument.Packages) + packageFilePaths := getPackageFilePaths(spdxDocument) // Package relationships would be as belows: // - Root (container image, filesystem, etc.) @@ -101,7 +102,7 @@ func (s *SPDX) unmarshal(spdxDocument *spdx.Document) error { s.SBOM.OS = parseOS(*pkgB) // Relationship: OS => OS package case isOperatingSystem(pkgA.PackageSPDXIdentifier): - pkg, err := parsePkg(*pkgB) + pkg, err := parsePkg(*pkgB, packageFilePaths) if err != nil { return xerrors.Errorf("failed to parse os package: %w", err) } @@ -117,7 +118,7 @@ func (s *SPDX) unmarshal(spdxDocument *spdx.Document) error { apps[pkgA.PackageSPDXIdentifier] = app } - lib, err := parsePkg(*pkgB) + lib, err := parsePkg(*pkgB, packageFilePaths) if err != nil { return xerrors.Errorf("failed to parse language-specific package: %w", err) } @@ -148,6 +149,14 @@ func createPackageSPDXIdentifierMap(packages []*spdx.Package) map[string]*spdx.P return ret } +func createFileSPDXIdentifierMap(files []*spdx.File) map[string]*spdx.File { + ret := make(map[string]*spdx.File) + for _, file := range files { + ret[string(file.FileSPDXIdentifier)] = file + } + return ret +} + func isOperatingSystem(elementID spdx.ElementID) bool { return strings.HasPrefix(string(elementID), ElementOperatingSystem) } @@ -156,6 +165,10 @@ func isApplication(elementID spdx.ElementID) bool { return strings.HasPrefix(string(elementID), ElementApplication) } +func isFile(elementID spdx.ElementID) bool { + return strings.HasPrefix(string(elementID), ElementFile) +} + func initApplication(pkg spdx.Package) *ftypes.Application { app := &ftypes.Application{ Type: pkg.PackageName, @@ -175,7 +188,7 @@ func parseOS(pkg spdx.Package) ftypes.OS { } } -func parsePkg(spdxPkg spdx.Package) (*ftypes.Package, error) { +func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes.Package, error) { pkg, pkgType, err := parseExternalReferences(spdxPkg.PackageExternalReferences) if err != nil { return nil, xerrors.Errorf("external references error: %w", err) @@ -192,9 +205,9 @@ func parsePkg(spdxPkg spdx.Package) (*ftypes.Package, error) { return nil, xerrors.Errorf("failed to parse source info: %w", err) } } - for _, f := range spdxPkg.Files { - pkg.FilePath = f.FileName - break // Take the first file name + + if path, ok := packageFilePaths[string(spdxPkg.PackageSPDXIdentifier)]; ok { + pkg.FilePath = path } pkg.ID = lookupAttributionTexts(spdxPkg.PackageAttributionTexts, PropertyPkgID) @@ -246,3 +259,30 @@ func parseSourceInfo(pkgType, sourceInfo string) (epoch int, name, ver, rel stri } return epoch, name, ver, rel, nil } + +// getPackageFilePaths parses Relationships and finds filepaths for packages +func getPackageFilePaths(spdxDocument *spdx.Document) map[string]string { + packageFilePaths := map[string]string{} + fileSPDXIdentifierMap := createFileSPDXIdentifierMap(spdxDocument.Files) + for _, rel := range spdxDocument.Relationships { + if rel.Relationship == common.TypeRelationshipDescribe || rel.Relationship == "DESCRIBE" { + // Skip the DESCRIBES relationship. + continue + } + + // hasFiles field is deprecated + // https://github.com/spdx/tools-golang/issues/171 + // hasFiles values converted in Relationships + // https://github.com/spdx/tools-golang/pull/201 + if isFile(rel.RefB.ElementRefID) { + file, ok := fileSPDXIdentifierMap[string(rel.RefB.ElementRefID)] + if ok { + // Save filePaths for packages + // Insert filepath will be later + packageFilePaths[string(rel.RefA.ElementRefID)] = file.FileName + } + continue + } + } + return packageFilePaths +} diff --git a/pkg/sbom/spdx/unmarshal_test.go b/pkg/sbom/spdx/unmarshal_test.go index 12071e6f8acf..3cddf4106349 100644 --- a/pkg/sbom/spdx/unmarshal_test.go +++ b/pkg/sbom/spdx/unmarshal_test.go @@ -110,6 +110,69 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, }, }, + { + name: "happy path for bom with hasFiles field", + inputFile: "testdata/happy/with-hasfiles-bom.json", + want: types.SBOM{ + Applications: []ftypes.Application{ + { + Type: "node-pkg", + Libraries: []ftypes.Package{ + { + ID: "yargs-parser@21.1.1", + Name: "yargs-parser", + Version: "21.1.1", + Licenses: []string{"ISC"}, + Ref: "pkg:npm/yargs-parser@21.1.1", + FilePath: "node_modules/yargs-parser/package.json", + }, + }, + }, + }, + }, + }, + { + name: "happy path for bom with hasFiles field", + inputFile: "testdata/happy/with-hasfiles-bom.json", + want: types.SBOM{ + Applications: []ftypes.Application{ + { + Type: "node-pkg", + Libraries: []ftypes.Package{ + { + ID: "yargs-parser@21.1.1", + Name: "yargs-parser", + Version: "21.1.1", + Licenses: []string{"ISC"}, + Ref: "pkg:npm/yargs-parser@21.1.1", + FilePath: "node_modules/yargs-parser/package.json", + }, + }, + }, + }, + }, + }, + { + name: "happy path for bom files in relationships", + inputFile: "testdata/happy/with-files-in-relationships-bom.json", + want: types.SBOM{ + Applications: []ftypes.Application{ + { + Type: "node-pkg", + Libraries: []ftypes.Package{ + { + ID: "yargs-parser@21.1.1", + Name: "yargs-parser", + Version: "21.1.1", + Licenses: []string{"ISC"}, + Ref: "pkg:npm/yargs-parser@21.1.1", + FilePath: "node_modules/yargs-parser/package.json", + }, + }, + }, + }, + }, + }, { name: "happy path for unrelated bom", inputFile: "testdata/happy/unrelated-bom.json", From 5c31b674e309e6e299a54a88160661b94e57b8ee Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 31 May 2023 13:28:05 +0600 Subject: [PATCH 2/4] refactor --- .../spdx/testdata/happy/with-files-in-relationships-bom.json | 2 +- pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json b/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json index bea4ab4f746e..577bff237946 100644 --- a/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json +++ b/pkg/sbom/spdx/testdata/happy/with-files-in-relationships-bom.json @@ -8,7 +8,7 @@ "licenseListVersion": "", "creators": [ "Organization: aquasecurity", - "Tool: trivy-0.36.2-107-gb0c591ef" + "Tool: trivy-dev" ], "created": "2023-05-31T05:58:45Z" }, diff --git a/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json b/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json index fdfe73df8a96..c0d836442405 100644 --- a/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json +++ b/pkg/sbom/spdx/testdata/happy/with-hasfiles-bom.json @@ -3,7 +3,7 @@ "creationInfo": { "created": "2023-05-31T04:56:43Z", "creators": [ - "Tool: trivy-0.40.0", + "Tool: trivy-dev", "Organization: aquasecurity" ] }, From c42bd1b7bc783a8734e2d68a867dcb1833790494 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 31 May 2023 13:44:58 +0600 Subject: [PATCH 3/4] test: sort Files for integration tests --- integration/integration_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration/integration_test.go b/integration/integration_test.go index eb87db5eee4c..5559da4f8fa3 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -178,6 +178,10 @@ func readSpdxJson(t *testing.T, filePath string) *spdx.Document { return bom.Relationships[i].RefB.ElementRefID < bom.Relationships[j].RefB.ElementRefID }) + sort.Slice(bom.Files, func(i, j int) bool { + return bom.Files[i].FileSPDXIdentifier < bom.Files[j].FileSPDXIdentifier + }) + // We don't compare values which change each time an SBOM is generated bom.CreationInfo.Created = "" bom.DocumentNamespace = "" From 01bb6e38d3d8f6d560300e02404b218ee2bd7111 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:52:25 +0600 Subject: [PATCH 4/4] use CONTAIN for get files Co-authored-by: Teppei Fukuda --- pkg/sbom/spdx/unmarshal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sbom/spdx/unmarshal.go b/pkg/sbom/spdx/unmarshal.go index 8dca8603b555..51c84b82c664 100644 --- a/pkg/sbom/spdx/unmarshal.go +++ b/pkg/sbom/spdx/unmarshal.go @@ -265,7 +265,7 @@ func getPackageFilePaths(spdxDocument *spdx.Document) map[string]string { packageFilePaths := map[string]string{} fileSPDXIdentifierMap := createFileSPDXIdentifierMap(spdxDocument.Files) for _, rel := range spdxDocument.Relationships { - if rel.Relationship == common.TypeRelationshipDescribe || rel.Relationship == "DESCRIBE" { + if rel.Relationship != common.TypeRelationshipContains && rel.Relationship != "CONTAIN" { // Skip the DESCRIBES relationship. continue }