mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
refactor(license): improve license expression normalization (#8257)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
This commit is contained in:
@@ -11,7 +11,7 @@ var (
|
||||
ErrInvalidExpression = xerrors.New("invalid expression error")
|
||||
)
|
||||
|
||||
type NormalizeFunc func(license string) SimpleExpr
|
||||
type NormalizeFunc func(license Expression) Expression
|
||||
|
||||
func parse(license string) (Expression, error) {
|
||||
l := NewLexer(strings.NewReader(license))
|
||||
@@ -24,42 +24,48 @@ func parse(license string) (Expression, error) {
|
||||
return l.result, nil
|
||||
}
|
||||
|
||||
func Normalize(license string, fn ...NormalizeFunc) (string, error) {
|
||||
func Normalize(license string, funcs ...NormalizeFunc) (string, error) {
|
||||
expr, err := parse(license)
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("license (%s) parse error: %w", license, err)
|
||||
}
|
||||
expr = normalize(expr, fn...)
|
||||
for _, fn := range funcs {
|
||||
expr = normalize(expr, fn)
|
||||
}
|
||||
|
||||
return expr.String(), nil
|
||||
}
|
||||
|
||||
func normalize(expr Expression, fn ...NormalizeFunc) Expression {
|
||||
switch e := expr.(type) {
|
||||
func normalize(expr Expression, fn NormalizeFunc) Expression {
|
||||
// Apply normalization function first
|
||||
normalized := fn(expr)
|
||||
|
||||
switch e := normalized.(type) {
|
||||
case SimpleExpr:
|
||||
for _, f := range fn {
|
||||
normalized := f(e.License)
|
||||
e.License = normalized.License
|
||||
e.HasPlus = e.HasPlus || normalized.HasPlus
|
||||
}
|
||||
return e
|
||||
// No further normalization for SimpleExpr
|
||||
case CompoundExpr:
|
||||
e.left = normalize(e.left, fn...)
|
||||
e.right = normalize(e.right, fn...)
|
||||
// Only recursively process if the result is a CompoundExpr
|
||||
e.left = normalize(e.left, fn)
|
||||
e.right = normalize(e.right, fn)
|
||||
e.conjunction.literal = strings.ToUpper(e.conjunction.literal) // e.g. "and" => "AND"
|
||||
return e
|
||||
}
|
||||
|
||||
return expr
|
||||
return normalized
|
||||
}
|
||||
|
||||
// NormalizeForSPDX replaces ' ' to '-' in 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) SimpleExpr {
|
||||
func NormalizeForSPDX(expr Expression) Expression {
|
||||
e, ok := expr.(SimpleExpr)
|
||||
if !ok {
|
||||
return expr // do not normalize compound expressions
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
for _, c := range s {
|
||||
for _, c := range e.License {
|
||||
switch {
|
||||
// spec: idstring = 1*(ALPHA / DIGIT / "-" / "." )
|
||||
case isAlphabet(c) || unicode.IsNumber(c) || c == '-' || c == '.':
|
||||
@@ -72,7 +78,7 @@ func NormalizeForSPDX(s string) SimpleExpr {
|
||||
_, _ = b.WriteRune('-')
|
||||
}
|
||||
}
|
||||
return SimpleExpr{License: b.String(), HasPlus: false}
|
||||
return SimpleExpr{License: b.String(), HasPlus: e.HasPlus}
|
||||
}
|
||||
|
||||
func isAlphabet(r rune) bool {
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestNormalize(t *testing.T) {
|
||||
{
|
||||
name: "upper",
|
||||
license: "LGPL-2.1-only OR MIT",
|
||||
fn: func(license string) SimpleExpr { return SimpleExpr{strings.ToUpper(license), false} },
|
||||
fn: func(license Expression) Expression { return SimpleExpr{strings.ToUpper(license.String()), false} },
|
||||
want: "LGPL-2.1-ONLY OR MIT",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
var (
|
||||
TokenIdent = Token{token: IDENT, literal: "IDENT"}
|
||||
TokenAnd = Token{token: AND, literal: "AND"}
|
||||
TokenOR = Token{token: OR, literal: "OR"}
|
||||
TokenWith = Token{token: WITH, literal: "WITH"}
|
||||
)
|
||||
|
||||
type Expression interface {
|
||||
String() string
|
||||
}
|
||||
@@ -41,6 +48,14 @@ type CompoundExpr struct {
|
||||
right Expression
|
||||
}
|
||||
|
||||
func NewCompoundExpr(left Expression, conjunction Token, right Expression) CompoundExpr {
|
||||
return CompoundExpr{left: left, conjunction: conjunction, right: right}
|
||||
}
|
||||
|
||||
func (c CompoundExpr) Conjunction() Token {
|
||||
return c.conjunction
|
||||
}
|
||||
|
||||
func (c CompoundExpr) String() string {
|
||||
left := c.left.String()
|
||||
if l, ok := c.left.(CompoundExpr); ok {
|
||||
|
||||
@@ -674,17 +674,38 @@ func standardizeKeyAndSuffix(name string) expr.SimpleExpr {
|
||||
}
|
||||
|
||||
func Normalize(name string) string {
|
||||
return NormalizeLicense(name).String()
|
||||
return NormalizeLicense(expr.SimpleExpr{License: name}).String()
|
||||
}
|
||||
|
||||
func NormalizeLicense(name string) expr.SimpleExpr {
|
||||
func NormalizeLicense(exp expr.Expression) expr.Expression {
|
||||
switch e := exp.(type) {
|
||||
case expr.SimpleExpr:
|
||||
return normalizeSimpleExpr(e)
|
||||
case expr.CompoundExpr:
|
||||
return normalizeCompoundExpr(e)
|
||||
}
|
||||
return exp
|
||||
}
|
||||
|
||||
func normalizeSimpleExpr(e expr.SimpleExpr) expr.Expression {
|
||||
// Always trim leading and trailing spaces, even if we don't find this license in `mapping`.
|
||||
name = strings.TrimSpace(name)
|
||||
name := strings.TrimSpace(e.License)
|
||||
normalized := standardizeKeyAndSuffix(name)
|
||||
if found, ok := mapping[normalized.License]; ok {
|
||||
return expr.SimpleExpr{License: found.License, HasPlus: e.HasPlus || found.HasPlus || normalized.HasPlus}
|
||||
}
|
||||
return expr.SimpleExpr{License: name, HasPlus: e.HasPlus}
|
||||
}
|
||||
|
||||
func normalizeCompoundExpr(e expr.CompoundExpr) expr.Expression {
|
||||
if e.Conjunction() != expr.TokenWith {
|
||||
return e // Do not normalize compound expressions other than "WITH"
|
||||
}
|
||||
normalized := standardizeKeyAndSuffix(e.String())
|
||||
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}
|
||||
return e // Do not normalize compound expressions that are not found in `mapping`
|
||||
}
|
||||
|
||||
func SplitLicenses(str string) []string {
|
||||
|
||||
@@ -6,224 +6,237 @@ 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 []string
|
||||
normalized string
|
||||
normalizedKey string
|
||||
licenses []expression.Expression
|
||||
want string
|
||||
wantLicense expression.Expression
|
||||
}{
|
||||
{
|
||||
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",
|
||||
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"},
|
||||
},
|
||||
normalized: "Apache-2.0",
|
||||
normalizedKey: "Apache-2.0",
|
||||
want: "Apache-2.0",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"Apache+",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Apache+"},
|
||||
},
|
||||
normalized: "Apache-2.0+",
|
||||
normalizedKey: "Apache-2.0",
|
||||
want: "Apache-2.0+",
|
||||
wantLicense: expression.SimpleExpr{License: "Apache-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
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)",
|
||||
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)"},
|
||||
},
|
||||
normalized: "CDDL-1.1",
|
||||
normalizedKey: "CDDL-1.1",
|
||||
want: "CDDL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "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",
|
||||
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"},
|
||||
},
|
||||
normalized: "EPL-1.0",
|
||||
normalizedKey: "EPL-1.0",
|
||||
want: "EPL-1.0",
|
||||
wantLicense: expression.SimpleExpr{License: "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",
|
||||
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"},
|
||||
},
|
||||
normalized: "EUPL-1.1",
|
||||
normalizedKey: "EUPL-1.1",
|
||||
want: "EUPL-1.1",
|
||||
wantLicense: expression.SimpleExpr{License: "EUPL-1.1"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"GPL-or-later",
|
||||
"GPL+",
|
||||
"GPL-2.0-only+",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "GPL-or-later"},
|
||||
expression.SimpleExpr{License: "GPL+"},
|
||||
expression.SimpleExpr{License: "GPL-2.0-only+"},
|
||||
},
|
||||
normalized: "GPL-2.0-or-later",
|
||||
normalizedKey: "GPL-2.0",
|
||||
want: "GPL-2.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-2.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"GPL (≥ 3)",
|
||||
"GPL3+",
|
||||
"GPL3-or-later",
|
||||
"GPL3 or later licence",
|
||||
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"},
|
||||
},
|
||||
normalized: "GPL-3.0-or-later",
|
||||
normalizedKey: "GPL-3.0",
|
||||
want: "GPL-3.0-or-later",
|
||||
wantLicense: expression.SimpleExpr{License: "GPL-3.0", HasPlus: true},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"GNU GENERAL PUBLIC LICENSE 3",
|
||||
"GNU GENERAL PUBLIC LICENSE (GPL) V. 3",
|
||||
"GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL V3)",
|
||||
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)"},
|
||||
},
|
||||
normalized: "GPL-3.0-only",
|
||||
normalizedKey: "GPL-3.0",
|
||||
want: "GPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "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",
|
||||
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"},
|
||||
},
|
||||
normalized: "LGPL-3.0-only",
|
||||
normalizedKey: "LGPL-3.0",
|
||||
want: "LGPL-3.0-only",
|
||||
wantLicense: expression.SimpleExpr{License: "LGPL-3.0"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"The Unlicense",
|
||||
"Unlicense",
|
||||
"Unlicensed",
|
||||
"UNLICENSE",
|
||||
"UNLICENSED",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "The Unlicense"},
|
||||
expression.SimpleExpr{License: "Unlicense"},
|
||||
expression.SimpleExpr{License: "Unlicensed"},
|
||||
expression.SimpleExpr{License: "UNLICENSE"},
|
||||
expression.SimpleExpr{License: "UNLICENSED"},
|
||||
},
|
||||
normalized: "Unlicense",
|
||||
normalizedKey: "Unlicense",
|
||||
want: "Unlicense",
|
||||
wantLicense: expression.SimpleExpr{License: "Unlicense"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"MIT License",
|
||||
"http://json.codeplex.com/license",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "MIT License"},
|
||||
expression.SimpleExpr{License: "http://json.codeplex.com/license"},
|
||||
},
|
||||
normalized: "MIT",
|
||||
normalizedKey: "MIT",
|
||||
want: "MIT",
|
||||
wantLicense: expression.SimpleExpr{License: "MIT"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
" The unmapped license ",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: " The unmapped license "},
|
||||
},
|
||||
normalized: "The unmapped license",
|
||||
normalizedKey: "The unmapped license",
|
||||
want: "The unmapped license",
|
||||
wantLicense: expression.SimpleExpr{License: "The unmapped license"},
|
||||
},
|
||||
{
|
||||
licenses: []string{
|
||||
"Universal Permissive License, Version 1.0",
|
||||
licenses: []expression.Expression{
|
||||
expression.SimpleExpr{License: "Universal Permissive License, Version 1.0"},
|
||||
},
|
||||
normalized: "UPL-1.0",
|
||||
normalizedKey: "UPL-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.normalized, func(t *testing.T) {
|
||||
t.Run(tt.want, 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)
|
||||
got := licensing.Normalize(ll.String())
|
||||
gotLicense := licensing.NormalizeLicense(ll)
|
||||
assert.Equal(t, tt.want, got)
|
||||
assert.Equal(t, tt.wantLicense, gotLicense)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/licensing/expression"
|
||||
)
|
||||
|
||||
type ScannerOption struct {
|
||||
@@ -21,9 +22,17 @@ func NewScanner(categories map[types.LicenseCategory][]string) Scanner {
|
||||
}
|
||||
|
||||
func (s *Scanner) Scan(licenseName string) (types.LicenseCategory, string) {
|
||||
license := NormalizeLicense(licenseName)
|
||||
normalized := NormalizeLicense(expression.SimpleExpr{License: licenseName})
|
||||
var normalizedName string
|
||||
switch normalized := normalized.(type) {
|
||||
case expression.SimpleExpr:
|
||||
normalizedName = normalized.License
|
||||
case expression.CompoundExpr:
|
||||
normalizedName = normalized.String()
|
||||
}
|
||||
|
||||
for category, names := range s.categories {
|
||||
if slices.Contains(names, license.License) {
|
||||
if slices.Contains(names, normalizedName) {
|
||||
return category, categoryToSeverity(category).String()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,18 @@ func TestScanner_Scan(t *testing.T) {
|
||||
wantCategory: types.CategoryForbidden,
|
||||
wantSeverity: "CRITICAL",
|
||||
},
|
||||
{
|
||||
name: "has plus",
|
||||
categories: map[types.LicenseCategory][]string{
|
||||
types.CategoryForbidden: {
|
||||
expression.BSD3Clause,
|
||||
expression.Apache20,
|
||||
},
|
||||
},
|
||||
licenseName: "Apache-2.0+",
|
||||
wantCategory: types.CategoryForbidden,
|
||||
wantSeverity: "CRITICAL",
|
||||
},
|
||||
{
|
||||
name: "restricted",
|
||||
categories: map[types.LicenseCategory][]string{
|
||||
|
||||
Reference in New Issue
Block a user