mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
432 lines
13 KiB
Go
432 lines
13 KiB
Go
package expression
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/samber/lo"
|
|
|
|
"github.com/aquasecurity/trivy/pkg/log"
|
|
"github.com/aquasecurity/trivy/pkg/set"
|
|
|
|
_ "embed"
|
|
)
|
|
|
|
// Canonical names of the licenses.
|
|
// ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L24-L177
|
|
const (
|
|
// The names come from the https://spdx.org/licenses website, and are
|
|
// also the filenames of the licenses in licenseclassifier/licenses.
|
|
AFL11 = "AFL-1.1"
|
|
AFL12 = "AFL-1.2"
|
|
AFL20 = "AFL-2.0"
|
|
AFL21 = "AFL-2.1"
|
|
AFL30 = "AFL-3.0"
|
|
AGPL10 = "AGPL-1.0"
|
|
AGPL30 = "AGPL-3.0"
|
|
Apache10 = "Apache-1.0"
|
|
Apache11 = "Apache-1.1"
|
|
Apache20 = "Apache-2.0"
|
|
APSL10 = "APSL-1.0"
|
|
APSL11 = "APSL-1.1"
|
|
APSL12 = "APSL-1.2"
|
|
APSL20 = "APSL-2.0"
|
|
Artistic10cl8 = "Artistic-1.0-cl8"
|
|
Artistic10Perl = "Artistic-1.0-Perl"
|
|
Artistic10 = "Artistic-1.0"
|
|
Artistic20 = "Artistic-2.0"
|
|
BCL = "BCL"
|
|
Beerware = "Beerware"
|
|
BSD2ClauseFreeBSD = "BSD-2-Clause-FreeBSD"
|
|
BSD2ClauseNetBSD = "BSD-2-Clause-NetBSD"
|
|
BSD2Clause = "BSD-2-Clause"
|
|
BSD3ClauseAttribution = "BSD-3-Clause-Attribution"
|
|
BSD3ClauseClear = "BSD-3-Clause-Clear"
|
|
BSD3ClauseLBNL = "BSD-3-Clause-LBNL"
|
|
BSD3Clause = "BSD-3-Clause"
|
|
BSD4Clause = "BSD-4-Clause"
|
|
BSD4ClauseUC = "BSD-4-Clause-UC"
|
|
BSDProtection = "BSD-Protection"
|
|
BSL10 = "BSL-1.0"
|
|
CC010 = "CC0-1.0"
|
|
CCBY10 = "CC-BY-1.0"
|
|
CCBY20 = "CC-BY-2.0"
|
|
CCBY25 = "CC-BY-2.5"
|
|
CCBY30 = "CC-BY-3.0"
|
|
CCBY40 = "CC-BY-4.0"
|
|
CCBYNC10 = "CC-BY-NC-1.0"
|
|
CCBYNC20 = "CC-BY-NC-2.0"
|
|
CCBYNC25 = "CC-BY-NC-2.5"
|
|
CCBYNC30 = "CC-BY-NC-3.0"
|
|
CCBYNC40 = "CC-BY-NC-4.0"
|
|
CCBYNCND10 = "CC-BY-NC-ND-1.0"
|
|
CCBYNCND20 = "CC-BY-NC-ND-2.0"
|
|
CCBYNCND25 = "CC-BY-NC-ND-2.5"
|
|
CCBYNCND30 = "CC-BY-NC-ND-3.0"
|
|
CCBYNCND40 = "CC-BY-NC-ND-4.0"
|
|
CCBYNCSA10 = "CC-BY-NC-SA-1.0"
|
|
CCBYNCSA20 = "CC-BY-NC-SA-2.0"
|
|
CCBYNCSA25 = "CC-BY-NC-SA-2.5"
|
|
CCBYNCSA30 = "CC-BY-NC-SA-3.0"
|
|
CCBYNCSA40 = "CC-BY-NC-SA-4.0"
|
|
CCBYND10 = "CC-BY-ND-1.0"
|
|
CCBYND20 = "CC-BY-ND-2.0"
|
|
CCBYND25 = "CC-BY-ND-2.5"
|
|
CCBYND30 = "CC-BY-ND-3.0"
|
|
CCBYND40 = "CC-BY-ND-4.0"
|
|
CCBYSA10 = "CC-BY-SA-1.0"
|
|
CCBYSA20 = "CC-BY-SA-2.0"
|
|
CCBYSA25 = "CC-BY-SA-2.5"
|
|
CCBYSA30 = "CC-BY-SA-3.0"
|
|
CCBYSA40 = "CC-BY-SA-4.0"
|
|
CDDL10 = "CDDL-1.0"
|
|
CDDL11 = "CDDL-1.1"
|
|
CommonsClause = "Commons-Clause"
|
|
CPAL10 = "CPAL-1.0"
|
|
CPL10 = "CPL-1.0"
|
|
EGenix = "eGenix"
|
|
EPL10 = "EPL-1.0"
|
|
EPL20 = "EPL-2.0"
|
|
EUPL10 = "EUPL-1.0"
|
|
EUPL11 = "EUPL-1.1"
|
|
Facebook2Clause = "Facebook-2-Clause"
|
|
Facebook3Clause = "Facebook-3-Clause"
|
|
FacebookExamples = "Facebook-Examples"
|
|
FreeImage = "FreeImage"
|
|
FTL = "FTL"
|
|
GFDL11WithInvariants = "GFDL-1.1-invariants"
|
|
GFDL11NoInvariants = "GFDL-1.1-no-invariants"
|
|
GFDL11 = "GFDL-1.1"
|
|
GFDL12WithInvariants = "GFDL-1.2-invariants"
|
|
GFDL12NoInvariants = "GFDL-1.2-no-invariants"
|
|
GFDL12 = "GFDL-1.2"
|
|
GFDL13WithInvariants = "GFDL-1.3-invariants"
|
|
GFDL13NoInvariants = "GFDL-1.3-no-invariants"
|
|
GFDL13 = "GFDL-1.3"
|
|
GPL10 = "GPL-1.0"
|
|
GPL20 = "GPL-2.0"
|
|
GPL20withautoconfexception = "GPL-2.0-with-autoconf-exception"
|
|
GPL20withbisonexception = "GPL-2.0-with-bison-exception"
|
|
GPL20withclasspathexception = "GPL-2.0-with-classpath-exception"
|
|
GPL20withfontexception = "GPL-2.0-with-font-exception"
|
|
GPL20withGCCexception = "GPL-2.0-with-GCC-exception"
|
|
GPL30 = "GPL-3.0"
|
|
GPL30withautoconfexception = "GPL-3.0-with-autoconf-exception"
|
|
GPL30withGCCexception = "GPL-3.0-with-GCC-exception"
|
|
GUSTFont = "GUST-Font-License"
|
|
ImageMagick = "ImageMagick"
|
|
IPL10 = "IPL-1.0"
|
|
ISC = "ISC"
|
|
LGPL20 = "LGPL-2.0"
|
|
LGPL21 = "LGPL-2.1"
|
|
LGPL30 = "LGPL-3.0"
|
|
LGPLLR = "LGPLLR"
|
|
Libpng = "Libpng"
|
|
Lil10 = "Lil-1.0"
|
|
LinuxOpenIB = "Linux-OpenIB"
|
|
LPL102 = "LPL-1.02"
|
|
LPL10 = "LPL-1.0"
|
|
LPPL13c = "LPPL-1.3c"
|
|
MIT = "MIT"
|
|
MPL10 = "MPL-1.0"
|
|
MPL11 = "MPL-1.1"
|
|
MPL20 = "MPL-2.0"
|
|
MSPL = "MS-PL"
|
|
NCSA = "NCSA"
|
|
NPL10 = "NPL-1.0"
|
|
NPL11 = "NPL-1.1"
|
|
OFL11 = "OFL-1.1"
|
|
OpenSSL = "OpenSSL"
|
|
OpenVision = "OpenVision"
|
|
OSL10 = "OSL-1.0"
|
|
OSL11 = "OSL-1.1"
|
|
OSL20 = "OSL-2.0"
|
|
OSL21 = "OSL-2.1"
|
|
OSL30 = "OSL-3.0"
|
|
PHP301 = "PHP-3.01"
|
|
PHP30 = "PHP-3.0"
|
|
PIL = "PIL"
|
|
PostgreSQL = "PostgreSQL"
|
|
Python20complete = "Python-2.0-complete"
|
|
Python20 = "Python-2.0"
|
|
QPL10 = "QPL-1.0"
|
|
Ruby = "Ruby"
|
|
SGIB10 = "SGI-B-1.0"
|
|
SGIB11 = "SGI-B-1.1"
|
|
SGIB20 = "SGI-B-2.0"
|
|
SISSL12 = "SISSL-1.2"
|
|
SISSL = "SISSL"
|
|
Sleepycat = "Sleepycat"
|
|
UnicodeTOU = "Unicode-TOU"
|
|
UnicodeDFS2015 = "Unicode-DFS-2015"
|
|
UnicodeDFS2016 = "Unicode-DFS-2016"
|
|
Unlicense = "Unlicense"
|
|
UPL10 = "UPL-1.0"
|
|
W3C19980720 = "W3C-19980720"
|
|
W3C20150513 = "W3C-20150513"
|
|
W3C = "W3C"
|
|
WTFPL = "WTFPL"
|
|
X11 = "X11"
|
|
Xnet = "Xnet"
|
|
Zend20 = "Zend-2.0"
|
|
ZeroBSD = "0BSD"
|
|
ZlibAcknowledgement = "zlib-acknowledgement"
|
|
Zlib = "Zlib"
|
|
ZPL11 = "ZPL-1.1"
|
|
ZPL20 = "ZPL-2.0"
|
|
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
|
|
ForbiddenLicenses = []string{
|
|
AGPL10,
|
|
AGPL30,
|
|
CCBYNC10,
|
|
CCBYNC20,
|
|
CCBYNC25,
|
|
CCBYNC30,
|
|
CCBYNC40,
|
|
CCBYNCND10,
|
|
CCBYNCND20,
|
|
CCBYNCND25,
|
|
CCBYNCND30,
|
|
CCBYNCND40,
|
|
CCBYNCSA10,
|
|
CCBYNCSA20,
|
|
CCBYNCSA25,
|
|
CCBYNCSA30,
|
|
CCBYNCSA40,
|
|
CommonsClause,
|
|
Facebook2Clause,
|
|
Facebook3Clause,
|
|
FacebookExamples,
|
|
WTFPL,
|
|
}
|
|
|
|
// RestrictedLicenses - Licenses in this category require mandatory source distribution if we ship a product
|
|
// that includes third-party code protected by such a license.
|
|
// ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L182-L219
|
|
RestrictedLicenses = []string{
|
|
BCL,
|
|
CCBYND10,
|
|
CCBYND20,
|
|
CCBYND25,
|
|
CCBYND30,
|
|
CCBYND40,
|
|
CCBYSA10,
|
|
CCBYSA20,
|
|
CCBYSA25,
|
|
CCBYSA30,
|
|
CCBYSA40,
|
|
GPL10,
|
|
GPL20,
|
|
GPL20withautoconfexception,
|
|
GPL20withbisonexception,
|
|
GPL20withclasspathexception,
|
|
GPL20withfontexception,
|
|
GPL20withGCCexception,
|
|
GPL30,
|
|
GPL30withautoconfexception,
|
|
GPL30withGCCexception,
|
|
LGPL20,
|
|
LGPL21,
|
|
LGPL30,
|
|
NPL10,
|
|
NPL11,
|
|
OSL10,
|
|
OSL11,
|
|
OSL20,
|
|
OSL21,
|
|
OSL30,
|
|
QPL10,
|
|
Sleepycat,
|
|
}
|
|
|
|
// ReciprocalLicenses - These licenses allow usage of software made available under such licenses freely
|
|
// in *unmodified* form. If the third-party source code is modified in any way these modifications to the
|
|
// original third-party source code must be made available.
|
|
ReciprocalLicenses = []string{
|
|
APSL10,
|
|
APSL11,
|
|
APSL12,
|
|
APSL20,
|
|
CDDL10,
|
|
CDDL11,
|
|
CPL10,
|
|
EPL10,
|
|
EPL20,
|
|
FreeImage,
|
|
IPL10,
|
|
MPL10,
|
|
MPL11,
|
|
MPL20,
|
|
Ruby,
|
|
}
|
|
|
|
// NoticeLicenses - These licenses contain few restrictions, allowing original or modified third-party software
|
|
// to be shipped in any product without endangering or encumbering our source code.
|
|
// All of the licenses in this category do, however, have an "original Copyright notice" or "advertising clause",
|
|
// wherein any external distributions must include the notice or clause specified in the license.
|
|
NoticeLicenses = []string{
|
|
AFL11,
|
|
AFL12,
|
|
AFL20,
|
|
AFL21,
|
|
AFL30,
|
|
Apache10,
|
|
Apache11,
|
|
Apache20,
|
|
Artistic10cl8,
|
|
Artistic10Perl,
|
|
Artistic10,
|
|
Artistic20,
|
|
BSL10,
|
|
BSD2ClauseFreeBSD,
|
|
BSD2ClauseNetBSD,
|
|
BSD2Clause,
|
|
BSD3ClauseAttribution,
|
|
BSD3ClauseClear,
|
|
BSD3ClauseLBNL,
|
|
BSD3Clause,
|
|
BSD4Clause,
|
|
BSD4ClauseUC,
|
|
BSDProtection,
|
|
CCBY10,
|
|
CCBY20,
|
|
CCBY25,
|
|
CCBY30,
|
|
CCBY40,
|
|
FTL,
|
|
ISC,
|
|
ImageMagick,
|
|
Libpng,
|
|
Lil10,
|
|
LinuxOpenIB,
|
|
LPL102,
|
|
LPL10,
|
|
MSPL,
|
|
MIT,
|
|
NCSA,
|
|
OpenSSL,
|
|
PHP301,
|
|
PHP30,
|
|
PIL,
|
|
Python20,
|
|
Python20complete,
|
|
PostgreSQL,
|
|
SGIB10,
|
|
SGIB11,
|
|
SGIB20,
|
|
UnicodeDFS2015,
|
|
UnicodeDFS2016,
|
|
UnicodeTOU,
|
|
UPL10,
|
|
W3C19980720,
|
|
W3C20150513,
|
|
W3C,
|
|
X11,
|
|
Xnet,
|
|
Zend20,
|
|
ZlibAcknowledgement,
|
|
Zlib,
|
|
ZPL11,
|
|
ZPL20,
|
|
ZPL21,
|
|
}
|
|
|
|
// PermissiveLicenses - These licenses can be used in (relatively rare) cases where third-party software is
|
|
// under a license (not "Public Domain" or "free for any use" like 'unencumbered') that is even more lenient
|
|
// than a 'notice' license. Use the 'permissive' license type when even a copyright notice is not required
|
|
// for license compliance.
|
|
PermissiveLicenses []string
|
|
|
|
// UnencumberedLicenses - Licenses that basically declare that the code is "free for any use".
|
|
UnencumberedLicenses = []string{
|
|
CC010,
|
|
Unlicense,
|
|
ZeroBSD,
|
|
}
|
|
)
|
|
|
|
var spdxLicenses = set.New[string]()
|
|
|
|
//go:embed licenses.json
|
|
var licenses []byte
|
|
|
|
var initSpdxLicenses = sync.OnceFunc(func() {
|
|
if spdxLicenses.Size() > 0 {
|
|
return
|
|
}
|
|
|
|
var lics []string
|
|
if err := json.Unmarshal(licenses, &lics); err != nil {
|
|
log.WithPrefix(log.PrefixSPDX).Warn("Unable to parse SPDX license file", log.Err(err))
|
|
return
|
|
}
|
|
|
|
// SPDX license list is case-insensitive. Store in upper case for simplicity.
|
|
spdxLicenses.Append(lo.Map(lics, func(l string, _ int) string {
|
|
return strings.ToUpper(l)
|
|
})...)
|
|
})
|
|
|
|
//go:embed exceptions.json
|
|
var exceptions []byte
|
|
|
|
var spdxExceptions map[string]SimpleExpr
|
|
|
|
var initSpdxExceptions = sync.OnceFunc(func() {
|
|
if len(spdxExceptions) > 0 {
|
|
return
|
|
}
|
|
|
|
var exs []string
|
|
if err := json.Unmarshal(exceptions, &exs); err != nil {
|
|
log.WithPrefix(log.PrefixSPDX).Warn("Unable to parse SPDX exception file", log.Err(err))
|
|
return
|
|
}
|
|
spdxExceptions = lo.SliceToMap(exs, func(exception string) (string, SimpleExpr) {
|
|
return strings.ToUpper(exception), SimpleExpr{License: exception}
|
|
})
|
|
})
|
|
|
|
// ValidateSPDXLicense returns true if SPDX license list contain licenseID
|
|
func ValidateSPDXLicense(license string) bool {
|
|
initSpdxLicenses()
|
|
|
|
return spdxLicenses.Contains(strings.ToUpper(license))
|
|
}
|
|
|
|
// ValidateSPDXException returns true if SPDX exception list contain exceptionID
|
|
func ValidateSPDXException(exception string) bool {
|
|
initSpdxExceptions()
|
|
|
|
_, ok := spdxExceptions[strings.ToUpper(exception)]
|
|
return ok
|
|
}
|