From 6472e3c9da2a8e7ba41598a45c80df8f18e57d4c Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Wed, 11 Sep 2024 08:47:50 +0200 Subject: [PATCH] feat(license): improve license normalization (#7131) Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen Co-authored-by: knqyf263 --- .../alpine-39-high-critical.json.golden | 2 +- integration/testdata/alpine-39.json.golden | 2 +- .../testdata/alpine-distroless.json.golden | 2 +- ...fluentd-multiple-lockfiles.cdx.json.golden | 836 +++++++++++++----- .../testdata/license-cyclonedx.json.golden | 4 +- .../testdata/ubi-7-comprehensive.json.golden | 2 +- .../python/packaging/packaging_test.go | 10 +- pkg/fanal/analyzer/pkg/apk/apk.go | 22 +- pkg/fanal/analyzer/pkg/apk/apk_test.go | 21 +- pkg/fanal/analyzer/pkg/dpkg/copyright_test.go | 9 +- pkg/fanal/artifact/image/image_test.go | 25 +- .../goldens/packages/alpine-310.json.golden | 28 +- .../goldens/packages/vulnimage.json.golden | 76 +- pkg/flag/license_flags.go | 14 +- pkg/licensing/{ => expression}/category.go | 24 +- pkg/licensing/expression/expression.go | 12 +- pkg/licensing/expression/expression_test.go | 2 +- pkg/licensing/expression/parser.go.y | 6 +- pkg/licensing/expression/parser_gen.go | 6 +- pkg/licensing/expression/parser_test.go | 34 +- pkg/licensing/expression/types.go | 40 +- pkg/licensing/normalize.go | 786 ++++++++++++---- pkg/licensing/normalize_private_test.go | 18 + pkg/licensing/normalize_test.go | 239 +++++ pkg/licensing/scanner.go | 3 +- pkg/licensing/scanner_test.go | 17 +- pkg/sbom/spdx/marshal.go | 2 +- pkg/sbom/spdx/marshal_test.go | 6 +- 28 files changed, 1702 insertions(+), 546 deletions(-) rename pkg/licensing/{ => expression}/category.go (96%) create mode 100644 pkg/licensing/normalize_private_test.go diff --git a/integration/testdata/alpine-39-high-critical.json.golden b/integration/testdata/alpine-39-high-critical.json.golden index 408cd11d4988..26931273fd01 100644 --- a/integration/testdata/alpine-39-high-critical.json.golden +++ b/integration/testdata/alpine-39-high-critical.json.golden @@ -106,7 +106,7 @@ "PkgName": "musl-utils", "PkgIdentifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4", - "UID": "8c341199f4077fc8" + "UID": "a35dd6cab4aabdf1" }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", diff --git a/integration/testdata/alpine-39.json.golden b/integration/testdata/alpine-39.json.golden index 3e1089f3e7cb..35d3e2a5c1b7 100644 --- a/integration/testdata/alpine-39.json.golden +++ b/integration/testdata/alpine-39.json.golden @@ -418,7 +418,7 @@ "PkgName": "musl-utils", "PkgIdentifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4", - "UID": "8c341199f4077fc8" + "UID": "a35dd6cab4aabdf1" }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", diff --git a/integration/testdata/alpine-distroless.json.golden b/integration/testdata/alpine-distroless.json.golden index 4ba010f0eea0..da03075d0cd5 100644 --- a/integration/testdata/alpine-distroless.json.golden +++ b/integration/testdata/alpine-distroless.json.golden @@ -55,7 +55,7 @@ "PkgName": "git", "PkgIdentifier": { "PURL": "pkg:apk/alpine/git@2.35.1-r2?arch=x86_64\u0026distro=3.16", - "UID": "d44ac4666246b919" + "UID": "2999d822f6cae40c" }, "InstalledVersion": "2.35.1-r2", "FixedVersion": "2.35.2-r0", diff --git a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden index cc442e7d881d..65fc78e6c66f 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden @@ -81,7 +81,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -121,7 +121,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -161,7 +166,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -201,7 +206,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { @@ -246,7 +251,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -290,7 +295,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -320,22 +330,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -379,7 +409,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -424,7 +459,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -468,7 +503,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -552,7 +587,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -592,7 +627,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -632,12 +667,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -685,7 +720,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -740,12 +780,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" } } ], @@ -789,7 +829,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -819,22 +864,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -878,12 +943,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.3" + "name": "GFDL-1.3-only" } } ], @@ -927,27 +992,32 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.2" + "name": "GFDL-1.2-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } } ], @@ -991,7 +1061,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -1001,12 +1071,12 @@ }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -1016,7 +1086,7 @@ }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { @@ -1033,6 +1103,21 @@ "license": { "name": "CC0-1.0" } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/gpgv@2.2.12-1%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -1075,7 +1160,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } } ], @@ -1119,7 +1209,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -1163,7 +1253,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1208,7 +1298,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -1248,17 +1343,22 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -1302,7 +1402,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -1342,17 +1447,22 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-only" } } ], @@ -1400,17 +1510,17 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-only" } } ], @@ -1458,17 +1568,17 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-only" } } ], @@ -1516,7 +1626,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -1546,22 +1661,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -1605,12 +1740,12 @@ "licenses": [ { "license": { - "name": "BSD-variant" + "name": "BSD-3-Clause" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1654,12 +1789,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1703,12 +1838,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1752,17 +1887,17 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -1913,12 +2048,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" } } ], @@ -1962,7 +2097,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -1992,22 +2132,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -2051,7 +2211,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -2132,12 +2292,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -2181,17 +2341,27 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GFDL-1.3-no-invariants-or-later" } }, { "license": { - "name": "GFDL-NIV-1.3+" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -2235,17 +2405,27 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GFDL-1.3-no-invariants-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-NIV-1.3+" + "name": "GPL-2.0-only" } } ], @@ -2289,17 +2469,22 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -2347,43 +2532,58 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GFDL-1.3" + "name": "LGPL-3.0-only" } }, { "license": { - "name": "CC0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "The MIT License" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPLv3+" + "name": "GFDL-1.3-only" } }, { "license": { - "name": "GPL-2.0" + "name": "CC0-1.0" + } + }, + { + "license": { + "name": "MIT" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" } }, { "license": { "name": "Apache-2.0" } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } } ], "purl": "pkg:deb/debian/libgnutls30@3.6.7-4?arch=amd64&distro=debian-10.2", @@ -2426,7 +2626,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -2441,7 +2641,17 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" } } ], @@ -2522,23 +2732,38 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { "name": "Unicode" } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" + } } ], "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64&distro=debian-10.2", @@ -2596,7 +2821,7 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -2655,7 +2880,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -2709,12 +2939,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -2732,6 +2962,11 @@ "name": "permissive-nowarranty" } }, + { + "license": { + "name": "GPL-2.0-only" + } + }, { "license": { "name": "none" @@ -2744,7 +2979,12 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" } }, { @@ -2759,7 +2999,7 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -2803,7 +3043,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -2833,22 +3078,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -2966,47 +3231,47 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "other" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "other" } }, { "license": { - "name": "GPL-2.0-with-autoconf-exception" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "public-domain" + "name": "GPL-2.0-with-autoconf-exception+" } }, { "license": { - "name": "GAP" + "name": "public-domain" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GAP" } } ], @@ -3114,7 +3379,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3158,7 +3423,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3202,7 +3467,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3246,7 +3511,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3331,12 +3596,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -3390,12 +3655,12 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -3440,27 +3705,27 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "zlib/libpng" + "name": "zlib-acknowledgement" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-or-later" } }, { "license": { - "name": "CC0" + "name": "CC0-1.0" } }, { @@ -3472,6 +3737,16 @@ "license": { "name": "Permissive" } + }, + { + "license": { + "name": "GPL-1.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } } ], "purl": "pkg:deb/debian/libruby2.5@2.5.5-3%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -3514,7 +3789,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -3558,12 +3833,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -3607,12 +3882,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3656,12 +3931,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3705,12 +3980,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3754,7 +4029,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -3784,22 +4064,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -3954,7 +4254,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -3964,18 +4264,28 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { "name": "public-domain" } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/libsystemd0@241-7~deb10u2?arch=amd64&distro=debian-10.2", @@ -4018,22 +4328,22 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.3" + "name": "GFDL-1.3-only" } } ], @@ -4114,7 +4424,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -4124,18 +4434,28 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { "name": "public-domain" } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/libudev1@241-7~deb10u2?arch=amd64&distro=debian-10.2", @@ -4178,12 +4498,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { @@ -4198,12 +4518,12 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GFDL-1.2+" + "name": "GFDL-1.2-or-later" } }, { @@ -4213,7 +4533,22 @@ }, { "license": { - "name": "GFDL-1.2" + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GFDL-1.2-only" } } ], @@ -4257,7 +4592,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -4287,22 +4627,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -4346,7 +4706,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -4400,7 +4760,7 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { @@ -4410,7 +4770,12 @@ }, { "license": { - "name": "Expat" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "MIT" } } ], @@ -4454,7 +4819,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4502,7 +4867,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4546,7 +4911,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -4576,22 +4946,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -4746,7 +5136,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4831,7 +5221,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -4875,12 +5265,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -4924,7 +5314,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -4968,7 +5358,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -5120,7 +5510,7 @@ }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -5218,12 +5608,12 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -5268,27 +5658,27 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "zlib/libpng" + "name": "zlib-acknowledgement" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-or-later" } }, { "license": { - "name": "CC0" + "name": "CC0-1.0" } }, { @@ -5300,6 +5690,16 @@ "license": { "name": "Permissive" } + }, + { + "license": { + "name": "GPL-1.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } } ], "purl": "pkg:deb/debian/ruby2.5@2.5.5-3%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -5342,12 +5742,12 @@ "licenses": [ { "license": { - "name": "RubyLicense" + "name": "Ruby" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -5391,7 +5791,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -5431,7 +5831,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -5475,7 +5875,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -5519,12 +5924,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -5605,7 +6010,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -5635,22 +6045,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -6289,7 +6719,7 @@ "licenses": [ { "license": { - "name": "Apache License (2.0)" + "name": "Apache-2.0" } } ], @@ -7370,7 +7800,7 @@ "licenses": [ { "license": { - "name": "2-clause BSDL" + "name": "BSD-2-Clause" } } ], diff --git a/integration/testdata/license-cyclonedx.json.golden b/integration/testdata/license-cyclonedx.json.golden index cf69da9756ed..95f8acd896b1 100644 --- a/integration/testdata/license-cyclonedx.json.golden +++ b/integration/testdata/license-cyclonedx.json.golden @@ -47,8 +47,8 @@ "Link": "" }, { - "Severity": "UNKNOWN", - "Category": "unknown", + "Severity": "LOW", + "Category": "notice", "PkgName": "org.slf4j:slf4j-api", "FilePath": "", "Name": "MIT License", diff --git a/integration/testdata/ubi-7-comprehensive.json.golden b/integration/testdata/ubi-7-comprehensive.json.golden index 6df4b8241456..b500dc5d4bc5 100644 --- a/integration/testdata/ubi-7-comprehensive.json.golden +++ b/integration/testdata/ubi-7-comprehensive.json.golden @@ -147,7 +147,7 @@ "PkgPath": "usr/lib/python2.7/site-packages/setuptools-0.9.8-py2.7.egg-info/PKG-INFO", "PkgIdentifier": { "PURL": "pkg:pypi/setuptools@0.9.8", - "UID": "3f4c89bf681c1d7a" + "UID": "13d32ebdc7bda1b4" }, "InstalledVersion": "0.9.8", "FixedVersion": "65.5.1", diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go index c3a89ad0cd19..960a92dfec2b 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go @@ -33,7 +33,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { Name: "kitchen", Version: "1.2.6", Licenses: []string{ - "GNU Library or Lesser General Public License (LGPL)", + "LGPL-2.1-only", }, FilePath: "kitchen-1.2.6-py2.7.egg", }, @@ -55,7 +55,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "distlib", Version: "0.3.1", - Licenses: []string{"Python license"}, + Licenses: []string{"Python-2.0"}, FilePath: "distlib-0.3.1.egg-info/PKG-INFO", Digest: "sha1:d9d89d8ed3b2b683767c96814c9c5d3e57ef2e1b", }, @@ -76,7 +76,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "setuptools", Version: "51.3.3", - Licenses: []string{"MIT License"}, + Licenses: []string{"MIT"}, FilePath: "setuptools-51.3.3.egg-info/PKG-INFO", }, }, @@ -96,7 +96,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "setuptools", Version: "51.3.3", - Licenses: []string{"MIT License"}, + Licenses: []string{"MIT"}, FilePath: "setuptools-51.3.3.dist-info/METADATA", }, }, @@ -116,7 +116,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "distlib", Version: "0.3.1", - Licenses: []string{"Python license"}, + Licenses: []string{"Python-2.0"}, FilePath: "distlib-0.3.1.dist-info/METADATA", }, }, diff --git a/pkg/fanal/analyzer/pkg/apk/apk.go b/pkg/fanal/analyzer/pkg/apk/apk.go index 9ce13e4b013d..962398600fc5 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk.go +++ b/pkg/fanal/analyzer/pkg/apk/apk.go @@ -142,26 +142,8 @@ func (a alpinePkgAnalyzer) trimRequirement(s string) string { } func (a alpinePkgAnalyzer) parseLicense(line string) []string { - line = line[2:] // Remove "L:" - if line == "" { - return nil - } - var licenses []string - // e.g. MPL 2.0 GPL2+ => {"MPL2.0", "GPL2+"} - for i, s := range strings.Fields(line) { - s = strings.Trim(s, "()") - switch { - case s == "": - continue - case s == "AND" || s == "OR": - continue - case i > 0 && (s == "1.0" || s == "2.0" || s == "3.0"): - licenses[i-1] = licensing.Normalize(licenses[i-1] + s) - default: - licenses = append(licenses, licensing.Normalize(s)) - } - } - return licenses + // Remove "L:" before split + return licensing.LaxSplitLicenses(line[2:]) } func (a alpinePkgAnalyzer) parseProvides(line, pkgID string, provides map[string]string) { diff --git a/pkg/fanal/analyzer/pkg/apk/apk_test.go b/pkg/fanal/analyzer/pkg/apk/apk_test.go index 08a5d302d324..0491ed57c0d2 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk_test.go +++ b/pkg/fanal/analyzer/pkg/apk/apk_test.go @@ -33,7 +33,7 @@ var pkgs = []types.Package{ Version: "1.24.2-r9", SrcName: "busybox", SrcVersion: "1.24.2-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, DependsOn: []string{"musl@1.1.14-r10"}, Arch: "x86_64", Digest: "sha1:ca124719267cd0bedc2f4cb850a286ac13f0ad44", @@ -51,7 +51,7 @@ var pkgs = []types.Package{ Version: "3.0.3-r0", SrcName: "alpine-baselayout", SrcVersion: "3.0.3-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, DependsOn: []string{ "busybox@1.24.2-r9", "musl@1.1.14-r10", @@ -92,7 +92,7 @@ var pkgs = []types.Package{ Version: "1.1-r0", SrcName: "alpine-keys", SrcVersion: "1.1-r0", - Licenses: []string{"GPL-3.0"}, + Licenses: []string{"GPL-2.0-or-later"}, Arch: "x86_64", Digest: "sha1:4def7ffaee6aeba700c1d62570326f75cbb8fa25", InstalledFiles: []string{ @@ -124,7 +124,7 @@ var pkgs = []types.Package{ Version: "1.0.2h-r1", SrcName: "openssl", SrcVersion: "1.0.2h-r1", - Licenses: []string{"openssl"}, + Licenses: []string{"OpenSSL"}, DependsOn: []string{ "musl@1.1.14-r10", "zlib@1.2.8-r2", @@ -155,7 +155,7 @@ var pkgs = []types.Package{ Version: "1.0.2h-r1", SrcName: "openssl", SrcVersion: "1.0.2h-r1", - Licenses: []string{"openssl"}, + Licenses: []string{"OpenSSL"}, Digest: "sha1:7120f337e93b2b4c44e0f5f31a15b60dc678ca14", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", @@ -173,7 +173,7 @@ var pkgs = []types.Package{ Version: "2.6.7-r0", SrcName: "apk-tools", SrcVersion: "2.6.7-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:0990c0acd62b4175818c3a4cc60ed11f14e23bd8", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", @@ -192,7 +192,7 @@ var pkgs = []types.Package{ Version: "1.1.6-r0", SrcName: "pax-utils", SrcVersion: "1.1.6-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:f9bab817c5ad93e92a6218bc0f7596b657c02d90", DependsOn: []string{"musl@1.1.14-r10"}, Arch: "x86_64", @@ -209,7 +209,7 @@ var pkgs = []types.Package{ Licenses: []string{ "MIT", "BSD-3-Clause", - "GPL-2.0", + "GPL-2.0-or-later", }, Digest: "sha1:608aa1dd39eff7bc6615d3e5e33383750f8f5ecc", DependsOn: []string{ @@ -231,7 +231,7 @@ var pkgs = []types.Package{ Version: "0.7-r0", SrcName: "libc-dev", SrcVersion: "0.7-r0", - Licenses: []string{"GPL-3.0"}, + Licenses: []string{"GPL-2.0-or-later"}, Digest: "sha1:9055bc7afd76cf2672198042f72fc4a5ed4fa961", DependsOn: []string{"musl-utils@1.1.14-r10"}, Arch: "x86_64", @@ -255,7 +255,6 @@ var pkgs = []types.Package{ "usr/share/aclocal/pkg.m4", }, }, - { ID: "sqlite-libs@3.26.0-r3", Name: "sqlite-libs", @@ -271,7 +270,6 @@ var pkgs = []types.Package{ "usr/lib/libsqlite3.so.0.8.6", }, }, - { ID: "test@2.9.11_pre20061021-r2", Name: "test", @@ -292,7 +290,6 @@ var pkgs = []types.Package{ "usr/include/sqlite3.h", }, }, - { ID: "ada-libs@2.7.4-r0", Name: "ada-libs", diff --git a/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go b/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go index d44899e4362e..2c6c1e2c50ee 100644 --- a/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go +++ b/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go @@ -29,8 +29,8 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/zlib1g/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-1.0"}, - {Name: "Artistic"}, + {Name: "GPL-1.0-or-later"}, + {Name: "Artistic-2.0"}, {Name: "BSD-4-clause-POWERDOG"}, {Name: "Zlib"}, }, @@ -49,7 +49,7 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/adduser/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-only"}, }, PkgName: "adduser", }, @@ -66,7 +66,8 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/apt/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-or-later"}, + {Name: "GPL-2.0-only"}, }, PkgName: "apt", }, diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index a69ab03708e2..f7e80e3cf578 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -40,7 +40,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "3.2.0-r3", SrcName: "alpine-baselayout", SrcVersion: "3.2.0-r3", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:8f373f5b329c3aaf136eb30c63a387661ee0f3d0", DependsOn: []string{ "busybox@1.31.1-r9", @@ -113,7 +113,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "2.10.4-r3", SrcName: "apk-tools", SrcVersion: "2.10.4-r3", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:b15ad0c90e4493dfdc948d6b90a8e020da8936ef", DependsOn: []string{ "libcrypto1.1@1.1.1d-r3", @@ -132,7 +132,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.31.1-r9", SrcName: "busybox", SrcVersion: "1.31.1-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:a457703d71654811ea28d8d27a5cfc49ece27b34", DependsOn: []string{ "musl@1.1.24-r2", @@ -156,7 +156,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcVersion: "20191127-r1", Licenses: []string{ "MPL-2.0", - "GPL-2.0", + "GPL-2.0-or-later", }, Arch: "x86_64", Digest: "sha1:3aeb8a90d7179d2a187782e980a964494e08c5fb", @@ -265,7 +265,7 @@ func TestArtifact_Inspect(t *testing.T) { Licenses: []string{ "MIT", "BSD-3-Clause", - "GPL-2.0", + "GPL-2.0-or-later", }, Digest: "sha1:6d3b45e79dbab444ca7cbfa59e2833203be6fb6a", DependsOn: []string{ @@ -287,7 +287,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.2.4-r0", SrcName: "pax-utils", SrcVersion: "1.2.4-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:d6147beb32bff803b5d9f83a3bec7ab319087185", DependsOn: []string{ "musl@1.1.24-r2", @@ -303,7 +303,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.31.1-r9", SrcName: "busybox", SrcVersion: "1.31.1-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:3b685152af320120ae8941c740d3376b54e43c10", DependsOn: []string{ "libtls-standalone@2.9.1-r0", @@ -567,7 +567,7 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/base-files/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-3.0"}, + {Name: "GPL-2.0-or-later"}, }, PkgName: "base-files", }, @@ -575,7 +575,8 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/ca-certificates/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-or-later"}, + {Name: "GPL-2.0-only"}, {Name: "MPL-2.0"}, }, PkgName: "ca-certificates", @@ -584,7 +585,7 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/netbase/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-only"}, }, PkgName: "netbase", }, @@ -655,8 +656,8 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/libc6/copyright", Findings: []types.LicenseFinding{ - {Name: "LGPL-2.1"}, - {Name: "GPL-2.0"}, + {Name: "LGPL-2.1-only"}, + {Name: "GPL-2.0-only"}, }, PkgName: "libc6", }, diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden index 32513f398b9f..17d3941a620e 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden @@ -4,14 +4,14 @@ "Name": "alpine-baselayout", "Identifier": { "PURL": "pkg:apk/alpine/alpine-baselayout@3.1.2-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "3ca42aecf84bfa9" + "UID": "2d19d30821e01d2c" }, "Version": "3.1.2-r0", "Arch": "x86_64", "SrcName": "alpine-baselayout", "SrcVersion": "3.1.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "busybox@1.30.1-r2", @@ -95,14 +95,14 @@ "Name": "apk-tools", "Identifier": { "PURL": "pkg:apk/alpine/apk-tools@2.10.4-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "fa7ca40ce236844e" + "UID": "e967fd57e4033819" }, "Version": "2.10.4-r2", "Arch": "x86_64", "SrcName": "apk-tools", "SrcVersion": "2.10.4-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libcrypto1.1@1.1.1c-r0", @@ -124,14 +124,14 @@ "Name": "busybox", "Identifier": { "PURL": "pkg:apk/alpine/busybox@1.30.1-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "1941d9acbebe7f44" + "UID": "f3002aff2b6b251d" }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.30.1-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.22-r3" @@ -155,7 +155,7 @@ "Name": "ca-certificates-cacert", "Identifier": { "PURL": "pkg:apk/alpine/ca-certificates-cacert@20190108-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "9b1db91ad655d76c" + "UID": "1d3125ae903daa3c" }, "Version": "20190108-r0", "Arch": "x86_64", @@ -163,7 +163,7 @@ "SrcVersion": "20190108-r0", "Licenses": [ "MPL-2.0", - "GPL-2.0" + "GPL-2.0-or-later" ], "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", @@ -321,7 +321,7 @@ "Name": "musl-utils", "Identifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.22-r3?arch=x86_64\u0026distro=3.10.2", - "UID": "40edadcb74964baa" + "UID": "112ed00987ba9c7d" }, "Version": "1.1.22-r3", "Arch": "x86_64", @@ -330,7 +330,7 @@ "Licenses": [ "MIT", "BSD-3-Clause", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.22-r3", @@ -354,14 +354,14 @@ "Name": "scanelf", "Identifier": { "PURL": "pkg:apk/alpine/scanelf@1.2.3-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "6e5cf642f47e44d0" + "UID": "3ae1856359a8e719" }, "Version": "1.2.3-r0", "Arch": "x86_64", "SrcName": "pax-utils", "SrcVersion": "1.2.3-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.22-r3" @@ -380,14 +380,14 @@ "Name": "ssl_client", "Identifier": { "PURL": "pkg:apk/alpine/ssl_client@1.30.1-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "3338164dd993d2c8" + "UID": "92ce33a8acb582f6" }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.30.1-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libtls-standalone@2.9.1-r0", diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden index 4bfbb16a3dff..b4a8d982d9f7 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden @@ -71,14 +71,14 @@ "Name": "alpine-baselayout", "Identifier": { "PURL": "pkg:apk/alpine/alpine-baselayout@3.0.5-r2?arch=x86_64\u0026distro=3.7.1", - "UID": "fb3e0109c30ad75d" + "UID": "1fd865bbd91dfad4" }, "Version": "3.0.5-r2", "Arch": "x86_64", "SrcName": "alpine-baselayout", "SrcVersion": "3.0.5-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -163,14 +163,14 @@ "Name": "apk-tools", "Identifier": { "PURL": "pkg:apk/alpine/apk-tools@2.10.1-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "44e4204bb4dc2b2a" + "UID": "78262f2dc70b3ede" }, "Version": "2.10.1-r0", "Arch": "x86_64", "SrcName": "apk-tools", "SrcVersion": "2.10.1-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", @@ -192,14 +192,14 @@ "Name": "apr", "Identifier": { "PURL": "pkg:apk/alpine/apr@1.6.3-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "715dd499dcec48f9" + "UID": "64f7de29e73c4636" }, "Version": "1.6.3-r0", "Arch": "x86_64", "SrcName": "apr", "SrcVersion": "1.6.3-r0", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "libuuid@2.31-r0", @@ -221,14 +221,14 @@ "Name": "apr-util", "Identifier": { "PURL": "pkg:apk/alpine/apr-util@1.6.1-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "2aa1dd25c68a60eb" + "UID": "2d3f23b8b61a097c" }, "Version": "1.6.1-r1", "Arch": "x86_64", "SrcName": "apr-util", "SrcVersion": "1.6.1-r1", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "apr@1.6.3-r0", @@ -253,14 +253,14 @@ "Name": "bash", "Identifier": { "PURL": "pkg:apk/alpine/bash@4.4.19-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "32e82b55d6afc293" + "UID": "c7841dcc19f73c7e" }, "Version": "4.4.19-r1", "Arch": "x86_64", "SrcName": "bash", "SrcVersion": "4.4.19-r1", "Licenses": [ - "GPL-3.0" + "GPL-3.0-or-later" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -368,14 +368,14 @@ "Name": "busybox", "Identifier": { "PURL": "pkg:apk/alpine/busybox@1.27.2-r11?arch=x86_64\u0026distro=3.7.1", - "UID": "e32c8aeae1daa385" + "UID": "d936440f5fd65b0a" }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.27.2-r11", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.18-r3" @@ -399,7 +399,7 @@ "Name": "ca-certificates", "Identifier": { "PURL": "pkg:apk/alpine/ca-certificates@20171114-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "fc49474e56f2cdca" + "UID": "88fab2304b2bb95" }, "Version": "20171114-r0", "Arch": "x86_64", @@ -407,7 +407,7 @@ "SrcVersion": "20171114-r0", "Licenses": [ "MPL-2.0", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -666,14 +666,14 @@ "Name": "gdbm", "Identifier": { "PURL": "pkg:apk/alpine/gdbm@1.13-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "eb4b3efac8d4d73f" + "UID": "1bbe6ee4fe37c0c5" }, "Version": "1.13-r1", "Arch": "x86_64", "SrcName": "gdbm", "SrcVersion": "1.13-r1", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" @@ -698,14 +698,14 @@ "Name": "git", "Identifier": { "PURL": "pkg:apk/alpine/git@2.15.2-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "845b6214d48ea80e" + "UID": "8f0a9684f6888b5b" }, "Version": "2.15.2-r0", "Arch": "x86_64", "SrcName": "git", "SrcVersion": "2.15.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "expat@2.2.5-r0", @@ -1271,16 +1271,16 @@ "Name": "libuuid", "Identifier": { "PURL": "pkg:apk/alpine/libuuid@2.31-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "ec8a9d1580eb93d7" + "UID": "39de02f4a8b5e0c" }, "Version": "2.31-r0", "Arch": "x86_64", "SrcName": "util-linux", "SrcVersion": "2.31-r0", "Licenses": [ - "GPL-2.0", - "GPL-2.0", - "LGPL-2.0", + "GPL-2.0-only", + "GPL-2.0-or-later", + "LGPL-2.0-or-later", "BSD-3-Clause", "Public", "Domain" @@ -1331,14 +1331,14 @@ "Name": "mercurial", "Identifier": { "PURL": "pkg:apk/alpine/mercurial@4.5.2-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "28d12c554475942a" + "UID": "6148e64298851c1b" }, "Version": "4.5.2-r0", "Arch": "x86_64", "SrcName": "mercurial", "SrcVersion": "4.5.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -2100,7 +2100,7 @@ "Name": "musl-utils", "Identifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.18-r3?arch=x86_64\u0026distro=3.7.1", - "UID": "c2765ad0d8dd83f9" + "UID": "dc61f5453717063a" }, "Version": "1.1.18-r3", "Arch": "x86_64", @@ -2109,7 +2109,7 @@ "Licenses": [ "MIT", "BSD-3-Clause", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -5136,14 +5136,14 @@ "Name": "patch", "Identifier": { "PURL": "pkg:apk/alpine/patch@2.7.5-r2?arch=x86_64\u0026distro=3.7.1", - "UID": "c3945b28493e2842" + "UID": "be58b1df7c42f71e" }, "Version": "2.7.5-r2", "Arch": "x86_64", "SrcName": "patch", "SrcVersion": "2.7.5-r2", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" @@ -7667,14 +7667,14 @@ "Name": "readline", "Identifier": { "PURL": "pkg:apk/alpine/readline@7.0.003-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "2cb2c7047f5911f5" + "UID": "f3dc1d91dea8744d" }, "Version": "7.0.003-r0", "Arch": "x86_64", "SrcName": "readline", "SrcVersion": "7.0.003-r0", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -7695,14 +7695,14 @@ "Name": "scanelf", "Identifier": { "PURL": "pkg:apk/alpine/scanelf@1.2.2-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "88086fdb5a997cfd" + "UID": "8520c35436819" }, "Version": "1.2.2-r1", "Arch": "x86_64", "SrcName": "pax-utils", "SrcVersion": "1.2.2-r1", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.18-r3" @@ -7721,14 +7721,14 @@ "Name": "serf", "Identifier": { "PURL": "pkg:apk/alpine/serf@1.3.9-r3?arch=x86_64\u0026distro=3.7.1", - "UID": "34d5052ef0071707" + "UID": "e052e8031c85839d" }, "Version": "1.3.9-r3", "Arch": "x86_64", "SrcName": "serf", "SrcVersion": "1.3.9-r3", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "apr-util@1.6.1-r1", @@ -7780,14 +7780,14 @@ "Name": "ssl_client", "Identifier": { "PURL": "pkg:apk/alpine/ssl_client@1.27.2-r11?arch=x86_64\u0026distro=3.7.1", - "UID": "eab2a79208d922b" + "UID": "740ce998f526d2c2" }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.27.2-r11", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libressl2.6-libtls@2.6.5-r0", @@ -7930,14 +7930,14 @@ "Name": "tar", "Identifier": { "PURL": "pkg:apk/alpine/tar@1.29-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "636f4bd512a19da9" + "UID": "35fcd0737165df45" }, "Version": "1.29-r1", "Arch": "x86_64", "SrcName": "tar", "SrcVersion": "1.29-r1", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" diff --git a/pkg/flag/license_flags.go b/pkg/flag/license_flags.go index 5f4e148af5b2..5ff4c912e2a9 100644 --- a/pkg/flag/license_flags.go +++ b/pkg/flag/license_flags.go @@ -2,7 +2,7 @@ package flag import ( "github.com/aquasecurity/trivy/pkg/fanal/types" - "github.com/aquasecurity/trivy/pkg/licensing" + "github.com/aquasecurity/trivy/pkg/licensing/expression" ) var ( @@ -26,37 +26,37 @@ var ( // LicenseForbidden is an option only in a config file LicenseForbidden = Flag[[]string]{ ConfigName: "license.forbidden", - Default: licensing.ForbiddenLicenses, + Default: expression.ForbiddenLicenses, Usage: "forbidden licenses", } // LicenseRestricted is an option only in a config file LicenseRestricted = Flag[[]string]{ ConfigName: "license.restricted", - Default: licensing.RestrictedLicenses, + Default: expression.RestrictedLicenses, Usage: "restricted licenses", } // LicenseReciprocal is an option only in a config file LicenseReciprocal = Flag[[]string]{ ConfigName: "license.reciprocal", - Default: licensing.ReciprocalLicenses, + Default: expression.ReciprocalLicenses, Usage: "reciprocal licenses", } // LicenseNotice is an option only in a config file LicenseNotice = Flag[[]string]{ ConfigName: "license.notice", - Default: licensing.NoticeLicenses, + Default: expression.NoticeLicenses, Usage: "notice licenses", } // LicensePermissive is an option only in a config file LicensePermissive = Flag[[]string]{ ConfigName: "license.permissive", - Default: licensing.PermissiveLicenses, + Default: expression.PermissiveLicenses, Usage: "permissive licenses", } // LicenseUnencumbered is an option only in a config file LicenseUnencumbered = Flag[[]string]{ ConfigName: "license.unencumbered", - Default: licensing.UnencumberedLicenses, + Default: expression.UnencumberedLicenses, Usage: "unencumbered licenses", } ) diff --git a/pkg/licensing/category.go b/pkg/licensing/expression/category.go similarity index 96% rename from pkg/licensing/category.go rename to pkg/licensing/expression/category.go index f99ccdc52af4..c32f228c07d8 100644 --- a/pkg/licensing/category.go +++ b/pkg/licensing/expression/category.go @@ -1,4 +1,4 @@ -package licensing +package expression // Canonical names of the licenses. // ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L24-L177 @@ -165,6 +165,28 @@ const ( ZPL21 = "ZPL-2.1" ) +// GNU licenses always use either the suffix “-only“ or the suffix “-or-later“ +// https://spdx.dev/learn/handling-license-info/ +var GnuLicenses = []string{ + AGPL10, + AGPL30, + GFDL11WithInvariants, + GFDL11NoInvariants, + GFDL11, + GFDL12WithInvariants, + GFDL12NoInvariants, + GFDL12, + GFDL13WithInvariants, + GFDL13NoInvariants, + GFDL13, + GPL10, + GPL20, + GPL30, + LGPL20, + LGPL21, + LGPL30, +} + var ( // ForbiddenLicenses - Licenses that are forbidden to be used. // ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L340-L364 diff --git a/pkg/licensing/expression/expression.go b/pkg/licensing/expression/expression.go index 59848e57eef7..6f3c0054f929 100644 --- a/pkg/licensing/expression/expression.go +++ b/pkg/licensing/expression/expression.go @@ -11,7 +11,7 @@ var ( ErrInvalidExpression = xerrors.New("invalid expression error") ) -type NormalizeFunc func(license string) string +type NormalizeFunc func(license string) SimpleExpr func parse(license string) (Expression, error) { l := NewLexer(strings.NewReader(license)) @@ -38,7 +38,9 @@ func normalize(expr Expression, fn ...NormalizeFunc) Expression { switch e := expr.(type) { case SimpleExpr: for _, f := range fn { - e.license = f(e.license) + normalized := f(e.License) + e.License = normalized.License + e.HasPlus = e.HasPlus || normalized.HasPlus } return e case CompoundExpr: @@ -52,10 +54,10 @@ func normalize(expr Expression, fn ...NormalizeFunc) Expression { } // NormalizeForSPDX replaces ' ' to '-' in license-id. -// SPDX license MUST NOT be white space between a license-id. +// SPDX license MUST NOT have white space between a license-id. // There MUST be white space on either side of the operator "WITH". // ref: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions -func NormalizeForSPDX(s string) string { +func NormalizeForSPDX(s string) SimpleExpr { var b strings.Builder for _, c := range s { switch { @@ -70,7 +72,7 @@ func NormalizeForSPDX(s string) string { _, _ = b.WriteRune('-') } } - return b.String() + return SimpleExpr{License: b.String(), HasPlus: false} } func isAlphabet(r rune) bool { diff --git a/pkg/licensing/expression/expression_test.go b/pkg/licensing/expression/expression_test.go index 0e3eaa7ae7cc..12b715e7ad30 100644 --- a/pkg/licensing/expression/expression_test.go +++ b/pkg/licensing/expression/expression_test.go @@ -37,7 +37,7 @@ func TestNormalize(t *testing.T) { { name: "upper", license: "LGPL-2.1-only OR MIT", - fn: strings.ToUpper, + fn: func(license string) SimpleExpr { return SimpleExpr{strings.ToUpper(license), false} }, want: "LGPL-2.1-ONLY OR MIT", }, } diff --git a/pkg/licensing/expression/parser.go.y b/pkg/licensing/expression/parser.go.y index 82bd11028619..85a90a5a73ce 100644 --- a/pkg/licensing/expression/parser.go.y +++ b/pkg/licensing/expression/parser.go.y @@ -32,17 +32,17 @@ license simple : IDENT { - $$ = SimpleExpr{license: $1.literal} + $$ = SimpleExpr{License: $1.literal} } | simple IDENT /* e.g. Public Domain */ { - $$ = SimpleExpr{license: $1.String() + " " + $2.literal} + $$ = SimpleExpr{License: $1.String() + " " + $2.literal} } plus : simple '+' { - $$ = SimpleExpr{license: $1.String(), hasPlus: true} + $$ = SimpleExpr{License: $1.String(), HasPlus: true} } compound diff --git a/pkg/licensing/expression/parser_gen.go b/pkg/licensing/expression/parser_gen.go index 32f65276374e..57c51b320e5d 100644 --- a/pkg/licensing/expression/parser_gen.go +++ b/pkg/licensing/expression/parser_gen.go @@ -452,19 +452,19 @@ yydefault: yyDollar = yyS[yypt-1 : yypt+1] //line parser.go.y:34 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].token.literal} + yyVAL.expr = SimpleExpr{License: yyDollar[1].token.literal} } case 3: yyDollar = yyS[yypt-2 : yypt+1] //line parser.go.y:38 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].expr.String() + " " + yyDollar[2].token.literal} + yyVAL.expr = SimpleExpr{License: yyDollar[1].expr.String() + " " + yyDollar[2].token.literal} } case 4: yyDollar = yyS[yypt-2 : yypt+1] //line parser.go.y:44 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].expr.String(), hasPlus: true} + yyVAL.expr = SimpleExpr{License: yyDollar[1].expr.String(), HasPlus: true} } case 5: yyDollar = yyS[yypt-1 : yypt+1] diff --git a/pkg/licensing/expression/parser_test.go b/pkg/licensing/expression/parser_test.go index 522777085b5b..acbc09a53545 100644 --- a/pkg/licensing/expression/parser_test.go +++ b/pkg/licensing/expression/parser_test.go @@ -20,7 +20,7 @@ func TestParse(t *testing.T) { name: "single license", input: "Public Domain", want: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, wantStr: "Public Domain", }, @@ -28,7 +28,7 @@ func TestParse(t *testing.T) { name: "tag:value license", input: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", want: SimpleExpr{ - license: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", + License: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", }, wantStr: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", }, @@ -36,8 +36,8 @@ func TestParse(t *testing.T) { name: "symbols", input: "Public ._-+", want: SimpleExpr{ - license: "Public ._-", - hasPlus: true, + License: "Public ._-", + HasPlus: true, }, wantStr: "Public ._-+", }, @@ -47,7 +47,7 @@ func TestParse(t *testing.T) { want: CompoundExpr{ left: CompoundExpr{ left: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, conjunction: Token{ token: AND, @@ -55,15 +55,15 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "GPLv2", - hasPlus: true, + License: "GPLv2", + HasPlus: true, }, conjunction: Token{ token: OR, literal: "or", }, right: SimpleExpr{ - license: "AFL", + License: "AFL", }, }, }, @@ -73,15 +73,15 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "LGPLv2", - hasPlus: true, + License: "LGPLv2", + HasPlus: true, }, conjunction: Token{ token: WITH, literal: "with", }, right: SimpleExpr{ - license: "distribution exceptions", + License: "distribution exceptions", }, }, }, @@ -92,7 +92,7 @@ func TestParse(t *testing.T) { input: "Public Domain AND ( GPLv2+ or AFL AND ( CC0 or LGPL1.0) )", want: CompoundExpr{ left: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, conjunction: Token{ token: AND, @@ -100,8 +100,8 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "GPLv2", - hasPlus: true, + License: "GPLv2", + HasPlus: true, }, conjunction: Token{ token: OR, @@ -109,7 +109,7 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "AFL", + License: "AFL", }, conjunction: Token{ token: AND, @@ -117,14 +117,14 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "CC0", + License: "CC0", }, conjunction: Token{ token: OR, literal: "or", }, right: SimpleExpr{ - license: "LGPL1.0", + License: "LGPL1.0", }, }, }, diff --git a/pkg/licensing/expression/types.go b/pkg/licensing/expression/types.go index f344c610ab4d..acf2473ed4e8 100644 --- a/pkg/licensing/expression/types.go +++ b/pkg/licensing/expression/types.go @@ -3,30 +3,8 @@ package expression import ( "fmt" "slices" - - "github.com/aquasecurity/trivy/pkg/licensing" ) -var versioned = []string{ - licensing.AGPL10, - licensing.AGPL30, - licensing.GFDL11WithInvariants, - licensing.GFDL11NoInvariants, - licensing.GFDL11, - licensing.GFDL12WithInvariants, - licensing.GFDL12NoInvariants, - licensing.GFDL12, - licensing.GFDL13WithInvariants, - licensing.GFDL13NoInvariants, - licensing.GFDL13, - licensing.GPL10, - licensing.GPL20, - licensing.GPL30, - licensing.LGPL20, - licensing.LGPL21, - licensing.LGPL30, -} - type Expression interface { String() string } @@ -37,24 +15,24 @@ type Token struct { } type SimpleExpr struct { - license string - hasPlus bool + License string + HasPlus bool } func (s SimpleExpr) String() string { - if slices.Contains(versioned, s.license) { - if s.hasPlus { + if slices.Contains(GnuLicenses, s.License) { + if s.HasPlus { // e.g. AGPL-1.0-or-later - return s.license + "-or-later" + return s.License + "-or-later" } // e.g. GPL-1.0-only - return s.license + "-only" + return s.License + "-only" } - if s.hasPlus { - return s.license + "+" + if s.HasPlus { + return s.License + "+" } - return s.license + return s.License } type CompoundExpr struct { diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index 4ca8eab00030..4ce294275214 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -3,160 +3,569 @@ package licensing import ( "regexp" "strings" -) - -var mapping = map[string]string{ - // GPL - "GPL-1": GPL10, - "GPL-1+": GPL10, - "GPL 1.0": GPL10, - "GPL 1": GPL10, - "GPL2": GPL20, - "GPL 2.0": GPL20, - "GPL 2": GPL20, - "GPL-2": GPL20, - "GPL-2.0-ONLY": GPL20, - "GPL2+": GPL20, - "GPLV2": GPL20, - "GPLV2+": GPL20, - "GPL-2+": GPL20, - "GPL-2.0+": GPL20, - "GPL-2.0-OR-LATER": GPL20, - "GPL-2+ WITH AUTOCONF EXCEPTION": GPL20withautoconfexception, - "GPL-2+-with-bison-exception": GPL20withbisonexception, - "GPL3": GPL30, - "GPL 3.0": GPL30, - "GPL 3": GPL30, - "GPLV3": GPL30, - "GPLV3+": GPL30, - "GPL-3": GPL30, - "GPL-3.0-ONLY": GPL30, - "GPL3+": GPL30, - "GPL-3+": GPL30, - "GPL-3.0-OR-LATER": GPL30, - "GPL-3+ WITH AUTOCONF EXCEPTION": GPL30withautoconfexception, - "GPL-3+-WITH-BISON-EXCEPTION": GPL20withbisonexception, - "GPL": GPL30, // 2? 3? - - // LGPL - "LGPL2": LGPL20, - "LGPL 2": LGPL20, - "LGPL 2.0": LGPL20, - "LGPL-2": LGPL20, - "LGPL2+": LGPL20, - "LGPL-2+": LGPL20, - "LGPL-2.0+": LGPL20, - "LGPL-2.1": LGPL21, - "LGPL 2.1": LGPL21, - "LGPL-2.1+": LGPL21, - "LGPLV2.1+": LGPL21, - "LGPL-3": LGPL30, - "LGPL 3": LGPL30, - "LGPL-3+": LGPL30, - "LGPL": LGPL30, // 2? 3? - "GNU LESSER": LGPL30, // 2? 3? - - // MPL - "MPL1.0": MPL10, - "MPL1": MPL10, - "MPL 1.0": MPL10, - "MPL 1": MPL10, - "MPL2.0": MPL20, - "MPL 2.0": MPL20, - "MPL2": MPL20, - "MPL 2": MPL20, - - // BSD - "BSD": BSD3Clause, // 2? 3? - "BSD-2-CLAUSE": BSD2Clause, - "BSD-3-CLAUSE": BSD3Clause, - "BSD-4-CLAUSE": BSD4Clause, - "BSD 2 CLAUSE": BSD2Clause, - "BSD 2-CLAUSE": BSD2Clause, - "BSD 2-CLAUSE LICENSE": BSD2Clause, - "THE BSD 2-CLAUSE LICENSE": BSD2Clause, - "THE 2-CLAUSE BSD LICENSE": BSD2Clause, - "TWO-CLAUSE BSD-STYLE LICENSE": BSD2Clause, - "BSD 3 CLAUSE": BSD3Clause, - "BSD 3-CLAUSE": BSD3Clause, - "BSD 3-CLAUSE LICENSE": BSD3Clause, - "THE BSD 3-CLAUSE LICENSE": BSD3Clause, - "BSD 3-CLAUSE \"NEW\" OR \"REVISED\" LICENSE (BSD-3-CLAUSE)": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE (NEW BSD LICENSE)": BSD3Clause, - "NEW BSD LICENSE": BSD3Clause, - "MODIFIED BSD LICENSE": BSD3Clause, - "REVISED BSD": BSD3Clause, - "REVISED BSD LICENSE": BSD3Clause, - "THE NEW BSD LICENSE": BSD3Clause, - "3-CLAUSE BSD LICENSE": BSD3Clause, - "BSD 3-CLAUSE NEW LICENSE": BSD3Clause, - "BSD LICENSE": BSD3Clause, - "EDL 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE - V 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE V. 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE V1.0": BSD3Clause, - "THE BSD LICENSE": BSD4Clause, - // APACHE - "APACHE LICENSE": Apache10, - "APACHE SOFTWARE LICENSES": Apache10, - "APACHE": Apache20, // 1? 2? - "APACHE 2.0": Apache20, - "APACHE 2": Apache20, - "APACHE V2": Apache20, - "APACHE 2.0 LICENSE": Apache20, - "APACHE SOFTWARE LICENSE, VERSION 2.0": Apache20, - "THE APACHE SOFTWARE LICENSE, VERSION 2.0": Apache20, - "APACHE LICENSE (V2.0)": Apache20, - "APACHE LICENSE 2.0": Apache20, - "APACHE LICENSE V2.0": Apache20, - "APACHE LICENSE VERSION 2.0": Apache20, - "APACHE LICENSE, VERSION 2.0": Apache20, - "APACHE PUBLIC LICENSE 2.0": Apache20, - "APACHE SOFTWARE LICENSE - VERSION 2.0": Apache20, - "THE APACHE LICENSE, VERSION 2.0": Apache20, - "APACHE-2.0 LICENSE": Apache20, - "APACHE 2 STYLE LICENSE": Apache20, - "ASF 2.0": Apache20, + expr "github.com/aquasecurity/trivy/pkg/licensing/expression" +) - // CC0-1.0 - "CC0 1.0 UNIVERSAL": CC010, - "PUBLIC DOMAIN, PER CREATIVE COMMONS CC0": CC010, +func licence(name string, hasPlus bool) expr.SimpleExpr { + return expr.SimpleExpr{License: name, HasPlus: hasPlus} +} - // CDDL 1.0 - "CDDL 1.0": CDDL10, - "CDDL LICENSE": CDDL10, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.0": CDDL10, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.0": CDDL10, +var mapping = map[string]expr.SimpleExpr{ + // Simple mappings (i.e. that could be parsed by SpdxExpression.parse, at least without space) + // modified from https://github.com/oss-review-toolkit/ort/blob/fc5389c2cfd9c8b009794c8a11f5c91321b7a730/utils/spdx/src/main/resources/simple-license-mapping.yml - // CDDL 1.1 - "CDDL 1.1": CDDL11, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1": CDDL11, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1": CDDL11, + // Ambiguous simple mappings (mapping reason not obvious without additional information) + "AFL": licence(expr.AFL30, false), + "AGPL": licence(expr.AGPL30, false), + "AL-2": licence(expr.Apache20, false), + "AL-2.0": licence(expr.Apache20, false), + "APACHE": licence(expr.Apache20, false), + "APACHE-STYLE": licence(expr.Apache20, false), + "ARTISTIC": licence(expr.Artistic20, false), + "ASL": licence(expr.Apache20, false), + "BSD": licence(expr.BSD3Clause, false), + "BSD*": licence(expr.BSD3Clause, false), + "BSD-LIKE": licence(expr.BSD3Clause, false), + "BSD-STYLE": licence(expr.BSD3Clause, false), + "BSD-VARIANT": licence(expr.BSD3Clause, false), + "CDDL": licence(expr.CDDL10, false), + "ECLIPSE": licence(expr.EPL10, false), + "EPL": licence(expr.EPL10, false), + "EUPL": licence(expr.EUPL10, false), + "FDL": licence(expr.GFDL13, true), + "GFDL": licence(expr.GFDL13, true), + "GPL": licence(expr.GPL20, true), + "LGPL": licence(expr.LGPL20, true), + "MPL": licence(expr.MPL20, false), + "NETSCAPE": licence(expr.NPL11, false), + "PYTHON": licence(expr.Python20, false), + "ZOPE": licence(expr.ZPL21, false), - // EPL 1.0 - "ECLIPSE PUBLIC LICENSE - VERSION 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE (EPL) 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE V1.0": EPL10, - "ECLIPSE PUBLIC LICENSE, VERSION 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE - V 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE - V1.0": EPL10, - "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0": EPL10, + // Non-ambiguous simple mappings + "0BSD": licence(expr.ZeroBSD, false), + "AFL-1.1": licence(expr.AFL11, false), + "AFL-1.2": licence(expr.AFL12, false), + "AFL-2": licence(expr.AFL20, false), + "AFL-2.0": licence(expr.AFL20, false), + "AFL-2.1": licence(expr.AFL21, false), + "AFL-3.0": licence(expr.AFL30, false), + "AGPL-1.0": licence(expr.AGPL10, false), + "AGPL-3.0": licence(expr.AGPL30, false), + "APACHE-1": licence(expr.Apache10, false), + "APACHE-1.0": licence(expr.Apache10, false), + "APACHE-1.1": licence(expr.Apache11, false), + "APACHE-2": licence(expr.Apache20, false), + "APACHE-2.0": licence(expr.Apache20, false), + "APL-2": licence(expr.Apache20, false), + "APL-2.0": licence(expr.Apache20, false), + "APSL-1.0": licence(expr.APSL10, false), + "APSL-1.1": licence(expr.APSL11, false), + "APSL-1.2": licence(expr.APSL12, false), + "APSL-2.0": licence(expr.APSL20, false), + "ARTISTIC-1.0": licence(expr.Artistic10, false), + "ARTISTIC-1.0-CL-8": licence(expr.Artistic10cl8, false), + "ARTISTIC-1.0-PERL": licence(expr.Artistic10Perl, false), + "ARTISTIC-2.0": licence(expr.Artistic20, false), + "ASF-1": licence(expr.Apache10, false), + "ASF-1.0": licence(expr.Apache10, false), + "ASF-1.1": licence(expr.Apache11, false), + "ASF-2": licence(expr.Apache20, false), + "ASF-2.0": licence(expr.Apache20, false), + "ASL-1": licence(expr.Apache10, false), + "ASL-1.0": licence(expr.Apache10, false), + "ASL-1.1": licence(expr.Apache11, false), + "ASL-2": licence(expr.Apache20, false), + "ASL-2.0": licence(expr.Apache20, false), + "BCL": licence(expr.BCL, false), + "BEERWARE": licence(expr.Beerware, false), + "BOOST": licence(expr.BSL10, false), + "BOOST-1.0": licence(expr.BSL10, false), + "BOUNCY": licence(expr.MIT, false), + "BSD-2": licence(expr.BSD2Clause, false), + "BSD-2-CLAUSE": licence(expr.BSD2Clause, false), + "BSD-2-CLAUSE-FREEBSD": licence(expr.BSD2ClauseFreeBSD, false), + "BSD-2-CLAUSE-NETBSD": licence(expr.BSD2ClauseNetBSD, false), + "BSD-3": licence(expr.BSD3Clause, false), + "BSD-3-CLAUSE": licence(expr.BSD3Clause, false), + "BSD-3-CLAUSE-ATTRIBUTION": licence(expr.BSD3ClauseAttribution, false), + "BSD-3-CLAUSE-CLEAR": licence(expr.BSD3ClauseClear, false), + "BSD-3-CLAUSE-LBNL": licence(expr.BSD3ClauseLBNL, false), + "BSD-4": licence(expr.BSD4Clause, false), + "BSD-4-CLAUSE": licence(expr.BSD4Clause, false), + "BSD-4-CLAUSE-UC": licence(expr.BSD4ClauseUC, false), + "BSD-PROTECTION": licence(expr.BSDProtection, false), + "BSL": licence(expr.BSL10, false), + "BSL-1.0": licence(expr.BSL10, false), + "CC-BY-1.0": licence(expr.CCBY10, false), + "CC-BY-2.0": licence(expr.CCBY20, false), + "CC-BY-2.5": licence(expr.CCBY25, false), + "CC-BY-3.0": licence(expr.CCBY30, false), + "CC-BY-4.0": licence(expr.CCBY40, false), + "CC-BY-NC-1.0": licence(expr.CCBYNC10, false), + "CC-BY-NC-2.0": licence(expr.CCBYNC20, false), + "CC-BY-NC-2.5": licence(expr.CCBYNC25, false), + "CC-BY-NC-3.0": licence(expr.CCBYNC30, false), + "CC-BY-NC-4.0": licence(expr.CCBYNC40, false), + "CC-BY-NC-ND-1.0": licence(expr.CCBYNCND10, false), + "CC-BY-NC-ND-2.0": licence(expr.CCBYNCND20, false), + "CC-BY-NC-ND-2.5": licence(expr.CCBYNCND25, false), + "CC-BY-NC-ND-3.0": licence(expr.CCBYNCND30, false), + "CC-BY-NC-ND-4.0": licence(expr.CCBYNCND40, false), + "CC-BY-NC-SA-1.0": licence(expr.CCBYNCSA10, false), + "CC-BY-NC-SA-2.0": licence(expr.CCBYNCSA20, false), + "CC-BY-NC-SA-2.5": licence(expr.CCBYNCSA25, false), + "CC-BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CC-BY-NC-SA-4.0": licence(expr.CCBYNCSA40, false), + "CC-BY-ND-1.0": licence(expr.CCBYND10, false), + "CC-BY-ND-2.0": licence(expr.CCBYND20, false), + "CC-BY-ND-2.5": licence(expr.CCBYND25, false), + "CC-BY-ND-3.0": licence(expr.CCBYND30, false), + "CC-BY-ND-4.0": licence(expr.CCBYND40, false), + "CC-BY-SA-1.0": licence(expr.CCBYSA10, false), + "CC-BY-SA-2.0": licence(expr.CCBYSA20, false), + "CC-BY-SA-2.5": licence(expr.CCBYSA25, false), + "CC-BY-SA-3.0": licence(expr.CCBYSA30, false), + "CC-BY-SA-4.0": licence(expr.CCBYSA40, false), + "CC0": licence(expr.CC010, false), + "CC0-1.0": licence(expr.CC010, false), + "CDDL-1": licence(expr.CDDL10, false), + "CDDL-1.0": licence(expr.CDDL10, false), + "CDDL-1.1": licence(expr.CDDL11, false), + "COMMONS-CLAUSE": licence(expr.CommonsClause, false), + "CPAL": licence(expr.CPAL10, false), + "CPAL-1.0": licence(expr.CPAL10, false), + "CPL": licence(expr.CPL10, false), + "CPL-1.0": licence(expr.CPL10, false), + "ECLIPSE-1.0": licence(expr.EPL10, false), + "ECLIPSE-2.0": licence(expr.EPL20, false), + "EDL-1.0": licence(expr.BSD3Clause, false), + "EGENIX": licence(expr.EGenix, false), + "EPL-1.0": licence(expr.EPL10, false), + "EPL-2.0": licence(expr.EPL20, false), + "EUPL-1.0": licence(expr.EUPL10, false), + "EUPL-1.1": licence(expr.EUPL11, false), + "EXPAT": licence(expr.MIT, false), + "FACEBOOK-2-CLAUSE": licence(expr.Facebook2Clause, false), + "FACEBOOK-3-CLAUSE": licence(expr.Facebook3Clause, false), + "FACEBOOK-EXAMPLES": licence(expr.FacebookExamples, false), + "FREEIMAGE": licence(expr.FreeImage, false), + "FTL": licence(expr.FTL, false), + "GFDL-1.1": licence(expr.GFDL11, false), + "GFDL-1.1-INVARIANTS": licence(expr.GFDL11WithInvariants, false), + "GFDL-1.1-NO-INVARIANTS": licence(expr.GFDL11NoInvariants, false), + "GFDL-1.2": licence(expr.GFDL12, false), + "GFDL-1.2-INVARIANTS": licence(expr.GFDL12WithInvariants, false), + "GFDL-1.2-NO-INVARIANTS": licence(expr.GFDL12NoInvariants, false), + "GFDL-1.3": licence(expr.GFDL13, false), + "GFDL-1.3-INVARIANTS": licence(expr.GFDL13WithInvariants, false), + "GFDL-1.3-NO-INVARIANTS": licence(expr.GFDL13NoInvariants, false), + "GFDL-NIV-1.3": licence(expr.GFDL13NoInvariants, false), + "GO": licence(expr.BSD3Clause, false), + "GPL-1": licence(expr.GPL10, false), + "GPL-1.0": licence(expr.GPL10, false), + "GPL-2": licence(expr.GPL20, false), + "GPL-2+-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, true), + "GPL-2.0": licence(expr.GPL20, false), + "GPL-2.0-WITH-AUTOCONF-EXCEPTION": licence(expr.GPL20withautoconfexception, false), + "GPL-2.0-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, false), + "GPL-2.0-WITH-CLASSPATH-EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL-2.0-WITH-FONT-EXCEPTION": licence(expr.GPL20withfontexception, false), + "GPL-2.0-WITH-GCC-EXCEPTION": licence(expr.GPL20withGCCexception, false), + "GPL-3": licence(expr.GPL30, false), + "GPL-3+-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, true), + "GPL-3.0": licence(expr.GPL30, false), + "GPL-3.0-WITH-AUTOCONF-EXCEPTION": licence(expr.GPL30withautoconfexception, false), + "GPL-3.0-WITH-GCC-EXCEPTION": licence(expr.GPL30withGCCexception, false), + "GPLV2+CE": licence(expr.GPL20withclasspathexception, true), + "GUST-FONT": licence(expr.GUSTFont, false), + "HSQLDB": licence(expr.BSD3Clause, false), + "IMAGEMAGICK": licence(expr.ImageMagick, false), + "IPL-1.0": licence(expr.IPL10, false), + "ISC": licence(expr.ISC, false), + "ISCL": licence(expr.ISC, false), + "JQUERY": licence(expr.MIT, false), + "LGPL-2": licence(expr.LGPL20, false), + "LGPL-2.0": licence(expr.LGPL20, false), + "LGPL-2.1": licence(expr.LGPL21, false), + "LGPL-3": licence(expr.LGPL30, false), + "LGPL-3.0": licence(expr.LGPL30, false), + "LGPLLR": licence(expr.LGPLLR, false), + "LIBPNG": licence(expr.Libpng, false), + "LIL-1.0": licence(expr.Lil10, false), + "LINUX-OPENIB": licence(expr.LinuxOpenIB, false), + "LPL-1.0": licence(expr.LPL10, false), + "LPL-1.02": licence(expr.LPL102, false), + "LPPL-1.3C": licence(expr.LPPL13c, false), + "MIT": licence(expr.MIT, false), + // MIT No Attribution (MIT-0) is not yet supported by google/licenseclassifier + "MIT-0": licence(expr.MIT, false), + "MIT-LIKE": licence(expr.MIT, false), + "MIT-STYLE": licence(expr.MIT, false), + "MPL-1": licence(expr.MPL10, false), + "MPL-1.0": licence(expr.MPL10, false), + "MPL-1.1": licence(expr.MPL11, false), + "MPL-2": licence(expr.MPL20, false), + "MPL-2.0": licence(expr.MPL20, false), + "MS-PL": licence(expr.MSPL, false), + "NCSA": licence(expr.NCSA, false), + "NPL-1.0": licence(expr.NPL10, false), + "NPL-1.1": licence(expr.NPL11, false), + "OFL-1.1": licence(expr.OFL11, false), + "OPENSSL": licence(expr.OpenSSL, false), + "OPENVISION": licence(expr.OpenVision, false), + "OSL-1": licence(expr.OSL10, false), + "OSL-1.0": licence(expr.OSL10, false), + "OSL-1.1": licence(expr.OSL11, false), + "OSL-2": licence(expr.OSL20, false), + "OSL-2.0": licence(expr.OSL20, false), + "OSL-2.1": licence(expr.OSL21, false), + "OSL-3": licence(expr.OSL30, false), + "OSL-3.0": licence(expr.OSL30, false), + "PHP-3.0": licence(expr.PHP30, false), + "PHP-3.01": licence(expr.PHP301, false), + "PIL": licence(expr.PIL, false), + "POSTGRESQL": licence(expr.PostgreSQL, false), + "PYTHON-2": licence(expr.Python20, false), + "PYTHON-2.0": licence(expr.Python20, false), + "PYTHON-2.0-COMPLETE": licence(expr.Python20complete, false), + "QPL-1": licence(expr.QPL10, false), + "QPL-1.0": licence(expr.QPL10, false), + "RUBY": licence(expr.Ruby, false), + "SGI-B-1.0": licence(expr.SGIB10, false), + "SGI-B-1.1": licence(expr.SGIB11, false), + "SGI-B-2.0": licence(expr.SGIB20, false), + "SISSL": licence(expr.SISSL, false), + "SISSL-1.2": licence(expr.SISSL12, false), + "SLEEPYCAT": licence(expr.Sleepycat, false), + "UNICODE-DFS-2015": licence(expr.UnicodeDFS2015, false), + "UNICODE-DFS-2016": licence(expr.UnicodeDFS2016, false), + "UNICODE-TOU": licence(expr.UnicodeTOU, false), + "UNLICENSE": licence(expr.Unlicense, false), + "UNLICENSED": licence(expr.Unlicense, false), + "UPL-1": licence(expr.UPL10, false), + "UPL-1.0": licence(expr.UPL10, false), + "W3C": licence(expr.W3C, false), + "W3C-19980720": licence(expr.W3C19980720, false), + "W3C-20150513": licence(expr.W3C20150513, false), + "W3CL": licence(expr.W3C, false), + "WTF": licence(expr.WTFPL, false), + "WTFPL": licence(expr.WTFPL, false), + "X11": licence(expr.X11, false), + "XNET": licence(expr.Xnet, false), + "ZEND-2": licence(expr.Zend20, false), + "ZEND-2.0": licence(expr.Zend20, false), + "ZLIB": licence(expr.Zlib, false), + "ZLIB-ACKNOWLEDGEMENT": licence(expr.ZlibAcknowledgement, false), + "ZOPE-1.1": licence(expr.ZPL11, false), + "ZOPE-2.0": licence(expr.ZPL20, false), + "ZOPE-2.1": licence(expr.ZPL21, false), + "ZPL-1.1": licence(expr.ZPL11, false), + "ZPL-2.0": licence(expr.ZPL20, false), + "ZPL-2.1": licence(expr.ZPL21, false), - // EPL 2.0 - "ECLIPSE PUBLIC LICENSE - VERSION 2.0": EPL20, - "EPL 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE - V 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE V2.0": EPL20, - "ECLIPSE PUBLIC LICENSE, VERSION 2.0": EPL20, - "THE ECLIPSE PUBLIC LICENSE VERSION 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE V. 2.0": EPL20, + // Non simple declared mappings + // modified from https://github.com/oss-review-toolkit/ort/blob/fc5389c2cfd9c8b009794c8a11f5c91321b7a730/utils/spdx/src/main/resources/declared-license-mapping.yml - "RUBY": Ruby, - "ZLIB": Zlib, + // Ambiguous declared mappings (mapping reason not obvious without additional information) + "ACADEMIC FREE LICENSE (AFL)": licence(expr.AFL21, false), + "APACHE SOFTWARE LICENSES": licence(expr.Apache20, false), + "APACHE SOFTWARE": licence(expr.Apache20, false), + "APPLE PUBLIC SOURCE": licence(expr.APSL10, false), + "BSD SOFTWARE": licence(expr.BSD2Clause, false), + "BSD STYLE": licence(expr.BSD3Clause, false), + "COMMON DEVELOPMENT AND DISTRIBUTION": licence(expr.CDDL10, false), + "CREATIVE COMMONS - BY": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION": licence(expr.CCBY30, false), + "CREATIVE COMMONS": licence(expr.CCBY30, false), + "ECLIPSE PUBLIC LICENSE (EPL)": licence(expr.EPL10, false), + "GENERAL PUBLIC LICENSE (GPL)": licence(expr.GPL20, true), + "GNU FREE DOCUMENTATION LICENSE (FDL)": licence(expr.GFDL13, true), + "GNU GENERAL PUBLIC LIBRARY": licence(expr.GPL30, true), + "GNU GENERAL PUBLIC LICENSE (GPL)": licence(expr.GPL30, true), + "GNU GPL": licence(expr.GPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC": licence(expr.LGPL21, false), + "GNU LESSER PUBLIC": licence(expr.LGPL21, false), + "GNU LESSER": licence(expr.LGPL21, false), + "GNU LGPL": licence(expr.LGPL21, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, false), + "GNU PUBLIC": licence(expr.GPL20, true), + "GPL (WITH DUAL LICENSING OPTION)": licence(expr.GPL20, false), + "GPLV2 WITH EXCEPTIONS": licence(expr.GPL20withclasspathexception, false), + "INDIVIDUAL BSD": licence(expr.BSD3Clause, false), + "LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, true), + "LGPL WITH EXCEPTIONS": licence(expr.LGPL30, false), + "LPGL, SEE LICENSE FILE.": licence(expr.LGPL30, true), + "MOZILLA PUBLIC": licence(expr.MPL20, false), + "ZOPE PUBLIC": licence(expr.ZPL21, false), - // Public Domain - "PUBLIC DOMAIN": Unlicense, + // Non-ambiguous declared mappings + "(NEW) BSD": licence(expr.BSD3Clause, false), + "2-CLAUSE BSD": licence(expr.BSD2Clause, false), + "2-CLAUSE BSDL": licence(expr.BSD2Clause, false), + "3-CLAUSE BDSL": licence(expr.BSD3Clause, false), + "3-CLAUSE BSD": licence(expr.BSD3Clause, false), + "ACADEMIC FREE LICENSE (AFL-2.1": licence(expr.AFL21, false), + "AFFERO GENERAL PUBLIC LICENSE (AGPL-3": licence(expr.AGPL30, false), + "APACHE 2 STYLE": licence(expr.Apache20, false), + "APACHE LICENSE, ASL-2.0": licence(expr.Apache20, false), + "APACHE LICENSE, VERSION 2.0 (HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "APACHE PUBLIC-1.1": licence(expr.Apache11, false), + "APACHE PUBLIC-2": licence(expr.Apache20, false), + "APACHE PUBLIC-2.0": licence(expr.Apache20, false), + "APACHE SOFTWARE LICENSE (APACHE-2": licence(expr.Apache20, false), + "APACHE SOFTWARE LICENSE (APACHE-2.0": licence(expr.Apache20, false), + "APACHE SOFTWARE-1.1": licence(expr.Apache11, false), + "APACHE SOFTWARE-2": licence(expr.Apache20, false), + "APACHE SOFTWARE-2.0": licence(expr.Apache20, false), + "APACHE VERSION 2.0, JANUARY 2004": licence(expr.Apache20, false), + "APACHE-2.0 */ ' " =END --": licence(expr.Apache20, false), + "BERKELEY SOFTWARE DISTRIBUTION (BSD)": licence(expr.BSD2Clause, false), + "BOOST SOFTWARE LICENSE 1.0 (BSL-1.0": licence(expr.BSL10, false), + "BOOST SOFTWARE": licence(expr.BSL10, false), + "BOUNCY CASTLE": licence(expr.MIT, false), + "BSD (3-CLAUSE)": licence(expr.BSD3Clause, false), + "BSD - SEE NDG/HTTPSCLIENT/LICENSE FILE FOR DETAILS": licence(expr.BSD3Clause, false), + "BSD 2 CLAUSE": licence(expr.BSD2Clause, false), + "BSD 2-CLAUSE": licence(expr.BSD2Clause, false), + "BSD 3 CLAUSE": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE NEW": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE \"NEW\" OR \"REVISED\" LICENSE (BSD-3-CLAUSE)": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE": licence(expr.BSD3Clause, false), + "BSD 4 CLAUSE": licence(expr.BSD4Clause, false), + "BSD 4-CLAUSE": licence(expr.BSD4Clause, false), + "BSD FOUR CLAUSE": licence(expr.BSD4Clause, false), + "BSD LICENSE FOR HSQL": licence(expr.BSD3Clause, false), + "BSD NEW": licence(expr.BSD3Clause, false), + "BSD THREE CLAUSE": licence(expr.BSD3Clause, false), + "BSD TWO CLAUSE": licence(expr.BSD2Clause, false), + "BSD-3 CLAUSE": licence(expr.BSD3Clause, false), + "BSD-STYLE + ATTRIBUTION": licence(expr.BSD3ClauseAttribution, false), + "CC BY-NC-SA-2.0": licence(expr.CCBYNCSA20, false), + "CC BY-NC-SA-2.5": licence(expr.CCBYNCSA25, false), + "CC BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CC BY-NC-SA-4.0": licence(expr.CCBYNCSA40, false), + "CC BY-SA-2.0": licence(expr.CCBYSA20, false), + "CC BY-SA-2.5": licence(expr.CCBYSA25, false), + "CC BY-SA-3.0": licence(expr.CCBYSA30, false), + "CC BY-SA-4.0": licence(expr.CCBYSA40, false), + "CC0 1.0 UNIVERSAL (CC0 1.0) PUBLIC DOMAIN DEDICATION": licence(expr.CC010, false), + "CC0 1.0 UNIVERSAL": licence(expr.CC010, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)-1.0": licence(expr.CDDL10, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)-1.1": licence(expr.CDDL11, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.0 (CDDL-1.0": licence(expr.CDDL10, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1": licence(expr.CDDL11, false), + "COMMON PUBLIC": licence(expr.CPL10, false), + "COMMON PUBLIC-1.0": licence(expr.CPL10, false), + "CREATIVE COMMONS - ATTRIBUTION 4.0 INTERNATIONAL": licence(expr.CCBY40, false), + "CREATIVE COMMONS 3.0 BY-SA": licence(expr.CCBYSA30, false), + "CREATIVE COMMONS ATTRIBUTION 3.0 UNPORTED (CC BY-3.0": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL (CC BY-4.0": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL PUBLIC": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION-1.0": licence(expr.CCBY10, false), + "CREATIVE COMMONS ATTRIBUTION-2.5": licence(expr.CCBY25, false), + "CREATIVE COMMONS ATTRIBUTION-3.0": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION-4.0": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL 4.0 INTERNATIONAL": licence(expr.CCBYNC40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-NODERIVATIVES 4.0 INTERNATIONAL": licence(expr.CCBYNCND40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 3.0 UNPORTED (CC BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 4.0 INTERNATIONAL PUBLIC": licence(expr.CCBYNCSA40, false), + "CREATIVE COMMONS CC0": licence(expr.CC010, false), + "CREATIVE COMMONS GNU LGPL-2.1": licence(expr.LGPL21, false), + "CREATIVE COMMONS LICENSE ATTRIBUTION-NODERIVS 3.0 UNPORTED": licence(expr.CCBYNCND30, false), + "CREATIVE COMMONS LICENSE ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 3.0 UNPORTED": licence(expr.CCBYNCSA30, false), + "CREATIVE COMMONS ZERO": licence(expr.CC010, false), + "CREATIVE COMMONS-3.0": licence(expr.CCBY30, false), + "ECLIPSE DISTRIBUTION LICENSE (EDL)-1.0": licence(expr.BSD3Clause, false), + "ECLIPSE DISTRIBUTION LICENSE (NEW BSD LICENSE)": licence(expr.BSD3Clause, false), + "ECLIPSE DISTRIBUTION-1.0": licence(expr.BSD3Clause, false), + "ECLIPSE PUBLIC LICENSE (EPL)-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC LICENSE (EPL)-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC LICENSE 2.0 (EPL-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLIC": licence(expr.EPL10, false), + "ECLIPSE PUBLIC-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLISH-1.0": licence(expr.EPL10, false), + "EPL (ECLIPSE PUBLIC LICENSE)-1.0": licence(expr.EPL10, false), + "EU PUBLIC LICENSE 1.0 (EUPL-1.0": licence(expr.EUPL10, false), + "EU PUBLIC LICENSE 1.1 (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC LICENSE (EUPL-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC LICENSE (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC LICENSE 1.0 (EUPL-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC-1.1": licence(expr.EUPL11, false), + "EXPAT (MIT/X11)": licence(expr.MIT, false), + "GENERAL PUBLIC LICENSE 2.0 (GPL)": licence(expr.GPL20, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 (AGPL-3": licence(expr.AGPL30, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 (AGPL-3.0": licence(expr.AGPL30, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 OR LATER (AGPL3+)": licence(expr.AGPL30, true), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 OR LATER (AGPLV3+)": licence(expr.AGPL30, true), + "GNU AFFERO GENERAL PUBLIC-3": licence(expr.AGPL30, false), + "GNU FREE DOCUMENTATION LICENSE (GFDL-1.3": licence(expr.GFDL13, false), + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL)-2.1": licence(expr.LGPL21, false), + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL)-3.0": licence(expr.LGPL30, false), + "GNU GENERAL PUBLIC LICENSE (GPL), VERSION 2, WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE (GPL), VERSION 2, WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE (GPL)-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE (GPL)-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE V2 (GPL-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE V2 OR LATER (GPLV2+)": licence(expr.GPL20, true), + "GNU GENERAL PUBLIC LICENSE V2.0 ONLY, WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE V3 (GPL-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE V3 OR LATER (GPLV3+)": licence(expr.GPL30, true), + "GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE VERSION 2, JUNE 1991": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 (GPL2), WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 WITH THE GNU CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2, WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC-3": licence(expr.GPL30, false), + "GNU GPL-2": licence(expr.GPL20, false), + "GNU GPL-3": licence(expr.GPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-3.0": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-3.0": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE V2 (LGPL-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE V2 OR LATER (LGPLV2+)": licence(expr.LGPL20, true), + "GNU LESSER GENERAL PUBLIC LICENSE V3 (LGPL-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE V3 OR LATER (LGPLV3+)": licence(expr.LGPL30, true), + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 2.1 (LGPL-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 2.1, FEBRUARY 1999": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 2.1, FEBRUARY 1999": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC-3.0": licence(expr.LGPL30, false), + "GNU LGP (GNU GENERAL PUBLIC LICENSE)-2": licence(expr.LGPL20, false), + "GNU LGPL (GNU LESSER GENERAL PUBLIC LICENSE)-2.1": licence(expr.LGPL21, false), + "GNU LGPL-2": licence(expr.LGPL20, false), + "GNU LGPL-2.0": licence(expr.LGPL20, false), + "GNU LGPL-2.1": licence(expr.LGPL21, false), + "GNU LGPL-3": licence(expr.LGPL30, false), + "GNU LGPL-3.0": licence(expr.LGPL30, false), + "GNU LIBRARY GENERAL PUBLIC-2.0": licence(expr.LGPL20, false), + "GNU LIBRARY GENERAL PUBLIC-2.1": licence(expr.LGPL21, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 2.0 (LGPL-2": licence(expr.LGPL20, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPL-3": licence(expr.LGPL30, false), + "GPL (≥ 3)": licence(expr.GPL30, true), + "GPL 2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL V2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL-2+ WITH AUTOCONF EXCEPTION": licence(expr.GPL20withautoconfexception, true), + "GPL-3+ WITH AUTOCONF EXCEPTION": licence(expr.GPL30withautoconfexception, true), + "GPL2 W/ CPE": licence(expr.GPL20withclasspathexception, false), + "GPLV2 LICENSE, INCLUDES THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPLV2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "HSQLDB LICENSE, A BSD OPEN SOURCE": licence(expr.BSD3Clause, false), + "HTTP://ANT-CONTRIB.SOURCEFORGE.NET/TASKS/LICENSE.TXT": licence(expr.Apache11, false), + "HTTP://ASM.OW2.ORG/LICENSE.HTML": licence(expr.BSD3Clause, false), + "HTTP://CREATIVECOMMONS.ORG/PUBLICDOMAIN/ZERO/1.0/LEGALCODE": licence(expr.CC010, false), + "HTTP://EN.WIKIPEDIA.ORG/WIKI/ZLIB_LICENSE": licence(expr.Zlib, false), + "HTTP://JSON.CODEPLEX.COM/LICENSE": licence(expr.MIT, false), + "HTTP://POLYMER.GITHUB.IO/LICENSE.TXT": licence(expr.BSD3Clause, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0.HTML": licence(expr.Apache20, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0.TXT": licence(expr.Apache20, false), + "HTTP://WWW.GNU.ORG/COPYLEFT/LESSER.HTML": licence(expr.LGPL30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/1.0": licence(expr.CCBYNCND10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/2.0": licence(expr.CCBYNCND20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/2.5": licence(expr.CCBYNCND25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/3.0": licence(expr.CCBYNCND30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/4.0": licence(expr.CCBYNCND40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/1.0": licence(expr.CCBYNCSA10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/2.0": licence(expr.CCBYNCSA20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/2.5": licence(expr.CCBYNCSA25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/3.0": licence(expr.CCBYNCSA30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/4.0": licence(expr.CCBYNCSA40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/1.0": licence(expr.CCBYND10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/2.0": licence(expr.CCBYND20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/2.5": licence(expr.CCBYND25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/3.0": licence(expr.CCBYND30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/4.0": licence(expr.CCBYND40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/1.0": licence(expr.CCBYSA10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/2.0": licence(expr.CCBYSA20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/2.5": licence(expr.CCBYSA25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/3.0": licence(expr.CCBYSA30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/4.0": licence(expr.CCBYSA40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/1.0": licence(expr.CCBY10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/2.0": licence(expr.CCBY20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/2.5": licence(expr.CCBY25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/3.0": licence(expr.CCBY30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/4.0": licence(expr.CCBY40, false), + "HTTPS://CREATIVECOMMONS.ORG/PUBLICDOMAIN/ZERO/1.0/": licence(expr.CC010, false), + "HTTPS://GITHUB.COM/DOTNET/CORE-SETUP/BLOB/MASTER/LICENSE.TXT": licence(expr.MIT, false), + "HTTPS://GITHUB.COM/DOTNET/COREFX/BLOB/MASTER/LICENSE.TXT": licence(expr.MIT, false), + "HTTPS://RAW.GITHUB.COM/RDFLIB/RDFLIB/MASTER/LICENSE": licence(expr.BSD3Clause, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/ASPNET/ASPNETCORE/2.0.0/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/ASPNET/HOME/2.0.0/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/NUGET/NUGET.CLIENT/DEV/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "HTTPS://WWW.ECLIPSE.ORG/LEGAL/EPL-V10.HTML": licence(expr.EPL10, false), + "HTTPS://WWW.ECLIPSE.ORG/LEGAL/EPL-V20.HTML": licence(expr.EPL20, false), + "IBM PUBLIC": licence(expr.IPL10, false), + "ISC LICENSE (ISCL)": licence(expr.ISC, false), + "JYTHON SOFTWARE": licence(expr.Python20, false), + "KIRKK.COM BSD": licence(expr.BSD3Clause, false), + "LESSER GENERAL PUBLIC LICENSE, VERSION 3 OR GREATER": licence(expr.LGPL30, true), + "LICENSE AGREEMENT FOR OPEN SOURCE COMPUTER VISION LIBRARY (3-CLAUSE BSD LICENSE)": licence(expr.BSD3Clause, false), + "MIT (HTTP://MOOTOOLS.NET/LICENSE.TXT)": licence(expr.MIT, false), + "MIT / HTTP://REM.MIT-LICENSE.ORG": licence(expr.MIT, false), + "MIT LICENSE (HTTP://OPENSOURCE.ORG/LICENSES/MIT)": licence(expr.MIT, false), + "MIT LICENSE (MIT)": licence(expr.MIT, false), + "MIT LICENSE(MIT)": licence(expr.MIT, false), + "MIT LICENSED. HTTP://WWW.OPENSOURCE.ORG/LICENSES/MIT-LICENSE.PHP": licence(expr.MIT, false), + "MIT/EXPAT": licence(expr.MIT, false), + "MOCKRUNNER LICENSE, BASED ON APACHE SOFTWARE-1.1": licence(expr.Apache11, false), + "MODIFIED BSD": licence(expr.BSD3Clause, false), + "MOZILLA PUBLIC LICENSE 1.0 (MPL)": licence(expr.MPL10, false), + "MOZILLA PUBLIC LICENSE 1.1 (MPL-1.1": licence(expr.MPL11, false), + "MOZILLA PUBLIC LICENSE 2.0 (MPL-2.0": licence(expr.MPL20, false), + "MOZILLA PUBLIC-1.0": licence(expr.MPL10, false), + "MOZILLA PUBLIC-1.1": licence(expr.MPL11, false), + "MOZILLA PUBLIC-2.0": licence(expr.MPL20, false), + "NCSA OPEN SOURCE": licence(expr.NCSA, false), + "NETSCAPE PUBLIC LICENSE (NPL)": licence(expr.NPL10, false), + "NETSCAPE PUBLIC": licence(expr.NPL10, false), + "NEW BSD": licence(expr.BSD3Clause, false), + "OPEN SOFTWARE LICENSE 3.0 (OSL-3.0": licence(expr.OSL30, false), + "OPEN SOFTWARE-3.0": licence(expr.OSL30, false), + "PERL ARTISTIC-2": licence(expr.Artistic10Perl, false), + // Note: public domain without a specific license should not be mapped + // see https://wiki.spdx.org/view/Legal_Team/Decisions/Dealing_with_Public_Domain_within_SPDX_Files + // and https://opensource.google/documentation/reference/thirdparty/licenses#unencumbered + "PUBLIC DOMAIN (CC0-1.0)": licence(expr.CC010, false), + "PUBLIC DOMAIN, PER CREATIVE COMMONS CC0": licence(expr.CC010, false), + "QT PUBLIC LICENSE (QPL)": licence(expr.QPL10, false), + "QT PUBLIC": licence(expr.QPL10, false), + "REVISED BSD": licence(expr.BSD3Clause, false), + "RUBY'S": licence(expr.Ruby, false), + "SEQUENCE LIBRARY LICENSE (BSD-LIKE)": licence(expr.BSD3Clause, false), + "SIL OPEN FONT LICENSE 1.1 (OFL-1.1": licence(expr.OFL11, false), + "SIL OPEN FONT-1.1": licence(expr.OFL11, false), + "SIMPLIFIED BSD LISCENCE": licence(expr.BSD2Clause, false), + "SIMPLIFIED BSD": licence(expr.BSD2Clause, false), + "SUN INDUSTRY STANDARDS SOURCE LICENSE (SISSL)": licence(expr.SISSL, false), + "THREE-CLAUSE BSD-STYLE": licence(expr.BSD3Clause, false), + "TWO-CLAUSE BSD-STYLE": licence(expr.BSD2Clause, false), + "UNIVERSAL PERMISSIVE LICENSE (UPL)": licence(expr.UPL10, false), + "UNIVERSAL PERMISSIVE-1.0": licence(expr.UPL10, false), + "UNLICENSE (UNLICENSE)": licence(expr.Unlicense, false), + "W3C SOFTWARE": licence(expr.W3C, false), + "ZLIB / LIBPNG": licence(expr.ZlibAcknowledgement, false), + "ZLIB/LIBPNG": licence(expr.ZlibAcknowledgement, false), + "['MIT']": licence(expr.MIT, false), } const ( @@ -181,8 +590,6 @@ var pythonLicenseExceptions = map[string]string{ // 'BSD-3-CLAUSE and GPL-2' => {"BSD-3-CLAUSE", "GPL-2"} // 'GPL-1+ or Artistic, and BSD-4-clause-POWERDOG' => {"GPL-1+", "Artistic", "BSD-4-clause-POWERDOG"} // 'BSD 3-Clause License or Apache License, Version 2.0' => {"BSD 3-Clause License", "Apache License, Version 2.0"} -// var LicenseSplitRegexp = regexp.MustCompile("(,?[_ ]+or[_ ]+)|(,?[_ ]+and[_ ])|(,[ ]*)") - var licenseSplitRegexp = regexp.MustCompile("(,?[_ ]+(?:or|and)[_ ]+)|(,[ ]*)") // Typical keywords for license texts @@ -218,12 +625,65 @@ func TrimLicenseText(text string) string { return strings.Join(s[:n], " ") + "..." } -func Normalize(name string) string { +// version number match +var versionRegexpString = "([A-UW-Z)]{2,})( LICENSE)?\\s*[,(-]?\\s*(V|V\\.|VER|VER\\.|VERSION|VERSION-|-)?\\s*([1-9](\\.\\d)*)[)]?" + +// case insensitive version match anywhere in string +var versionRegexp = regexp.MustCompile("(?i)" + versionRegexpString) + +// version suffix match +var versionSuffixRegexp = regexp.MustCompile(versionRegexpString + "$") + +// suffixes from https://spdx.dev/learn/handling-license-info/ +var onlySuffixes = [2]string{"-ONLY", " ONLY"} +var plusSuffixes = [3]string{"+", "-OR-LATER", " OR LATER"} + +func standardizeKeyAndSuffix(name string) expr.SimpleExpr { + // Standardize space, including newline + name = strings.Join(strings.Fields(name), " ") name = strings.TrimSpace(name) - if l, ok := mapping[strings.ToUpper(name)]; ok { - return l + name = strings.ToUpper(name) + // Do not perform any further normalization for URLs + if strings.HasPrefix(name, "HTTP") { + return expr.SimpleExpr{License: name, HasPlus: false} + } + name = strings.ReplaceAll(name, "LICENCE", "LICENSE") + name = strings.TrimPrefix(name, "THE ") + name = strings.TrimSuffix(name, " LICENSE") + name = strings.TrimSuffix(name, " LICENSED") + name = strings.TrimSuffix(name, "-LICENSE") + name = strings.TrimSuffix(name, "-LICENSED") + // Remove License and Licensed suffixes except for licenses already containing those suffixes such as Unlicense + if name != "UNLICENSE" { + name = strings.TrimSuffix(name, "LICENSE") + } + if name != "UNLICENSED" { + name = strings.TrimSuffix(name, "LICENSED") + } + hasPlus := false + for _, s := range plusSuffixes { + if strings.HasSuffix(name, s) { + name = strings.TrimSuffix(name, s) + hasPlus = true + } } - return name + for _, s := range onlySuffixes { + name = strings.TrimSuffix(name, s) + } + name = versionSuffixRegexp.ReplaceAllString(name, "$1-$4") + return expr.SimpleExpr{License: name, HasPlus: hasPlus} +} + +func Normalize(name string) string { + return NormalizeLicense(name).String() +} + +func NormalizeLicense(name string) expr.SimpleExpr { + normalized := standardizeKeyAndSuffix(name) + if found, ok := mapping[normalized.License]; ok { + return expr.SimpleExpr{License: found.License, HasPlus: found.HasPlus || normalized.HasPlus} + } + return expr.SimpleExpr{License: name, HasPlus: false} } func SplitLicenses(str string) []string { @@ -261,3 +721,25 @@ func SplitLicenses(str string) []string { } return licenses } + +// Split license string considering spaces as separator +// e.g. MPL 2.0 GPL2+ => {"MPL2.0", "GPL2+"} +func LaxSplitLicenses(str string) []string { + if str == "" { + return nil + } + var licenses []string + str = versionRegexp.ReplaceAllString(str, "$1-$4") + for _, s := range strings.Fields(str) { + s = strings.Trim(s, "()") + switch { + case s == "": + continue + case s == "AND" || s == "OR": + continue + default: + licenses = append(licenses, Normalize(s)) + } + } + return licenses +} diff --git a/pkg/licensing/normalize_private_test.go b/pkg/licensing/normalize_private_test.go new file mode 100644 index 000000000000..68d62f241944 --- /dev/null +++ b/pkg/licensing/normalize_private_test.go @@ -0,0 +1,18 @@ +package licensing + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// All map keys must be standardized to be matched +// (uppercase, no common suffixes, standardized version, etc.) +func TestMap(t *testing.T) { + for key := range mapping { + t.Run(key, func(t *testing.T) { + standardized := standardizeKeyAndSuffix(key) + assert.Equal(t, standardized.License, key) + }) + } +} diff --git a/pkg/licensing/normalize_test.go b/pkg/licensing/normalize_test.go index 16fa9eac6250..9b47fd923f29 100644 --- a/pkg/licensing/normalize_test.go +++ b/pkg/licensing/normalize_test.go @@ -8,6 +8,220 @@ import ( "github.com/aquasecurity/trivy/pkg/licensing" ) +func TestNormalize(t *testing.T) { + tests := []struct { + licenses []string + normalized string + normalizedKey string + }{ + { + licenses: []string{ + " the apache license ", + " the\tapache \r\nlicense \r\n ", + " apache ", + "ApacheLicence", + "ApacheLicense", + "al-2", + "al-v2", + "al2", + "alv2", + "apache - v 2.0", + "apache - v. 2.0", + "apache - ver 2.0", + "apache - version 2.0", + "apache 2", + "apache 2.0", + "apache license (2.0)", + "apache license (v. 2)", + "apache license (v. 2.0)", + "apache license (v2)", + "apache license (v2.0)", + "apache license (version 2.0)", + "apache license 2", + "apache license 2.0", + "apache license v2", + "apache license v2.0", + "apache license version 2", + "apache license version 2.0", + "apache license", + "apache license, 2.0", + "apache license, asl version 2.0", + "apache license, version 2", + "apache license, version 2.0 (http://www.apache.org/licenses/license-2.0)", + "apache license, version 2.0", + "apache license,version 2.0", + "apache license,version-2.0", + "apache license-2.0", + "apache public 2.0", + "apache public license 2.0", + "apache public license-2.0", + "apache public-2", + "apache public-2.0", + "apache software license (apache-2.0)", + "apache software license - version 2.0", + "apache software license 2.0", + "apache software license, version 2", + "apache software license, version 2.0", + "apache software-2.0", + "apache v 2.0", + "apache v. 2.0", + "apache v2", + "apache v2.0", + "apache ver 2.0", + "apache ver. 2.0", + "apache version 2.0", + "apache version 2.0, january 2004", + "apache version-2", + "apache version-2.0", + "apache", + "apache, 2", + "apache, v2.0", + "apache, version 2", + "apache, version 2.0", + "apache-2", + "apache-2.0", + "apache-licence", + "apache-license", + "apache-licensed", + "apache-licensed", + "asf 2.0", + "asl 2", + "asl, version 2", + "asl2.0", + "the apache license", + "the apache license", + }, + normalized: "Apache-2.0", + normalizedKey: "Apache-2.0", + }, + { + licenses: []string{ + "Apache+", + }, + normalized: "Apache-2.0+", + normalizedKey: "Apache-2.0", + }, + { + licenses: []string{ + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL), VERSION 1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1)", + }, + normalized: "CDDL-1.1", + normalizedKey: "CDDL-1.1", + }, + { + licenses: []string{ + "ECLIPSE PUBLIC LICENSE (EPL) 1.0", + "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0", + "ECLIPSE PUBLIC LICENSE - V 1.0", + "ECLIPSE PUBLIC LICENSE - V1.0", + "ECLIPSE PUBLIC LICENSE - VERSION 1.0", + "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0)", + "ECLIPSE PUBLIC LICENSE 1.0", + "ECLIPSE PUBLIC LICENSE V. 1.0", + "ECLIPSE PUBLIC LICENSE V1.0", + "ECLIPSE PUBLIC LICENSE VERSION 1.0", + "ECLIPSE PUBLIC LICENSE, VERSION 1.0", + "ECLIPSE PUBLIC", + }, + normalized: "EPL-1.0", + normalizedKey: "EPL-1.0", + }, + { + licenses: []string{ + "EUROPEAN UNION PUBLIC LICENSE (EUPL V.1.1)", + "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL 1.1)", + "EUROPEAN UNION PUBLIC LICENSE 1.1", + "EUROPEAN UNION PUBLIC LICENSE, VERSION 1.1", + }, + normalized: "EUPL-1.1", + normalizedKey: "EUPL-1.1", + }, + { + licenses: []string{ + "GPL-or-later", + "GPL+", + "GPL-2.0-only+", + }, + normalized: "GPL-2.0-or-later", + normalizedKey: "GPL-2.0", + }, + { + licenses: []string{ + "GPL (≥ 3)", + "GPL3+", + "GPL3-or-later", + "GPL3 or later licence", + }, + normalized: "GPL-3.0-or-later", + normalizedKey: "GPL-3.0", + }, + { + licenses: []string{ + "GNU GENERAL PUBLIC LICENSE 3", + "GNU GENERAL PUBLIC LICENSE (GPL) V. 3", + "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL V3)", + }, + normalized: "GPL-3.0-only", + normalizedKey: "GPL-3.0", + }, + + { + licenses: []string{ + "LGPL LICENSE-3", + "GNU LESSER GENERAL PUBLIC LICENSE V3", + "GNU LESSER GENERAL PUBLIC LICENSE V3.0", + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3", + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0", + "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 3.0", + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPLV3)", + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL) VERSION 3.0", + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL), VERSION 3", + }, + normalized: "LGPL-3.0-only", + normalizedKey: "LGPL-3.0", + }, + { + licenses: []string{ + "The Unlicense", + "Unlicense", + "Unlicensed", + "UNLICENSE", + "UNLICENSED", + }, + normalized: "Unlicense", + normalizedKey: "Unlicense", + }, + { + licenses: []string{ + "MIT License", + "http://json.codeplex.com/license", + }, + normalized: "MIT", + normalizedKey: "MIT", + }, + { + licenses: []string{ + " The unmapped license ", + }, + normalized: " The unmapped license ", + normalizedKey: " The unmapped license ", + }, + } + for _, tt := range tests { + t.Run(tt.normalized, func(t *testing.T) { + for _, ll := range tt.licenses { + normalized := licensing.Normalize(ll) + normalizedKey := licensing.NormalizeLicense(ll).License + assert.Equal(t, tt.normalized, normalized) + assert.Equal(t, tt.normalizedKey, normalizedKey) + } + }) + } +} + func TestSplitLicenses(t *testing.T) { tests := []struct { name string @@ -113,3 +327,28 @@ func TestSplitLicenses(t *testing.T) { }) } } + +func TestLaxSplitLicense(t *testing.T) { + var tests = []struct { + license string + wantLicenses []string + }{ + { + license: "ASL 2.0", + wantLicenses: []string{"Apache-2.0"}, + }, + { + license: "MPL 2.0 GPL2+", + wantLicenses: []string{ + "MPL-2.0", + "GPL-2.0-or-later", + }, + }, + } + for _, tt := range tests { + t.Run(tt.license, func(t *testing.T) { + parsed := licensing.LaxSplitLicenses(tt.license) + assert.Equal(t, tt.wantLicenses, parsed) + }) + } +} diff --git a/pkg/licensing/scanner.go b/pkg/licensing/scanner.go index 100358a5af6c..1a8ed8e1d9f0 100644 --- a/pkg/licensing/scanner.go +++ b/pkg/licensing/scanner.go @@ -21,8 +21,9 @@ func NewScanner(categories map[types.LicenseCategory][]string) Scanner { } func (s *Scanner) Scan(licenseName string) (types.LicenseCategory, string) { + license := NormalizeLicense(licenseName) for category, names := range s.categories { - if slices.Contains(names, licenseName) { + if slices.Contains(names, license.License) { return category, categoryToSeverity(category).String() } } diff --git a/pkg/licensing/scanner_test.go b/pkg/licensing/scanner_test.go index fce93f3c5337..992992e48f9a 100644 --- a/pkg/licensing/scanner_test.go +++ b/pkg/licensing/scanner_test.go @@ -7,6 +7,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/licensing" + "github.com/aquasecurity/trivy/pkg/licensing/expression" ) func TestScanner_Scan(t *testing.T) { @@ -21,11 +22,11 @@ func TestScanner_Scan(t *testing.T) { name: "forbidden", categories: map[types.LicenseCategory][]string{ types.CategoryForbidden: { - licensing.BSD3Clause, - licensing.Apache20, + expression.BSD3Clause, + expression.Apache20, }, }, - licenseName: licensing.Apache20, + licenseName: expression.Apache20, wantCategory: types.CategoryForbidden, wantSeverity: "CRITICAL", }, @@ -33,21 +34,21 @@ func TestScanner_Scan(t *testing.T) { name: "restricted", categories: map[types.LicenseCategory][]string{ types.CategoryForbidden: { - licensing.GPL30, + expression.GPL30, }, types.CategoryRestricted: { - licensing.BSD3Clause, - licensing.Apache20, + expression.BSD3Clause, + expression.Apache20, }, }, - licenseName: licensing.BSD3Clause, + licenseName: expression.BSD3Clause, wantCategory: types.CategoryRestricted, wantSeverity: "HIGH", }, { name: "unknown", categories: make(map[types.LicenseCategory][]string), - licenseName: licensing.BSD3Clause, + licenseName: expression.BSD3Clause, wantCategory: types.CategoryUnknown, wantSeverity: "UNKNOWN", }, diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 33952ab41441..809ce95d7e4c 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -547,7 +547,7 @@ func NormalizeLicense(licenses []string) string { return fmt.Sprintf("(%s)", license) }), " AND ") - s, err := expression.Normalize(license, licensing.Normalize, expression.NormalizeForSPDX) + s, err := expression.Normalize(license, licensing.NormalizeLicense, expression.NormalizeForSPDX) if err != nil { // Not fail on the invalid license log.Warn("Unable to marshal SPDX licenses", log.String("license", license)) diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index ef64cf4651d5..74e9bee0a45d 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -11,6 +11,7 @@ import ( "github.com/package-url/packageurl-go" "github.com/spdx/tools-golang/spdx" "github.com/spdx/tools-golang/spdx/v2/common" + "github.com/spdx/tools-golang/spdxlib" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1329,6 +1330,7 @@ func TestMarshaler_Marshal(t *testing.T) { spdxDoc, err := marshaler.MarshalReport(ctx, tc.inputReport) require.NoError(t, err) + assert.NoError(t, spdxlib.ValidateDocument(spdxDoc)) assert.Equal(t, tc.wantSBOM, spdxDoc) }) } @@ -1361,7 +1363,7 @@ func Test_GetLicense(t *testing.T) { "GPLv2+", "LGPL 2.0 or GNU LESSER", }, - want: "GPL-2.0-or-later AND (LGPL-2.0-only OR LGPL-3.0-only)", + want: "GPL-2.0-or-later AND (LGPL-2.0-only OR LGPL-2.1-only)", }, { name: "happy path with AND operator", @@ -1369,7 +1371,7 @@ func Test_GetLicense(t *testing.T) { "GPLv2+", "LGPL 2.0 and GNU LESSER", }, - want: "GPL-2.0-or-later AND LGPL-2.0-only AND LGPL-3.0-only", + want: "GPL-2.0-or-later AND LGPL-2.0-only AND LGPL-2.1-only", }, { name: "happy path with WITH operator",