diff --git a/syft/format/internal/spdxutil/helpers/license.go b/syft/format/internal/spdxutil/helpers/license.go index ae19dfb1d..c6db3d819 100644 --- a/syft/format/internal/spdxutil/helpers/license.go +++ b/syft/format/internal/spdxutil/helpers/license.go @@ -80,7 +80,7 @@ func ParseLicenses(raw []pkg.License) (concluded, declared []SPDXLicense) { func createSPDXLicense(l pkg.License) SPDXLicense { candidate := SPDXLicense{ ID: generateLicenseID(l), - FullText: l.FullText, + FullText: l.Contents, } if l.SPDXExpression == "" { @@ -96,7 +96,7 @@ func generateLicenseID(l pkg.License) string { if l.Value != "" { return spdxlicense.LicenseRefPrefix + SanitizeElementID(l.Value) } - return licenseSum(l.FullText) + return licenseSum(l.Contents) } func licenseSum(s string) string { diff --git a/syft/format/internal/spdxutil/helpers/license_test.go b/syft/format/internal/spdxutil/helpers/license_test.go index 81f0359f6..19e466ab4 100644 --- a/syft/format/internal/spdxutil/helpers/license_test.go +++ b/syft/format/internal/spdxutil/helpers/license_test.go @@ -116,7 +116,7 @@ func TestGenerateLicenseID(t *testing.T) { license: pkg.License{ SPDXExpression: "Apache-2.0", Value: "SomeValue", - FullText: "Some text", + Contents: "Some text", }, expected: "Apache-2.0", }, @@ -136,9 +136,9 @@ func TestGenerateLicenseID(t *testing.T) { "LGPLv2--and-LGPLv2--with-exceptions-and-GPLv2--and-GPLv2--with-exceptions-and-BSD-and-Inner-Net-and-ISC-and-Public-Domain-and-GFDL", }, { - name: "Uses hash of fullText when nothing else is provided", + name: "Uses hash of contents when nothing else is provided", license: pkg.License{ - FullText: "This is a very long custom license text that should be hashed because it's more than 64 characters long.", + Contents: "This is a very long custom license text that should be hashed because it's more than 64 characters long.", }, expected: "", // We'll verify it starts with the correct prefix }, diff --git a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONDirectoryEncoder.golden b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONDirectoryEncoder.golden index fb83fe604..110d291dd 100644 --- a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONDirectoryEncoder.golden +++ b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONDirectoryEncoder.golden @@ -15,7 +15,7 @@ "packages": [ { "name": "package-1", - "SPDXID": "SPDXRef-Package-python-package-1-cf21bacaa74c8c08", + "SPDXID": "SPDXRef-Package-python-package-1-4dd25c6ee16b729a", "versionInfo": "1.0.1", "supplier": "NOASSERTION", "downloadLocation": "NOASSERTION", @@ -76,7 +76,7 @@ "relationships": [ { "spdxElementId": "SPDXRef-DocumentRoot-Directory-some-path", - "relatedSpdxElement": "SPDXRef-Package-python-package-1-cf21bacaa74c8c08", + "relatedSpdxElement": "SPDXRef-Package-python-package-1-4dd25c6ee16b729a", "relationshipType": "CONTAINS" }, { diff --git a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONImageEncoder.golden b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONImageEncoder.golden index 4cee4ec12..3a75a972c 100644 --- a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONImageEncoder.golden +++ b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXJSONImageEncoder.golden @@ -15,7 +15,7 @@ "packages": [ { "name": "package-1", - "SPDXID": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "SPDXID": "SPDXRef-Package-python-package-1-72567175418f73f8", "versionInfo": "1.0.1", "supplier": "NOASSERTION", "downloadLocation": "NOASSERTION", @@ -90,7 +90,7 @@ "relationships": [ { "spdxElementId": "SPDXRef-DocumentRoot-Image-user-image-input", - "relatedSpdxElement": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "relatedSpdxElement": "SPDXRef-Package-python-package-1-72567175418f73f8", "relationshipType": "CONTAINS" }, { diff --git a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden index e69eeada1..2a8ad1ebe 100644 --- a/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden +++ b/syft/format/spdxjson/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden @@ -15,7 +15,7 @@ "packages": [ { "name": "package-1", - "SPDXID": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "SPDXID": "SPDXRef-Package-python-package-1-72567175418f73f8", "versionInfo": "1.0.1", "supplier": "NOASSERTION", "downloadLocation": "NOASSERTION", @@ -199,38 +199,38 @@ ], "relationships": [ { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-f1-5265a4dde3edbf7c", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-z1-f5-839d99ee67d9d174", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-a1-f6-9c2f7510199b17f6", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-d2-f4-c641caa71518099f", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-d1-f3-c6f5b29dca12661f", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "spdxElementId": "SPDXRef-Package-python-package-1-72567175418f73f8", "relatedSpdxElement": "SPDXRef-File-f2-f9e49132a4b96ccd", "relationshipType": "CONTAINS" }, { "spdxElementId": "SPDXRef-DocumentRoot-Image-user-image-input", - "relatedSpdxElement": "SPDXRef-Package-python-package-1-2d8996d6f81313df", + "relatedSpdxElement": "SPDXRef-Package-python-package-1-72567175418f73f8", "relationshipType": "CONTAINS" }, { diff --git a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden index 4690c8895..bc4804074 100644 --- a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden +++ b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXRelationshipOrder.golden @@ -91,7 +91,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1 ##### Package: package-1 PackageName: package-1 -SPDXID: SPDXRef-Package-python-package-1-2d8996d6f81313df +SPDXID: SPDXRef-Package-python-package-1-72567175418f73f8 PackageVersion: 1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION @@ -105,13 +105,13 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-1 ##### Relationships -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-f1-5265a4dde3edbf7c -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-z1-f5-839d99ee67d9d174 -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-a1-f6-9c2f7510199b17f6 -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-d2-f4-c641caa71518099f -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-d1-f3-c6f5b29dca12661f -Relationship: SPDXRef-Package-python-package-1-2d8996d6f81313df CONTAINS SPDXRef-File-f2-f9e49132a4b96ccd -Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-2d8996d6f81313df +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-f1-5265a4dde3edbf7c +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-z1-f5-839d99ee67d9d174 +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-a1-f6-9c2f7510199b17f6 +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-d2-f4-c641caa71518099f +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-d1-f3-c6f5b29dca12661f +Relationship: SPDXRef-Package-python-package-1-72567175418f73f8 CONTAINS SPDXRef-File-f2-f9e49132a4b96ccd +Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-72567175418f73f8 Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-deb-package-2-4b756c6f6fb127a3 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Image-user-image-input diff --git a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueDirectoryEncoder.golden b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueDirectoryEncoder.golden index 4ed78e787..69d8e7e8a 100644 --- a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueDirectoryEncoder.golden +++ b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueDirectoryEncoder.golden @@ -38,7 +38,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1 ##### Package: package-1 PackageName: package-1 -SPDXID: SPDXRef-Package-python-package-1-cf21bacaa74c8c08 +SPDXID: SPDXRef-Package-python-package-1-4dd25c6ee16b729a PackageVersion: 1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION @@ -52,7 +52,7 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-2 ##### Relationships -Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-python-package-1-cf21bacaa74c8c08 +Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-python-package-1-4dd25c6ee16b729a Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-deb-package-2-39392bb5e270f669 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Directory-some-path diff --git a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueImageEncoder.golden b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueImageEncoder.golden index b9bf89066..2031d7663 100644 --- a/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueImageEncoder.golden +++ b/syft/format/spdxtagvalue/test-fixtures/snapshot/TestSPDXTagValueImageEncoder.golden @@ -41,7 +41,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1 ##### Package: package-1 PackageName: package-1 -SPDXID: SPDXRef-Package-python-package-1-2d8996d6f81313df +SPDXID: SPDXRef-Package-python-package-1-72567175418f73f8 PackageVersion: 1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION @@ -55,7 +55,7 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-1 ##### Relationships -Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-2d8996d6f81313df +Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-72567175418f73f8 Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-deb-package-2-4b756c6f6fb127a3 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Image-user-image-input diff --git a/syft/format/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden b/syft/format/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden index 4cdd71385..8ced61f4e 100644 --- a/syft/format/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden +++ b/syft/format/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden @@ -1,7 +1,7 @@ { "artifacts": [ { - "id": "cf21bacaa74c8c08", + "id": "4dd25c6ee16b729a", "name": "package-1", "version": "1.0.1", "type": "python", diff --git a/syft/format/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden b/syft/format/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden index ddb03d0a1..3c017a4de 100644 --- a/syft/format/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden +++ b/syft/format/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden @@ -1,7 +1,7 @@ { "artifacts": [ { - "id": "783177db0211edb6", + "id": "fba4ca04d4906f25", "name": "package-1", "version": "1.0.1", "type": "python", diff --git a/syft/format/syftjson/test-fixtures/snapshot/TestImageEncoder.golden b/syft/format/syftjson/test-fixtures/snapshot/TestImageEncoder.golden index 28f43c5e8..62379330c 100644 --- a/syft/format/syftjson/test-fixtures/snapshot/TestImageEncoder.golden +++ b/syft/format/syftjson/test-fixtures/snapshot/TestImageEncoder.golden @@ -1,7 +1,7 @@ { "artifacts": [ { - "id": "2d8996d6f81313df", + "id": "72567175418f73f8", "name": "package-1", "version": "1.0.1", "type": "python", diff --git a/syft/format/syftjson/to_format_model.go b/syft/format/syftjson/to_format_model.go index de93611bb..7cb264bef 100644 --- a/syft/format/syftjson/to_format_model.go +++ b/syft/format/syftjson/to_format_model.go @@ -230,12 +230,11 @@ func toLicenseModel(pkgLicenses []pkg.License) (modelLicenses []model.License) { modelLicenses = append(modelLicenses, model.License{ Value: l.Value, - FullText: l.FullText, SPDXExpression: l.SPDXExpression, + Contents: l.Contents, Type: l.Type, URLs: urls, Locations: locations, - Contents: l.Contents, }) } return diff --git a/syft/pkg/license.go b/syft/pkg/license.go index 43fdd85cb..4fefff98c 100644 --- a/syft/pkg/license.go +++ b/syft/pkg/license.go @@ -27,17 +27,16 @@ var _ sort.Interface = (*Licenses)(nil) // of where a license was declared/concluded for a given package // If a license is given as it's full text in the metadata rather than it's value or SPDX expression -// The FullText field is used to represent this data +// The Contents field is used to represent this data // A Concluded License type is the license the SBOM creator believes governs the package (human crafted or altered SBOM) // The Declared License is what the authors of a project believe govern the package. This is the default type syft declares. type License struct { SPDXExpression string Value string - FullText string Type license.Type + Contents string URLs []string `hash:"ignore"` Locations file.LocationSet `hash:"ignore"` - Contents string `hash:"ignore"` // The optional binary contents of the license file } type Licenses []License @@ -93,7 +92,7 @@ func NewLicenseFromType(value string, t license.Type) License { if fullText != "" { return License{ - FullText: fullText, + Contents: fullText, Type: t, Locations: file.NewLocationSet(), } @@ -180,7 +179,7 @@ func NewLicenseFromFields(value, url string, location *file.Location) License { } func (s License) Empty() bool { - return s.Value == "" && s.SPDXExpression == "" && s.FullText == "" + return s.Value == "" && s.SPDXExpression == "" && s.Contents == "" } // Merge two licenses into a new license object. If the merge is not possible due to unmergeable fields diff --git a/syft/pkg/license_set_test.go b/syft/pkg/license_set_test.go index 15da2bb76..cecaa6b9c 100644 --- a/syft/pkg/license_set_test.go +++ b/syft/pkg/license_set_test.go @@ -1,6 +1,7 @@ package pkg import ( + "os" "testing" "github.com/google/go-cmp/cmp" @@ -125,6 +126,23 @@ func TestLicenseSet_Add(t *testing.T) { }, }, }, + { + name: "licenses that are unknown with different contents can exist in the same set", + licenses: []License{ + NewLicense(readFileAsString("../../internal/licenses/test-fixtures/nvidia-software-and-cuda-supplement")), + NewLicense(readFileAsString("../../internal/licenses/test-fixtures/apache-license-2.0")), + }, + want: []License{ + { + Contents: readFileAsString("../../internal/licenses/test-fixtures/apache-license-2.0"), + Type: license.Declared, + }, + { + Contents: readFileAsString("../../internal/licenses/test-fixtures/nvidia-software-and-cuda-supplement"), + Type: license.Declared, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -160,3 +178,11 @@ func defaultLicenseComparer(x, y License) bool { }, )) } + +func readFileAsString(filepath string) string { + data, err := os.ReadFile(filepath) + if err != nil { + panic(err) + } + return string(data) +} diff --git a/syft/pkg/license_test.go b/syft/pkg/license_test.go index 52a255b4f..dccfca749 100644 --- a/syft/pkg/license_test.go +++ b/syft/pkg/license_test.go @@ -240,7 +240,7 @@ func TestFullText(t *testing.T) { want: License{ Value: "", Type: license.Declared, - FullText: fullText, + Contents: fullText, }, }, }