mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 06:26:30 +01:00
SPDX license list 3.29.0 rewrote every opensource.org seeAlso URL from opensource.org/licenses/<ID> to opensource.org/license/<ID> (and e.g. opensource.org/license/mit/ to opensource.org/license/MIT). Package metadata in the wild (Maven POM <license><url>, npm, etc.) still uses the older forms, so regenerating the list would stop LicenseByURL from resolving them. Fall back to a normalized index of the opensource.org entries that ignores the www. prefix, /licenses/ vs /license/, case, and a trailing slash. The index is built from the generated urlToLicense map, so it works with both the current and the updated license list without changes to the generator. URL forms that would normalize to different licenses are left out rather than guessed. Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
package spdxlicense
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
// https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-short-name
|
|
// License generated in license_list.go uses a regular expression to help resolve cases where
|
|
// x.0.0 and x are supplied as version numbers. For SPDX compatibility, versions with trailing
|
|
// dot-zeroes are considered to be equivalent to versions without (e.g., “2.0.0” is considered equal to “2.0” and “2”).
|
|
// EX: gpl-2+ ---> GPL-2.0+
|
|
// EX: gpl-2.0.0-only ---> GPL-2.0-only
|
|
// See the debian link for more details on the spdx license differences
|
|
|
|
const (
|
|
LicenseRefPrefix = "LicenseRef-" // prefix for non-standard licenses
|
|
)
|
|
|
|
//go:generate go run ./generate
|
|
|
|
// ID returns the canonical license ID for the given license ID
|
|
// Note: this function is only concerned with returning a best match of an SPDX license ID
|
|
// SPDX Expressions will be handled by a parent package which will call this function
|
|
func ID(id string) (value string, exists bool) {
|
|
// first look for a canonical license
|
|
if value, exists := licenseIDs[cleanLicenseID(id)]; exists {
|
|
return value, exists
|
|
}
|
|
// we did not find, so treat it as a separate license
|
|
return "", false
|
|
}
|
|
|
|
func cleanLicenseID(id string) string {
|
|
id = strings.TrimSpace(id)
|
|
id = strings.ToLower(id)
|
|
return strings.ReplaceAll(id, "-", "")
|
|
}
|
|
|
|
// LicenseInfo contains license ID and name
|
|
type LicenseInfo struct {
|
|
ID string
|
|
}
|
|
|
|
// LicenseByURL returns the license ID and name for a given URL from the SPDX license list.
|
|
// The URL should match one of the URLs in the seeAlso field of an SPDX license.
|
|
// The scheme (http:// or https://) is stripped before lookup, so both schemes match.
|
|
// opensource.org URLs additionally match regardless of the form used (see normalizeOpenSourceOrgURL).
|
|
func LicenseByURL(url string) (LicenseInfo, bool) {
|
|
url = strings.TrimSpace(url)
|
|
url = stripScheme(url)
|
|
if id, exists := urlToLicense[url]; exists {
|
|
return LicenseInfo{
|
|
ID: id,
|
|
}, true
|
|
}
|
|
if normalized, ok := normalizeOpenSourceOrgURL(url); ok {
|
|
if id, exists := openSourceOrgURLToLicense[normalized]; exists {
|
|
return LicenseInfo{
|
|
ID: id,
|
|
}, true
|
|
}
|
|
}
|
|
return LicenseInfo{}, false
|
|
}
|
|
|
|
// openSourceOrgURLToLicense indexes the opensource.org entries of urlToLicense by normalized URL.
|
|
var openSourceOrgURLToLicense = buildOpenSourceOrgURLToLicense(urlToLicense)
|
|
|
|
func buildOpenSourceOrgURLToLicense(urls map[string]string) map[string]string {
|
|
index := make(map[string]string)
|
|
ambiguous := make(map[string]bool)
|
|
for url, id := range urls {
|
|
normalized, ok := normalizeOpenSourceOrgURL(url)
|
|
if !ok || ambiguous[normalized] {
|
|
continue
|
|
}
|
|
if existing, exists := index[normalized]; exists && existing != id {
|
|
// don't guess between licenses that only differ by URL form
|
|
delete(index, normalized)
|
|
ambiguous[normalized] = true
|
|
continue
|
|
}
|
|
index[normalized] = id
|
|
}
|
|
return index
|
|
}
|
|
|
|
// normalizeOpenSourceOrgURL reduces a scheme-less opensource.org URL to a canonical form.
|
|
// SPDX has changed these URLs over time (e.g. 3.29.0 replaced opensource.org/licenses/MIT and
|
|
// opensource.org/license/mit/ with opensource.org/license/MIT), while package metadata in the wild
|
|
// still uses the older forms. The www. prefix, /licenses/ vs /license/, case, and trailing slash are ignored.
|
|
func normalizeOpenSourceOrgURL(url string) (string, bool) {
|
|
url = strings.TrimPrefix(strings.ToLower(url), "www.")
|
|
if !strings.HasPrefix(url, "opensource.org/") {
|
|
return "", false
|
|
}
|
|
url = strings.Replace(url, "opensource.org/licenses/", "opensource.org/license/", 1)
|
|
return strings.TrimSuffix(url, "/"), true
|
|
}
|
|
|
|
// stripScheme removes http:// or https:// prefix from a URL.
|
|
// This allows a single map entry to match both schemes.
|
|
func stripScheme(url string) string {
|
|
url = strings.TrimPrefix(url, "https://")
|
|
url = strings.TrimPrefix(url, "http://")
|
|
return url
|
|
}
|