From e5072f1eef8f3a78f4db48b4ac3f7c48aeec5e92 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 6 Mar 2025 17:52:01 +0600 Subject: [PATCH] fix(spdx): save text licenses into `otherLicenses` without normalize (#8502) Co-authored-by: Teppei Fukuda --- pkg/sbom/spdx/marshal.go | 19 +++++++++++++------ pkg/sbom/spdx/marshal_private_test.go | 8 ++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index ac91da0fa427..3d21f3657e3f 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -416,6 +416,16 @@ func (m *Marshaler) normalizeLicenses(licenses []string) (string, []*spdx.OtherL var otherLicenses = make(map[string]*spdx.OtherLicense) // licenseID -> OtherLicense license := strings.Join(lo.Map(licenses, func(license string, index int) string { + // We need to save text licenses before normalization, + // because it is impossible to handle all cases possible in the text. + // as an example, parse a license with 2 consecutive tokens (see https://github.com/aquasecurity/trivy/issues/8465) + if strings.HasPrefix(license, licensing.LicenseTextPrefix) { + license = strings.TrimPrefix(license, licensing.LicenseTextPrefix) + otherLicense := m.newOtherLicense(license, true) + otherLicenses[otherLicense.LicenseIdentifier] = otherLicense + return otherLicense.LicenseIdentifier + } + // e.g. GPL-3.0-with-autoconf-exception license = strings.ReplaceAll(license, "-with-", " WITH ") license = strings.ReplaceAll(license, "-WITH-", " WITH ") @@ -424,13 +434,10 @@ func (m *Marshaler) normalizeLicenses(licenses []string) (string, []*spdx.OtherL replaceOtherLicenses := func(expr expression.Expression) expression.Expression { var licenseName string - var textLicense bool switch e := expr.(type) { case expression.SimpleExpr: - // Trim `text:--` prefix (expression.NormalizeForSPDX normalized `text://` prefix) - if strings.HasPrefix(e.License, "text:--") { - textLicense = true - e.License = strings.TrimPrefix(e.License, "text:--") + if strings.HasPrefix(e.License, LicenseRefPrefix) { + return e } if expression.ValidateSPDXLicense(e.License) || expression.ValidateSPDXException(e.License) { @@ -454,7 +461,7 @@ func (m *Marshaler) normalizeLicenses(licenses []string) (string, []*spdx.OtherL licenseName = e.String() } - l := m.newOtherLicense(licenseName, textLicense) + l := m.newOtherLicense(licenseName, false) otherLicenses[l.LicenseIdentifier] = l return expression.SimpleExpr{License: l.LicenseIdentifier} } diff --git a/pkg/sbom/spdx/marshal_private_test.go b/pkg/sbom/spdx/marshal_private_test.go index 3f2161bd40ed..60d7945efef2 100644 --- a/pkg/sbom/spdx/marshal_private_test.go +++ b/pkg/sbom/spdx/marshal_private_test.go @@ -100,11 +100,11 @@ func TestMarshaler_normalizeLicenses(t *testing.T) { { name: "happy path with text of license", input: []string{ - "text://unknown-license", + "text://Redistribution and use in source and binary forms, with or without", "AFL 2.0", "unknown-license", }, - wantLicenseName: "LicenseRef-ffca10435cadded4 AND AFL-2.0 AND LicenseRef-a0bb0951a6dfbdbe", + wantLicenseName: "LicenseRef-b5b4cc09bc5f0e16 AND AFL-2.0 AND LicenseRef-a0bb0951a6dfbdbe", wantOtherLicenses: []*spdx.OtherLicense{ { LicenseIdentifier: "LicenseRef-a0bb0951a6dfbdbe", @@ -112,9 +112,9 @@ func TestMarshaler_normalizeLicenses(t *testing.T) { ExtractedText: `This component is licensed under "unknown-license"`, }, { - LicenseIdentifier: "LicenseRef-ffca10435cadded4", + LicenseIdentifier: "LicenseRef-b5b4cc09bc5f0e16", LicenseName: "NOASSERTION", - ExtractedText: "unknown-license", + ExtractedText: "Redistribution and use in source and binary forms, with or without", LicenseComment: "The license text represents text found in package metadata and may not represent the full text of the license", }, },