From e1374f758ef822d377dabcc4b1afa9c36267917f Mon Sep 17 00:00:00 2001 From: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com> Date: Fri, 16 May 2025 10:25:15 -0400 Subject: [PATCH] fix: update license content filtering default case to be 'none' for no content returned --------- Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com> --- cmd/syft/internal/options/license.go | 44 +++---------------- internal/task/package_task_factory.go | 10 ++--- internal/task/package_task_factory_test.go | 37 +++++++++++++++- syft/cataloging/license.go | 4 -- .../spdxhelpers/to_format_model_test.go | 2 +- .../internal/spdxutil/helpers/license.go | 2 +- syft/pkg/license.go | 2 +- syft/pkg/license_set_test.go | 2 +- syft/pkg/license_test.go | 2 +- 9 files changed, 52 insertions(+), 53 deletions(-) diff --git a/cmd/syft/internal/options/license.go b/cmd/syft/internal/options/license.go index c9eef8769..02f259058 100644 --- a/cmd/syft/internal/options/license.go +++ b/cmd/syft/internal/options/license.go @@ -4,18 +4,13 @@ import ( "fmt" "github.com/anchore/clio" + "github.com/anchore/syft/internal" "github.com/anchore/syft/syft/cataloging" ) type licenseConfig struct { - Content cataloging.LicenseContent `yaml:"content" json:"content" mapstructure:"content"` - // Deprecated: please use include-license-content instead - IncludeUnknownLicenseContent *bool `yaml:"-" json:"-" mapstructure:"include-unknown-license-content"` - - Coverage float64 `yaml:"coverage" json:"coverage" mapstructure:"coverage"` - // Deprecated: please use coverage instead - LicenseCoverage *float64 `yaml:"license-coverage" json:"license-coverage" mapstructure:"license-coverage"` - + Content cataloging.LicenseContent `yaml:"content" json:"content" mapstructure:"content"` + Coverage float64 `yaml:"coverage" json:"coverage" mapstructure:"coverage"` AvailableLicenseContent []cataloging.LicenseContent `yaml:"-" json:"-" mapstructure:"-"` } @@ -25,43 +20,16 @@ var _ interface { func (o *licenseConfig) DescribeFields(descriptions clio.FieldDescriptionSet) { descriptions.Add(&o.Content, fmt.Sprintf("include the content of licenses in the SBOM for a given syft scan; valid values are: %s", o.AvailableLicenseContent)) - descriptions.Add(&o.IncludeUnknownLicenseContent, `deprecated: please use 'license-content' instead`) descriptions.Add(&o.Coverage, `adjust the percent as a fraction of the total text, in normalized words, that matches any valid license for the given inputs, expressed as a percentage across all of the licenses matched.`) - descriptions.Add(&o.LicenseCoverage, `deprecated: please use 'coverage' instead`) } func (o *licenseConfig) PostLoad() error { - cfg := cataloging.DefaultLicenseConfig() - defaultContent := cfg.IncludeContent - defaultCoverage := cfg.Coverage - - // if both legacy and new fields are specified, error out - if o.IncludeUnknownLicenseContent != nil && o.Content != defaultContent { - return fmt.Errorf("both 'include-unknown-license-content' and 'content' are set, please use only 'content'") + validContent := internal.NewSet(o.AvailableLicenseContent...) + if !validContent.Contains(o.Content) { + return fmt.Errorf("could not use %q as license content option; valid values are: %v", o.Content, validContent.ToSlice()) } - - if o.LicenseCoverage != nil && o.Coverage != defaultCoverage { - return fmt.Errorf("both 'license-coverage' and 'coverage' are set, please use only 'coverage'") - } - - // finalize the license content value - if o.IncludeUnknownLicenseContent != nil { - // convert 'include-unknown-license-content' -> 'license-content' - v := cataloging.LicenseContentExcludeAll - if *o.IncludeUnknownLicenseContent { - v = cataloging.LicenseContentIncludeUnknown - } - o.Content = v - } - - // finalize the coverage value - if o.LicenseCoverage != nil { - // convert 'license-coverage' -> 'coverage' - o.Coverage = *o.LicenseCoverage - } - return nil } diff --git a/internal/task/package_task_factory.go b/internal/task/package_task_factory.go index 7834edeb1..0e83bf2ca 100644 --- a/internal/task/package_task_factory.go +++ b/internal/task/package_task_factory.go @@ -278,16 +278,16 @@ func applyLicenseContentRules(p *pkg.Package, cfg cataloging.LicenseConfig) { l := &licenses[i] switch cfg.IncludeContent { case cataloging.LicenseContentIncludeUnknown: - // we don't have an SPDX expression, which means we didn't find an SPDX license - // include the unknown licenses content in the final SBOM + // we have an SPDX expression, which means this is NOT an unknown license + // remove the content, we are only including content for unknown licenses by default if l.SPDXExpression != "" { licenses[i].Contents = "" } - case cataloging.LicenseContentExcludeAll: - // clear it all out - licenses[i].Contents = "" case cataloging.LicenseContentIncludeAll: // always include the content + default: + // clear it all out + licenses[i].Contents = "" } } diff --git a/internal/task/package_task_factory_test.go b/internal/task/package_task_factory_test.go index d42030794..f1b8a217c 100644 --- a/internal/task/package_task_factory_test.go +++ b/internal/task/package_task_factory_test.go @@ -174,7 +174,7 @@ func TestApplyLicenseContentRules(t *testing.T) { }, }, { - name: "IncludeLicenseContentDefault", + name: "LicenseContentIncludeAll", inputLicenses: []pkg.License{ licenseWithSPDX, licenseWithoutSPDX, @@ -193,6 +193,41 @@ func TestApplyLicenseContentRules(t *testing.T) { }, }, }, + { + name: "default license config should be LicenseContentExcludeAll", + inputLicenses: []pkg.License{ + licenseWithSPDX, + licenseWithoutSPDX, + }, + cfg: cataloging.DefaultLicenseConfig(), + expectedLicenses: []pkg.License{ + { + SPDXExpression: "MIT", + }, + { + Value: "License-Not-A-SPDX-Expression", + }, + }, + }, + { + name: "invalid license content cataloging config results in the default case", + inputLicenses: []pkg.License{ + licenseWithSPDX, + licenseWithoutSPDX, + }, + cfg: cataloging.LicenseConfig{ + IncludeContent: cataloging.LicenseContent("invalid"), + }, + expectedLicenses: []pkg.License{ + { + SPDXExpression: "MIT", + }, + { + Value: "License-Not-A-SPDX-Expression", + Contents: "", // content all removed + }, + }, + }, { name: "Empty licenses", inputLicenses: []pkg.License{}, diff --git a/syft/cataloging/license.go b/syft/cataloging/license.go index 6d8e58fea..f7b36ddd9 100644 --- a/syft/cataloging/license.go +++ b/syft/cataloging/license.go @@ -14,10 +14,6 @@ const ( ) type LicenseConfig struct { - // IncludeUnknownLicenseContent controls whether the content of a license should be included in the SBOM when the license ID cannot be determined. - // Deprecated: use IncludeContent instead - IncludeUnknownLicenseContent bool `json:"-" yaml:"-" mapstructure:"-"` - // IncludeContent controls whether license copy discovered should be included in the SBOM. IncludeContent LicenseContent `json:"include-content" yaml:"include-content" mapstructure:"include-content"` diff --git a/syft/format/common/spdxhelpers/to_format_model_test.go b/syft/format/common/spdxhelpers/to_format_model_test.go index fe666c3bf..4a3182f06 100644 --- a/syft/format/common/spdxhelpers/to_format_model_test.go +++ b/syft/format/common/spdxhelpers/to_format_model_test.go @@ -958,7 +958,7 @@ func Test_otherLicenses(t *testing.T) { { LicenseIdentifier: "LicenseRef-3f17782eef51ae86f18fdd6832f5918e2b40f688b52c9adc07ba6ec1024ef408", // Carries through the syft-json license value when we shasum large texts - LicenseName: "LicenseRef-sha256:3f17782eef51ae86f18fdd6832f5918e2b40f688b52c9adc07ba6ec1024ef408", + LicenseName: "sha256:3f17782eef51ae86f18fdd6832f5918e2b40f688b52c9adc07ba6ec1024ef408", ExtractedText: strings.TrimSpace(bigText), }, }, diff --git a/syft/format/internal/spdxutil/helpers/license.go b/syft/format/internal/spdxutil/helpers/license.go index 979ea16d5..8ba477a6a 100644 --- a/syft/format/internal/spdxutil/helpers/license.go +++ b/syft/format/internal/spdxutil/helpers/license.go @@ -73,7 +73,7 @@ func ParseLicenses(raw []pkg.License) (concluded, declared []SPDXLicense, otherL for _, l := range raw { candidate := createSPDXLicense(l) - // isCustomLicense determines if the candidate falls under https://spdx.github.io/spdx-spec/v2.3/other-licensing-information-detected/# + // this determines if the candidate falls under https://spdx.github.io/spdx-spec/v2.3/other-licensing-information-detected/# // of the SPDX spec, where: // - we should not have a complex SPDX expression // - if a single license, it should not be a known license (on the SPDX license list) diff --git a/syft/pkg/license.go b/syft/pkg/license.go index e0bbae8da..24a2a6875 100644 --- a/syft/pkg/license.go +++ b/syft/pkg/license.go @@ -365,7 +365,7 @@ func (b *licenseBuilder) licensesFromEvidenceAndContent(evidence []licenses.Evid func (b *licenseBuilder) licenseFromContentHash(content string) License { hash := sha256HexFromString(content) - value := "LicenseRef-sha256:" + hash + value := "sha256:" + hash return License{ Value: value, diff --git a/syft/pkg/license_set_test.go b/syft/pkg/license_set_test.go index ada5502fa..ea7f81f75 100644 --- a/syft/pkg/license_set_test.go +++ b/syft/pkg/license_set_test.go @@ -149,7 +149,7 @@ func TestLicenseSet_Add(t *testing.T) { Locations: file.NewLocationSet(), }, { - Value: "LicenseRef-sha256:eebcea3ab1d1a28e671de90119ffcfb35fe86951e4af1b17af52b7a82fcf7d0a", + Value: "sha256:eebcea3ab1d1a28e671de90119ffcfb35fe86951e4af1b17af52b7a82fcf7d0a", Contents: readFileAsString("../../internal/licenses/test-fixtures/nvidia-software-and-cuda-supplement"), Type: license.Declared, }, diff --git a/syft/pkg/license_test.go b/syft/pkg/license_test.go index 101b8adeb..ac3066d31 100644 --- a/syft/pkg/license_test.go +++ b/syft/pkg/license_test.go @@ -255,7 +255,7 @@ func TestFullText(t *testing.T) { name: "Full Text field is populated with the correct full text and contents are given a sha256 as value", value: fullText, want: License{ - Value: "LicenseRef-sha256:108067fa71229a2b98b9696af0ce21cd11d9639634c8bc94bda70ebedf291e5a", + Value: "sha256:108067fa71229a2b98b9696af0ce21cd11d9639634c8bc94bda70ebedf291e5a", Type: license.Declared, Contents: fullText, },