mirror of
https://github.com/aquasecurity/trivy.git
synced 2026-01-31 05:43:14 +08:00
fix(license): normalize licenses for PostAnalyzers (#9941)
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
fos "github.com/aquasecurity/trivy/pkg/fanal/analyzer/os"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/licensing"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/misconf"
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
@@ -287,6 +288,7 @@ func (r *AnalysisResult) Merge(newResult *AnalysisResult) {
|
||||
}
|
||||
|
||||
if len(newResult.Applications) > 0 {
|
||||
normalizeApplicationsLicenses(newResult.Applications)
|
||||
r.Applications = append(r.Applications, newResult.Applications...)
|
||||
}
|
||||
|
||||
@@ -335,6 +337,14 @@ func belongToGroup(groupName Group, analyzerType Type, disabledAnalyzers []Type,
|
||||
return true
|
||||
}
|
||||
|
||||
func normalizeApplicationsLicenses(applications []types.Application) {
|
||||
for i, app := range applications {
|
||||
for j, pkg := range app.Packages {
|
||||
applications[i].Packages[j].Licenses = licensing.NormalizeLicenses(pkg.Licenses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const separator = ":"
|
||||
|
||||
func NewAnalyzerGroup(opts AnalyzerOptions) (AnalyzerGroup, error) {
|
||||
|
||||
@@ -276,6 +276,73 @@ func TestAnalysisResult_Merge(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "normalize licenses for PackageInfos and Applications",
|
||||
args: args{
|
||||
new: &analyzer.AnalysisResult{
|
||||
Applications: []types.Application{
|
||||
{
|
||||
Type: "gomod",
|
||||
FilePath: "go.mod",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
Name: "github.com/example/package",
|
||||
Version: "v1.0.0",
|
||||
Licenses: []string{
|
||||
"",
|
||||
"BSD",
|
||||
"GPL-2",
|
||||
"GPL-2.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "gomod",
|
||||
FilePath: "empty-license/go.mod",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
Name: "github.com/empty/license",
|
||||
Version: "v1.0.0",
|
||||
Licenses: []string{
|
||||
"",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: analyzer.AnalysisResult{
|
||||
Applications: []types.Application{
|
||||
{
|
||||
Type: "gomod",
|
||||
FilePath: "go.mod",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
Name: "github.com/example/package",
|
||||
Version: "v1.0.0",
|
||||
Licenses: []string{
|
||||
"BSD-3-Clause",
|
||||
"GPL-2.0-only",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "gomod",
|
||||
FilePath: "empty-license/go.mod",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
Name: "github.com/empty/license",
|
||||
Version: "v1.0.0",
|
||||
Licenses: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/digest"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/licensing"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
)
|
||||
@@ -104,10 +103,6 @@ func toApplication(fileType types.LangType, filePath, libFilePath string, r xio.
|
||||
pkgs[i].DependsOn = deps[pkg.ID]
|
||||
pkgs[i].Digest = d
|
||||
pkgs[i].Indirect = isIndirect(pkg.Relationship) // For backward compatibility
|
||||
|
||||
for j, license := range pkg.Licenses {
|
||||
pkgs[i].Licenses[j] = licensing.Normalize(license)
|
||||
}
|
||||
}
|
||||
|
||||
return &types.Application{
|
||||
|
||||
@@ -33,7 +33,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
||||
ID: "com.example:example:1.0.0",
|
||||
Name: "com.example:example",
|
||||
Version: "1.0.0",
|
||||
Licenses: []string{"Apache-2.0"},
|
||||
Licenses: []string{"Apache 2.0"},
|
||||
Relationship: types.RelationshipRoot,
|
||||
DependsOn: []string{
|
||||
"com.example:example-api:2.0.0",
|
||||
@@ -71,7 +71,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
||||
Name: "com.example:example",
|
||||
Version: "1.0.0",
|
||||
Relationship: types.RelationshipRoot,
|
||||
Licenses: []string{"Apache-2.0"},
|
||||
Licenses: []string{"Apache 2.0"},
|
||||
DependsOn: []string{
|
||||
"com.example:example-api:2.0.0",
|
||||
},
|
||||
@@ -106,7 +106,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
||||
ID: "com.example:example:1.0.0",
|
||||
Name: "com.example:example",
|
||||
Version: "1.0.0",
|
||||
Licenses: []string{"Apache-2.0"},
|
||||
Licenses: []string{"Apache 2.0"},
|
||||
Relationship: types.RelationshipRoot,
|
||||
DependsOn: []string{
|
||||
"com.example:example-api:@example.version@",
|
||||
@@ -144,7 +144,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) {
|
||||
ID: "com.example:example:2.0.0",
|
||||
Name: "com.example:example",
|
||||
Version: "2.0.0",
|
||||
Licenses: []string{"Apache-2.0"},
|
||||
Licenses: []string{"Apache 2.0"},
|
||||
Relationship: types.RelationshipRoot,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ func Test_eggAnalyzer_Analyze(t *testing.T) {
|
||||
Name: "kitchen",
|
||||
Version: "1.2.6",
|
||||
Licenses: []string{
|
||||
"LGPL-2.1-only",
|
||||
"GNU Library or Lesser General Public License (LGPL)",
|
||||
},
|
||||
FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg",
|
||||
},
|
||||
@@ -55,7 +55,7 @@ func Test_eggAnalyzer_Analyze(t *testing.T) {
|
||||
Name: "kitchen",
|
||||
Version: "1.2.6",
|
||||
Licenses: []string{
|
||||
"LGPL-2.1-only",
|
||||
"GNU Library or Lesser General Public License (LGPL)",
|
||||
},
|
||||
FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg",
|
||||
Digest: "sha1:4e13b6e379966771e896ee43cf8e240bf6083dca",
|
||||
|
||||
@@ -32,7 +32,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) {
|
||||
{
|
||||
Name: "distlib",
|
||||
Version: "0.3.1",
|
||||
Licenses: []string{"Python-2.0"},
|
||||
Licenses: []string{"Python license"},
|
||||
FilePath: "distlib-0.3.1.egg-info/PKG-INFO",
|
||||
Digest: "sha1:d9d89d8ed3b2b683767c96814c9c5d3e57ef2e1b",
|
||||
},
|
||||
@@ -53,7 +53,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) {
|
||||
{
|
||||
Name: "setuptools",
|
||||
Version: "51.3.3",
|
||||
Licenses: []string{"MIT"},
|
||||
Licenses: []string{"MIT License"},
|
||||
FilePath: "setuptools-51.3.3.egg-info/PKG-INFO",
|
||||
},
|
||||
},
|
||||
@@ -73,7 +73,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) {
|
||||
{
|
||||
Name: "setuptools",
|
||||
Version: "51.3.3",
|
||||
Licenses: []string{"MIT"},
|
||||
Licenses: []string{"MIT License"},
|
||||
FilePath: "setuptools-51.3.3.dist-info/METADATA",
|
||||
},
|
||||
},
|
||||
@@ -93,7 +93,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) {
|
||||
{
|
||||
Name: "distlib",
|
||||
Version: "0.3.1",
|
||||
Licenses: []string{"Python-2.0"},
|
||||
Licenses: []string{"Python license"},
|
||||
FilePath: "distlib-0.3.1.dist-info/METADATA",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
@@ -88,30 +88,19 @@ func (a *dpkgLicenseAnalyzer) parseCopyright(r xio.ReadSeekerAt) ([]types.Licens
|
||||
l := strings.TrimSpace(line[8:])
|
||||
|
||||
l = normalizeLicense(l)
|
||||
if l != "" {
|
||||
for _, lic := range licensing.SplitLicenses(l) {
|
||||
if lic == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
lic = licensing.Normalize(lic)
|
||||
if !slices.Contains(licenses, lic) {
|
||||
licenses = append(licenses, lic)
|
||||
}
|
||||
}
|
||||
}
|
||||
licenses = append(licenses, licensing.SplitLicenses(l)...)
|
||||
case strings.Contains(line, "/usr/share/common-licenses/"):
|
||||
// Common license pattern
|
||||
license := commonLicenseReferenceRegexp.FindStringSubmatch(line)
|
||||
if len(license) == 2 {
|
||||
l := licensing.Normalize(license[1])
|
||||
if l != "" && !slices.Contains(licenses, l) {
|
||||
licenses = append(licenses, l)
|
||||
}
|
||||
licenses = append(licenses, license[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
licenses = licensing.NormalizeLicenses(licenses)
|
||||
licenses = lo.Uniq(licenses)
|
||||
|
||||
return xslices.Map(licenses, func(license string) types.LicenseFinding {
|
||||
return types.LicenseFinding{Name: license}
|
||||
}), nil
|
||||
|
||||
@@ -2,8 +2,11 @@ package licensing
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
|
||||
expr "github.com/aquasecurity/trivy/pkg/licensing/expression"
|
||||
)
|
||||
|
||||
@@ -671,11 +674,23 @@ func standardizeKeyAndSuffix(name string) expr.SimpleExpr {
|
||||
return expr.SimpleExpr{License: name, HasPlus: hasPlus}
|
||||
}
|
||||
|
||||
func Normalize(name string) string {
|
||||
return NormalizeLicense(expr.SimpleExpr{License: name}).String()
|
||||
func NormalizeLicenses(licenses []string) []string {
|
||||
seq := it.UniqMap(slices.Values(licenses), normalizeLicense)
|
||||
seq = it.Compact(seq)
|
||||
normalized := slices.Collect(seq)
|
||||
|
||||
if len(normalized) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
func NormalizeLicense(exp expr.Expression) expr.Expression {
|
||||
func normalizeLicense(name string) string {
|
||||
return NormalizeLicenseExpression(expr.SimpleExpr{License: name}).String()
|
||||
}
|
||||
|
||||
func NormalizeLicenseExpression(exp expr.Expression) expr.Expression {
|
||||
switch e := exp.(type) {
|
||||
case expr.SimpleExpr:
|
||||
return normalizeSimpleExpr(e)
|
||||
@@ -762,7 +777,7 @@ func LaxSplitLicenses(str string) []string {
|
||||
afterWith = true
|
||||
continue
|
||||
default:
|
||||
normalizedLicense := Normalize(s)
|
||||
normalizedLicense := normalizeLicense(s)
|
||||
if afterWith && len(licenses) > 0 {
|
||||
// If we found "WITH" operator, we should not split the license
|
||||
// e.g. "GPL-2 WITH Autoconf exception" => {"GPL-2 WITH Autoconf exception"}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/licensing/expression"
|
||||
)
|
||||
|
||||
// All map keys must be standardized to be matched
|
||||
@@ -16,3 +18,234 @@ func TestMap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalize(t *testing.T) {
|
||||
tests := []struct {
|
||||
licenses []expression.Expression
|
||||
want string
|
||||
wantLicense expression.Expression
|
||||
}{
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: " the apache license "},
|
||||
expression.SimpleExpr{License: " the\tapache \r\nlicense \r\n "},
|
||||
expression.SimpleExpr{License: " apache "},
|
||||
expression.SimpleExpr{License: "ApacheLicence"},
|
||||
expression.SimpleExpr{License: "ApacheLicense"},
|
||||
expression.SimpleExpr{License: "al-2"},
|
||||
expression.SimpleExpr{License: "al-v2"},
|
||||
expression.SimpleExpr{License: "al2"},
|
||||
expression.SimpleExpr{License: "alv2"},
|
||||
expression.SimpleExpr{License: "apache - v 2.0"},
|
||||
expression.SimpleExpr{License: "apache - v. 2.0"},
|
||||
expression.SimpleExpr{License: "apache - ver 2.0"},
|
||||
expression.SimpleExpr{License: "apache - version 2.0"},
|
||||
expression.SimpleExpr{License: "apache 2"},
|
||||
expression.SimpleExpr{License: "apache 2.0"},
|
||||
expression.SimpleExpr{License: "apache license (2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (v. 2)"},
|
||||
expression.SimpleExpr{License: "apache license (v. 2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (v2)"},
|
||||
expression.SimpleExpr{License: "apache license (v2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (version 2.0)"},
|
||||
expression.SimpleExpr{License: "apache license 2"},
|
||||
expression.SimpleExpr{License: "apache license 2.0"},
|
||||
expression.SimpleExpr{License: "apache license v2"},
|
||||
expression.SimpleExpr{License: "apache license v2.0"},
|
||||
expression.SimpleExpr{License: "apache license version 2"},
|
||||
expression.SimpleExpr{License: "apache license version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license"},
|
||||
expression.SimpleExpr{License: "apache license, 2.0"},
|
||||
expression.SimpleExpr{License: "apache license, asl version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license, version 2"},
|
||||
expression.SimpleExpr{License: "apache license, version 2.0 (http://www.apache.org/licenses/license-2.0)"},
|
||||
expression.SimpleExpr{License: "apache license, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license,version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license,version-2.0"},
|
||||
expression.SimpleExpr{License: "apache license-2.0"},
|
||||
expression.SimpleExpr{License: "apache public 2.0"},
|
||||
expression.SimpleExpr{License: "apache public license 2.0"},
|
||||
expression.SimpleExpr{License: "apache public license-2.0"},
|
||||
expression.SimpleExpr{License: "apache public-2"},
|
||||
expression.SimpleExpr{License: "apache public-2.0"},
|
||||
expression.SimpleExpr{License: "apache software license (apache-2.0)"},
|
||||
expression.SimpleExpr{License: "apache software license - version 2.0"},
|
||||
expression.SimpleExpr{License: "apache software license 2.0"},
|
||||
expression.SimpleExpr{License: "apache software license, version 2"},
|
||||
expression.SimpleExpr{License: "apache software license, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache software-2.0"},
|
||||
expression.SimpleExpr{License: "apache v 2.0"},
|
||||
expression.SimpleExpr{License: "apache v. 2.0"},
|
||||
expression.SimpleExpr{License: "apache v2"},
|
||||
expression.SimpleExpr{License: "apache v2.0"},
|
||||
expression.SimpleExpr{License: "apache ver 2.0"},
|
||||
expression.SimpleExpr{License: "apache ver. 2.0"},
|
||||
expression.SimpleExpr{License: "apache version 2.0"},
|
||||
expression.SimpleExpr{License: "apache version 2.0, january 2004"},
|
||||
expression.SimpleExpr{License: "apache version-2"},
|
||||
expression.SimpleExpr{License: "apache version-2.0"},
|
||||
expression.SimpleExpr{License: "apache"},
|
||||
expression.SimpleExpr{License: "apache, 2"},
|
||||
expression.SimpleExpr{License: "apache, v2.0"},
|
||||
expression.SimpleExpr{License: "apache, version 2"},
|
||||
expression.SimpleExpr{License: "apache, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache-2"},
|
||||
expression.SimpleExpr{License: "apache-2.0"},
|
||||
expression.SimpleExpr{License: "apache-licence"},
|
||||
expression.SimpleExpr{License: "apache-license"},
|
||||
expression.SimpleExpr{License: "apache-licensed"},
|
||||
expression.SimpleExpr{License: "apache-licensed"},
|
||||
expression.SimpleExpr{License: "asf 2.0"},
|
||||
expression.SimpleExpr{License: "asl 2"},
|
||||
expression.SimpleExpr{License: "asl, version 2"},
|
||||
expression.SimpleExpr{License: "asl2.0"},
|
||||
expression.SimpleExpr{License: "the apache license"},
|
||||
expression.SimpleExpr{License: "the apache license"},
|
||||
},
|
||||
want: "Apache-2.0",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Apache+"},
|
||||
},
|
||||
want: "Apache-2.0+",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL), VERSION 1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1)"},
|
||||
},
|
||||
want: "CDDL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "CDDL-1.1"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE (EPL) 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - V 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - V1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0)"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE V. 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE V1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE, VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC"},
|
||||
},
|
||||
want: "EPL-1.0",
|
||||
wantLicense: expression.SimpleExpr{License: "EPL-1.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE (EUPL V.1.1)"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL 1.1)"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE 1.1"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE, VERSION 1.1"},
|
||||
},
|
||||
want: "EUPL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "EUPL-1.1"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPL-or-later"},
|
||||
expression.SimpleExpr{License: "GPL+"},
|
||||
expression.SimpleExpr{License: "GPL-2.0-only+"},
|
||||
},
|
||||
want: "GPL-2.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPL (≥ 3)"},
|
||||
expression.SimpleExpr{License: "GPL3+"},
|
||||
expression.SimpleExpr{License: "GPL3-or-later"},
|
||||
expression.SimpleExpr{License: "GPL3 or later licence"},
|
||||
},
|
||||
want: "GPL-3.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-3.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE 3"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE (GPL) V. 3"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL V3)"},
|
||||
},
|
||||
want: "GPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-3.0"},
|
||||
},
|
||||
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "LGPL LICENSE-3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE V3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE V3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPLV3)"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL LESSER PUBLIC LICENSE (LGPL) VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE (LGPL), VERSION 3"},
|
||||
},
|
||||
want: "LGPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "LGPL-3.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "The Unlicense"},
|
||||
expression.SimpleExpr{License: "Unlicense"},
|
||||
expression.SimpleExpr{License: "UNLICENSE"},
|
||||
},
|
||||
want: "Unlicense",
|
||||
wantLicense: expression.SimpleExpr{License: "Unlicense"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "MIT License"},
|
||||
expression.SimpleExpr{License: "http://json.codeplex.com/license"},
|
||||
},
|
||||
want: "MIT",
|
||||
wantLicense: expression.SimpleExpr{License: "MIT"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: " The unmapped license "},
|
||||
},
|
||||
want: "The unmapped license",
|
||||
wantLicense: expression.SimpleExpr{License: "The unmapped license"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Universal Permissive License, Version 1.0"},
|
||||
},
|
||||
want: "UPL-1.0",
|
||||
wantLicense: expression.SimpleExpr{License: "UPL-1.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPLv2 WITH EXCEPTIONS"},
|
||||
expression.NewCompoundExpr( // "GPLv2 WITH EXCEPTIONS"
|
||||
expression.SimpleExpr{License: "GPLv2"},
|
||||
expression.TokenWith,
|
||||
expression.SimpleExpr{License: "EXCEPTIONS"},
|
||||
),
|
||||
},
|
||||
want: "GPL-2.0-with-classpath-exception",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-2.0-with-classpath-exception"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.want, func(t *testing.T) {
|
||||
for _, ll := range tt.licenses {
|
||||
got := normalizeLicense(ll.String())
|
||||
gotLicense := NormalizeLicenseExpression(ll)
|
||||
assert.Equal(t, tt.want, got)
|
||||
assert.Equal(t, tt.wantLicense, gotLicense)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,240 +6,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/licensing"
|
||||
"github.com/aquasecurity/trivy/pkg/licensing/expression"
|
||||
)
|
||||
|
||||
func TestNormalize(t *testing.T) {
|
||||
tests := []struct {
|
||||
licenses []expression.Expression
|
||||
want string
|
||||
wantLicense expression.Expression
|
||||
}{
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: " the apache license "},
|
||||
expression.SimpleExpr{License: " the\tapache \r\nlicense \r\n "},
|
||||
expression.SimpleExpr{License: " apache "},
|
||||
expression.SimpleExpr{License: "ApacheLicence"},
|
||||
expression.SimpleExpr{License: "ApacheLicense"},
|
||||
expression.SimpleExpr{License: "al-2"},
|
||||
expression.SimpleExpr{License: "al-v2"},
|
||||
expression.SimpleExpr{License: "al2"},
|
||||
expression.SimpleExpr{License: "alv2"},
|
||||
expression.SimpleExpr{License: "apache - v 2.0"},
|
||||
expression.SimpleExpr{License: "apache - v. 2.0"},
|
||||
expression.SimpleExpr{License: "apache - ver 2.0"},
|
||||
expression.SimpleExpr{License: "apache - version 2.0"},
|
||||
expression.SimpleExpr{License: "apache 2"},
|
||||
expression.SimpleExpr{License: "apache 2.0"},
|
||||
expression.SimpleExpr{License: "apache license (2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (v. 2)"},
|
||||
expression.SimpleExpr{License: "apache license (v. 2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (v2)"},
|
||||
expression.SimpleExpr{License: "apache license (v2.0)"},
|
||||
expression.SimpleExpr{License: "apache license (version 2.0)"},
|
||||
expression.SimpleExpr{License: "apache license 2"},
|
||||
expression.SimpleExpr{License: "apache license 2.0"},
|
||||
expression.SimpleExpr{License: "apache license v2"},
|
||||
expression.SimpleExpr{License: "apache license v2.0"},
|
||||
expression.SimpleExpr{License: "apache license version 2"},
|
||||
expression.SimpleExpr{License: "apache license version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license"},
|
||||
expression.SimpleExpr{License: "apache license, 2.0"},
|
||||
expression.SimpleExpr{License: "apache license, asl version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license, version 2"},
|
||||
expression.SimpleExpr{License: "apache license, version 2.0 (http://www.apache.org/licenses/license-2.0)"},
|
||||
expression.SimpleExpr{License: "apache license, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license,version 2.0"},
|
||||
expression.SimpleExpr{License: "apache license,version-2.0"},
|
||||
expression.SimpleExpr{License: "apache license-2.0"},
|
||||
expression.SimpleExpr{License: "apache public 2.0"},
|
||||
expression.SimpleExpr{License: "apache public license 2.0"},
|
||||
expression.SimpleExpr{License: "apache public license-2.0"},
|
||||
expression.SimpleExpr{License: "apache public-2"},
|
||||
expression.SimpleExpr{License: "apache public-2.0"},
|
||||
expression.SimpleExpr{License: "apache software license (apache-2.0)"},
|
||||
expression.SimpleExpr{License: "apache software license - version 2.0"},
|
||||
expression.SimpleExpr{License: "apache software license 2.0"},
|
||||
expression.SimpleExpr{License: "apache software license, version 2"},
|
||||
expression.SimpleExpr{License: "apache software license, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache software-2.0"},
|
||||
expression.SimpleExpr{License: "apache v 2.0"},
|
||||
expression.SimpleExpr{License: "apache v. 2.0"},
|
||||
expression.SimpleExpr{License: "apache v2"},
|
||||
expression.SimpleExpr{License: "apache v2.0"},
|
||||
expression.SimpleExpr{License: "apache ver 2.0"},
|
||||
expression.SimpleExpr{License: "apache ver. 2.0"},
|
||||
expression.SimpleExpr{License: "apache version 2.0"},
|
||||
expression.SimpleExpr{License: "apache version 2.0, january 2004"},
|
||||
expression.SimpleExpr{License: "apache version-2"},
|
||||
expression.SimpleExpr{License: "apache version-2.0"},
|
||||
expression.SimpleExpr{License: "apache"},
|
||||
expression.SimpleExpr{License: "apache, 2"},
|
||||
expression.SimpleExpr{License: "apache, v2.0"},
|
||||
expression.SimpleExpr{License: "apache, version 2"},
|
||||
expression.SimpleExpr{License: "apache, version 2.0"},
|
||||
expression.SimpleExpr{License: "apache-2"},
|
||||
expression.SimpleExpr{License: "apache-2.0"},
|
||||
expression.SimpleExpr{License: "apache-licence"},
|
||||
expression.SimpleExpr{License: "apache-license"},
|
||||
expression.SimpleExpr{License: "apache-licensed"},
|
||||
expression.SimpleExpr{License: "apache-licensed"},
|
||||
expression.SimpleExpr{License: "asf 2.0"},
|
||||
expression.SimpleExpr{License: "asl 2"},
|
||||
expression.SimpleExpr{License: "asl, version 2"},
|
||||
expression.SimpleExpr{License: "asl2.0"},
|
||||
expression.SimpleExpr{License: "the apache license"},
|
||||
expression.SimpleExpr{License: "the apache license"},
|
||||
},
|
||||
want: "Apache-2.0",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Apache+"},
|
||||
},
|
||||
want: "Apache-2.0+",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL), VERSION 1.1"},
|
||||
expression.SimpleExpr{License: "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1)"},
|
||||
},
|
||||
want: "CDDL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "CDDL-1.1"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE (EPL) 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - V 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - V1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE - VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0)"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE V. 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE V1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC LICENSE, VERSION 1.0"},
|
||||
expression.SimpleExpr{License: "ECLIPSE PUBLIC"},
|
||||
},
|
||||
want: "EPL-1.0",
|
||||
wantLicense: expression.SimpleExpr{License: "EPL-1.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE (EUPL V.1.1)"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL 1.1)"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE 1.1"},
|
||||
expression.SimpleExpr{License: "EUROPEAN UNION PUBLIC LICENSE, VERSION 1.1"},
|
||||
},
|
||||
want: "EUPL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "EUPL-1.1"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPL-or-later"},
|
||||
expression.SimpleExpr{License: "GPL+"},
|
||||
expression.SimpleExpr{License: "GPL-2.0-only+"},
|
||||
},
|
||||
want: "GPL-2.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPL (≥ 3)"},
|
||||
expression.SimpleExpr{License: "GPL3+"},
|
||||
expression.SimpleExpr{License: "GPL3-or-later"},
|
||||
expression.SimpleExpr{License: "GPL3 or later licence"},
|
||||
},
|
||||
want: "GPL-3.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-3.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE 3"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE (GPL) V. 3"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL V3)"},
|
||||
},
|
||||
want: "GPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-3.0"},
|
||||
},
|
||||
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "LGPL LICENSE-3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE V3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE V3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPLV3)"},
|
||||
expression.SimpleExpr{License: "GNU GENERAL LESSER PUBLIC LICENSE (LGPL) VERSION 3.0"},
|
||||
expression.SimpleExpr{License: "GNU LESSER GENERAL PUBLIC LICENSE (LGPL), VERSION 3"},
|
||||
},
|
||||
want: "LGPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "LGPL-3.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "The Unlicense"},
|
||||
expression.SimpleExpr{License: "Unlicense"},
|
||||
expression.SimpleExpr{License: "UNLICENSE"},
|
||||
},
|
||||
want: "Unlicense",
|
||||
wantLicense: expression.SimpleExpr{License: "Unlicense"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "MIT License"},
|
||||
expression.SimpleExpr{License: "http://json.codeplex.com/license"},
|
||||
},
|
||||
want: "MIT",
|
||||
wantLicense: expression.SimpleExpr{License: "MIT"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: " The unmapped license "},
|
||||
},
|
||||
want: "The unmapped license",
|
||||
wantLicense: expression.SimpleExpr{License: "The unmapped license"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Universal Permissive License, Version 1.0"},
|
||||
},
|
||||
want: "UPL-1.0",
|
||||
wantLicense: expression.SimpleExpr{License: "UPL-1.0"},
|
||||
},
|
||||
{
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPLv2 WITH EXCEPTIONS"},
|
||||
expression.NewCompoundExpr( // "GPLv2 WITH EXCEPTIONS"
|
||||
expression.SimpleExpr{License: "GPLv2"},
|
||||
expression.TokenWith,
|
||||
expression.SimpleExpr{License: "EXCEPTIONS"},
|
||||
),
|
||||
},
|
||||
want: "GPL-2.0-with-classpath-exception",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-2.0-with-classpath-exception"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.want, func(t *testing.T) {
|
||||
for _, ll := range tt.licenses {
|
||||
got := licensing.Normalize(ll.String())
|
||||
gotLicense := licensing.NormalizeLicense(ll)
|
||||
assert.Equal(t, tt.want, got)
|
||||
assert.Equal(t, tt.wantLicense, gotLicense)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitLicenses(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -26,7 +26,7 @@ func NewScanner(categories map[types.LicenseCategory][]string) Scanner {
|
||||
}
|
||||
|
||||
func (s *Scanner) Scan(licenseName string) (types.LicenseCategory, string) {
|
||||
expr, err := expression.Normalize(licenseName, NormalizeLicense)
|
||||
expr, err := expression.Normalize(licenseName, NormalizeLicenseExpression)
|
||||
if err != nil {
|
||||
return types.CategoryUnknown, ""
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ func (c *IgnoreConfig) MatchLicense(licenseID, filePath string) *IgnoreFinding {
|
||||
return expr
|
||||
}
|
||||
|
||||
_, err := expression.Normalize(licenseID, licensing.NormalizeLicense, matchLicenses)
|
||||
_, err := expression.Normalize(licenseID, licensing.NormalizeLicenseExpression, matchLicenses)
|
||||
if err != nil {
|
||||
log.WithPrefix("ignore").Debug("Unable to normalize license expression", log.String("license", licenseID), log.Err(err))
|
||||
return nil
|
||||
|
||||
@@ -348,7 +348,7 @@ func (m *Marshaler) normalizeLicense(license string) expression.Expression {
|
||||
license = strings.ReplaceAll(license, "-with-", " WITH ")
|
||||
license = strings.ReplaceAll(license, "-WITH-", " WITH ")
|
||||
|
||||
normalizedLicenses, err := expression.Normalize(license, licensing.NormalizeLicense, expression.NormalizeForSPDX)
|
||||
normalizedLicenses, err := expression.Normalize(license, licensing.NormalizeLicenseExpression, expression.NormalizeForSPDX)
|
||||
if err != nil {
|
||||
// Not fail on the invalid license
|
||||
m.logger.Warn("Unable to marshal SPDX licenses", log.String("license", license))
|
||||
|
||||
@@ -463,7 +463,7 @@ func (m *Marshaler) normalizeLicenses(licenses []string) (string, []*spdx.OtherL
|
||||
return expression.SimpleExpr{License: l.LicenseIdentifier}
|
||||
}
|
||||
|
||||
normalizedLicense, err := expression.Normalize(license, licensing.NormalizeLicense, expression.NormalizeForSPDX, replaceOtherLicenses)
|
||||
normalizedLicense, err := expression.Normalize(license, licensing.NormalizeLicenseExpression, expression.NormalizeForSPDX, replaceOtherLicenses)
|
||||
if err != nil {
|
||||
// Not fail on the invalid license
|
||||
m.logger.Warn("Unable to marshal SPDX licenses", log.String("license", license))
|
||||
|
||||
Reference in New Issue
Block a user