From e7b65c2c58dd28a0ae102c04c77b42f2461458f5 Mon Sep 17 00:00:00 2001 From: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:00:59 -0500 Subject: [PATCH] 3030 license declared spdx correction (#3461) * feat: update hasExtractedLicense field to include license-ref candidates --------- Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com> --- .../common/spdxhelpers/to_format_model.go | 26 ++++++++++++++++--- .../spdxhelpers/to_format_model_test.go | 23 ++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/syft/format/common/spdxhelpers/to_format_model.go b/syft/format/common/spdxhelpers/to_format_model.go index 3f93883cf..643c5aa9f 100644 --- a/syft/format/common/spdxhelpers/to_format_model.go +++ b/syft/format/common/spdxhelpers/to_format_model.go @@ -5,6 +5,7 @@ import ( "crypto/sha1" "fmt" "path" + "regexp" "slices" "sort" "strings" @@ -713,8 +714,8 @@ func toFileTypes(metadata *file.Metadata) (ty []string) { return ty } -// other licenses are for licenses from the pkg.Package that do not have an SPDXExpression -// field. The spdxexpression field is only filled given a validated Value field. +// other licenses are for licenses from the pkg.Package that do not have a valid SPDX Expression +// OR are an expression that is a single `License-Ref-*` func toOtherLicenses(catalog *pkg.Collection) []*spdx.OtherLicense { licenses := map[string]helpers.SPDXLicense{} @@ -724,11 +725,17 @@ func toOtherLicenses(catalog *pkg.Collection) []*spdx.OtherLicense { if l.Value != "" { licenses[l.ID] = l } + if l.ID != "" && isLicenseRef(l.ID) { + licenses[l.ID] = l + } } for _, l := range concludedLicenses { if l.Value != "" { licenses[l.ID] = l } + if l.ID != "" && isLicenseRef(l.ID) { + licenses[l.ID] = l + } } } @@ -742,14 +749,27 @@ func toOtherLicenses(catalog *pkg.Collection) []*spdx.OtherLicense { slices.Sort(ids) for _, id := range ids { license := licenses[id] + value := license.Value + // handle cases where LicenseRef needs to be included in hasExtractedLicensingInfos + if license.Value == "" { + value, _ = strings.CutPrefix(license.ID, "LicenseRef-") + } result = append(result, &spdx.OtherLicense{ LicenseIdentifier: license.ID, - ExtractedText: license.Value, + ExtractedText: value, }) } return result } +var licenseRefRegEx = regexp.MustCompile(`^LicenseRef-[A-Za-z0-9_-]+$`) + +// isSingularLicenseRef checks if the string is a singular LicenseRef-* identifier +func isLicenseRef(s string) bool { + // Match the input string against the regex + return licenseRefRegEx.MatchString(s) +} + // TODO: handle SPDX excludes file case // f file is an "excludes" file, skip it /* exclude SPDX analysis file(s) */ // see: https://spdx.github.io/spdx-spec/v2.3/package-information/#79-package-verification-code-field diff --git a/syft/format/common/spdxhelpers/to_format_model_test.go b/syft/format/common/spdxhelpers/to_format_model_test.go index 934fc95dd..36201bc85 100644 --- a/syft/format/common/spdxhelpers/to_format_model_test.go +++ b/syft/format/common/spdxhelpers/to_format_model_test.go @@ -753,6 +753,29 @@ func Test_OtherLicenses(t *testing.T) { }, }, }, + { + name: "LicenseRef as a valid spdx expression", + pkg: pkg.Package{ + Licenses: pkg.NewLicenseSet( + pkg.NewLicense("LicenseRef-Fedora-Public-Domain"), + ), + }, + expected: []*spdx.OtherLicense{ + { + LicenseIdentifier: "LicenseRef-Fedora-Public-Domain", + ExtractedText: "Fedora-Public-Domain", + }, + }, + }, + { + name: "LicenseRef as a valid spdx expression does not otherize compound spdx expressions", + pkg: pkg.Package{ + Licenses: pkg.NewLicenseSet( + pkg.NewLicense("(MIT AND LicenseRef-Fedora-Public-Domain)"), + ), + }, + expected: nil, + }, } for _, test := range tests {