feat: update syft license concept to complex struct (#1743)

this PR makes the following changes to update the underlying license model to have more expressive capabilities
it also provides some guarantee's surrounding the license values themselves

- Licenses are updated from string -> pkg.LicenseSet which contain pkg.License with the following fields:
- original `Value` read by syft
- If it's possible to construct licenses will always have a valid SPDX expression for downstream consumption
- the above is run against a generated list of SPDX license ID to try and find the correct ID
- SPDX concluded vs declared is added to the new struct
- URL source for license is added to the new struct
- Location source is added to the new struct to show where the expression was pulled from
This commit is contained in:
Christopher Angelo Phillips
2023-05-15 16:23:39 -04:00
committed by GitHub
parent 8046f09562
commit 42fa9e4965
126 changed files with 5165 additions and 1503 deletions
+35
View File
@@ -0,0 +1,35 @@
// package license provides common methods for working with SPDX license data
package license
import (
"fmt"
"github.com/github/go-spdx/v2/spdxexp"
"github.com/anchore/syft/internal/spdxlicense"
)
type Type string
const (
Declared Type = "declared"
Concluded Type = "concluded"
)
func ParseExpression(expression string) (string, error) {
licenseID, exists := spdxlicense.ID(expression)
if exists {
return licenseID, nil
}
// If it doesn't exist initially in the SPDX list it might be a more complex expression
// ignored variable is any invalid expressions
// TODO: contribute to spdxexp to expose deprecated license IDs
// https://github.com/anchore/syft/issues/1814
valid, _ := spdxexp.ValidateLicenses([]string{expression})
if !valid {
return "", fmt.Errorf("failed to validate spdx expression: %s", expression)
}
return expression, nil
}
+42
View File
@@ -0,0 +1,42 @@
package license
import "testing"
func TestParseExpression(t *testing.T) {
tests := []struct {
name string
expression string
want string
wantErr bool
}{
{
name: "valid single ID expression returns SPDX ID",
expression: "mit",
want: "MIT",
wantErr: false,
},
{
name: "Valid SPDX expression returns SPDX expression",
expression: "MIT OR Apache-2.0",
want: "MIT OR Apache-2.0",
},
{
name: "Invalid SPDX expression returns error",
expression: "MIT OR Apache-2.0 OR invalid",
want: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseExpression(tt.expression)
if (err != nil) != tt.wantErr {
t.Errorf("ParseExpression() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ParseExpression() got = %v, want %v", got, tt.want)
}
})
}
}