Skip to content

fix(license): strip plus operator from SPDX exception identifiers#10394

Closed
ogulcanaydogan wants to merge 1 commit intoaquasecurity:mainfrom
ogulcanaydogan:fix/license-exception-plus
Closed

fix(license): strip plus operator from SPDX exception identifiers#10394
ogulcanaydogan wants to merge 1 commit intoaquasecurity:mainfrom
ogulcanaydogan:fix/license-exception-plus

Conversation

@ogulcanaydogan
Copy link
Copy Markdown

Description

Fixes invalid SPDX license expressions where the + (or-later) operator was appended to exception identifiers in WITH clauses.

Per the SPDX spec (Annex D), the + operator is only valid after a license identifier, not an exception identifier. Trivy was generating expressions like GPL-3.0-only WITH autoconf-exception+, which is invalid.

Root Cause

In NormalizeForSPDX, when handling WITH expressions, the right-hand side (exception) was not having its HasPlus flag stripped. This caused two problems:

  1. The SPDX exception lookup failed because spdxExceptions keys don't include +
  2. The final .String() output included the invalid + suffix on the exception

Changes

  • pkg/licensing/expression/expression.go: Strip HasPlus from exception SimpleExpr in NormalizeForSPDX when handling WITH clauses. Also return the stripped expression even when the exception is not in the SPDX list.
  • pkg/licensing/expression/expression_test.go: Add test cases for exception with +, exception with + (Bison), and exception without + (unchanged).

Reproduction

trivy image bitnami/wordpress --format spdx-json | grep "autoconf-exception+"

Fixes #7838

The '+' (or-later) operator is only valid after a license identifier,
not after an exception identifier per the SPDX spec. Trivy was
generating invalid expressions like 'GPL-3.0-only WITH autoconf-exception+'
because NormalizeForSPDX did not strip HasPlus from the right side of
WITH clauses. This also caused the SPDX exception lookup to fail since
the map keys don't include '+'.

Fixes aquasecurity#7838
@DmitriyLewen
Copy link
Copy Markdown
Contributor

Hello @ogulcanaydogan
Thanks for your work.

trivy image bitnami/wordpress --format spdx-json | grep "autoconf-exception+"

Can you reproduce this case?
I couldn't get an incorrect result.

We added logic for searching SPDX license IDs and expressions from official lists.
If I understand correctly, "utoconf-exception+" won't be matched with the list and will be saved as other license (here's a test example -

{
name: "happy path with non-SPDX exception",
input: []string{
"AFL 2.0",
"AFL 3.0 with wrong-exceptions",
},
wantLicenseName: "AFL-2.0 AND LicenseRef-51373b28fab165e9",
wantOtherLicenses: []*spdx.OtherLicense{
{
LicenseIdentifier: "LicenseRef-51373b28fab165e9",
LicenseName: "AFL-3.0 WITH wrong-exceptions",
ExtractedText: `This component is licensed under "AFL-3.0 WITH wrong-exceptions"`,
},
},
},
).

@ogulcanaydogan
Copy link
Copy Markdown
Author

Hi @DmitriyLewen — thanks for looking into this and for the pointer to the test cases!

You're right. I tried to reproduce but couldn't get autoconf-exception+ in the output either. Looking at the code more carefully, I see the current normalization path already handles this correctly:

  1. NormalizeForSPDX looks up exceptions via spdxExceptions map (expression.go L80-86) — invalid suffixes like + won't match
  2. IsSPDXExpression() validates the exception via ValidateSPDXException — so any WITH expression with an invalid exception falls through to LicenseRef-xxx

The test case at marshal_test.go L1611-1625 confirms this behavior — non-SPDX exceptions get properly classified as OtherLicense.

It seems the bug from the original issue (Oct 2024) has been implicitly fixed by the SPDX expression normalization logic added since then. I'll close this PR.

Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

License exceptions with a plus sign

2 participants