feat(license): improve license normalization (#7131)

Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
Pierre Baumard
2024-09-11 08:47:50 +02:00
committed by GitHub
parent d589856fdd
commit 6472e3c9da
28 changed files with 1707 additions and 551 deletions

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

File diff suppressed because it is too large Load Diff

View File

@@ -47,8 +47,8 @@
"Link": ""
},
{
"Severity": "UNKNOWN",
"Category": "unknown",
"Severity": "LOW",
"Category": "notice",
"PkgName": "org.slf4j:slf4j-api",
"FilePath": "",
"Name": "MIT License",

View File

@@ -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",

View File

@@ -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",
},
},

View File

@@ -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) {

View File

@@ -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",

View File

@@ -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",
},

View File

@@ -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",
},

View File

@@ -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",

View File

@@ -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"

View File

@@ -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",
}
)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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",
},
}

View File

@@ -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

View File

@@ -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]

View File

@@ -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",
},
},
},

View File

@@ -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 {

View File

@@ -3,160 +3,569 @@ package licensing
import (
"regexp"
"strings"
expr "github.com/aquasecurity/trivy/pkg/licensing/expression"
)
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?
func licence(name string, hasPlus bool) expr.SimpleExpr {
return expr.SimpleExpr{License: name, HasPlus: hasPlus}
}
// 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?
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
// 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,
// 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),
// 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,
// 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),
// 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,
// Non simple declared mappings
// modified from https://github.com/oss-review-toolkit/ort/blob/fc5389c2cfd9c8b009794c8a11f5c91321b7a730/utils/spdx/src/main/resources/declared-license-mapping.yml
// CC0-1.0
"CC0 1.0 UNIVERSAL": CC010,
"PUBLIC DOMAIN, PER CREATIVE COMMONS CC0": CC010,
// 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),
// 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,
// 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,
// 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,
// 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,
"RUBY": Ruby,
"ZLIB": Zlib,
// 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 */ &#39; &QUOT; &#X3D;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}
}
return name
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
}
}
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
}

View File

@@ -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)
})
}
}

View File

@@ -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)
})
}
}

View File

@@ -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()
}
}

View File

@@ -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",
},

View File

@@ -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))

View File

@@ -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",