-
Notifications
You must be signed in to change notification settings - Fork 856
Detect license ID from full text when incidentally provided as a value #3876
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
4328a18
chore: update license signatures to inject context
spiffcs 165b63a
feat: refactor scanner; update to new License Constructors
spiffcs 772741c
chore: refactor catalogers that use scanner to use new constructor
spiffcs 75a823b
chore: refactor tests to take new ctx param
spiffcs d3f9987
chore: fix static analysis
spiffcs 47e3412
chore: small cleanup before unit test fixes
spiffcs 99ca2f2
fix: update unit tests to pass with new content expectations
spiffcs 884927f
chore: add back deprecated licenses
spiffcs 185adbe
chore: refactor other licenses to be created with packages in SPDX
spiffcs d569180
feat: add configuration for IncludeLicenseContent
spiffcs cac618d
test: update snapshots given contents no longer hashed
spiffcs d32e08c
tests: add new tests to cover changes in spdx format
spiffcs 920cb0f
chore: fix static analysis
spiffcs a1a046b
Merge branch 'main' into 3088-new-license-ctx-scaner
spiffcs 6e6ba9c
address review comments
wagoodman dde463a
fix tests
wagoodman 1aac0a7
feat: add warning in postload to communicate deprecated option
spiffcs 1d89ee2
chore: fix unit tests with new license constraints
spiffcs e5f45f0
tests: add tests to apply license content rules to the package tasks
spiffcs bbdc8c2
Merge remote-tracking branch 'origin/main' into 3088-new-license-ctx-…
wagoodman 3ae907c
chore: merge with main
spiffcs d2a0510
rename configuration
wagoodman 7875c3a
deprecate the license-coverage configuration
wagoodman 85046b0
put package ID under test when enforcing license config
wagoodman 03bdd8c
restore url-only license cases
wagoodman 84fc885
preserve whitespace in license contents
wagoodman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,79 @@ | ||
| package options | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/anchore/clio" | ||
| "github.com/anchore/syft/syft/cataloging" | ||
| ) | ||
|
|
||
| type licenseConfig struct { | ||
| IncludeUnknownLicenseContent bool `yaml:"include-unknown-license-content" json:"include-unknown-license-content" mapstructure:"include-unknown-license-content"` | ||
| LicenseCoverage float64 `yaml:"license-coverage" json:"license-coverage" mapstructure:"license-coverage"` | ||
| Content cataloging.LicenseContent `yaml:"content" json:"content" mapstructure:"content"` | ||
| // Deprecated: please use include-license-content instead | ||
| IncludeUnknownLicenseContent *bool `yaml:"-" json:"-" mapstructure:"include-unknown-license-content"` | ||
|
|
||
| Coverage float64 `yaml:"coverage" json:"coverage" mapstructure:"coverage"` | ||
| // Deprecated: please use coverage instead | ||
| LicenseCoverage *float64 `yaml:"license-coverage" json:"license-coverage" mapstructure:"license-coverage"` | ||
|
|
||
| AvailableLicenseContent []cataloging.LicenseContent `yaml:"-" json:"-" mapstructure:"-"` | ||
| } | ||
|
|
||
| var _ interface { | ||
| clio.FieldDescriber | ||
| } = (*licenseConfig)(nil) | ||
|
|
||
| func (o *licenseConfig) DescribeFields(descriptions clio.FieldDescriptionSet) { | ||
| descriptions.Add(&o.IncludeUnknownLicenseContent, `include the content of a license in the SBOM when syft | ||
| cannot determine a valid SPDX ID for the given license`) | ||
| descriptions.Add(&o.LicenseCoverage, `adjust the percent as a fraction of the total text, in normalized words, that | ||
| descriptions.Add(&o.Content, fmt.Sprintf("include the content of licenses in the SBOM for a given syft scan; valid values are: %s", o.AvailableLicenseContent)) | ||
| descriptions.Add(&o.IncludeUnknownLicenseContent, `deprecated: please use 'license-content' instead`) | ||
|
|
||
| descriptions.Add(&o.Coverage, `adjust the percent as a fraction of the total text, in normalized words, that | ||
| matches any valid license for the given inputs, expressed as a percentage across all of the licenses matched.`) | ||
| descriptions.Add(&o.LicenseCoverage, `deprecated: please use 'coverage' instead`) | ||
| } | ||
|
|
||
| func (o *licenseConfig) PostLoad() error { | ||
| cfg := cataloging.DefaultLicenseConfig() | ||
| defaultContent := cfg.IncludeContent | ||
| defaultCoverage := cfg.Coverage | ||
|
|
||
| // if both legacy and new fields are specified, error out | ||
| if o.IncludeUnknownLicenseContent != nil && o.Content != defaultContent { | ||
| return fmt.Errorf("both 'include-unknown-license-content' and 'content' are set, please use only 'content'") | ||
| } | ||
|
|
||
| if o.LicenseCoverage != nil && o.Coverage != defaultCoverage { | ||
| return fmt.Errorf("both 'license-coverage' and 'coverage' are set, please use only 'coverage'") | ||
| } | ||
|
|
||
| // finalize the license content value | ||
| if o.IncludeUnknownLicenseContent != nil { | ||
| // convert 'include-unknown-license-content' -> 'license-content' | ||
| v := cataloging.LicenseContentExcludeAll | ||
| if *o.IncludeUnknownLicenseContent { | ||
| v = cataloging.LicenseContentIncludeUnknown | ||
| } | ||
| o.Content = v | ||
| } | ||
|
|
||
| // finalize the coverage value | ||
| if o.LicenseCoverage != nil { | ||
| // convert 'license-coverage' -> 'coverage' | ||
| o.Coverage = *o.LicenseCoverage | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func defaultLicenseConfig() licenseConfig { | ||
| cfg := cataloging.DefaultLicenseConfig() | ||
| return licenseConfig{ | ||
| IncludeUnknownLicenseContent: false, | ||
| LicenseCoverage: 75, | ||
| Content: cfg.IncludeContent, | ||
| Coverage: cfg.Coverage, | ||
| AvailableLicenseContent: []cataloging.LicenseContent{ | ||
| cataloging.LicenseContentIncludeAll, | ||
| cataloging.LicenseContentIncludeUnknown, | ||
| cataloging.LicenseContentExcludeAll, | ||
| }, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package licenses | ||
|
|
||
| import ( | ||
| "context" | ||
| "io" | ||
| ) | ||
|
|
||
| func (s *scanner) FindEvidence(_ context.Context, reader io.Reader) (evidence []Evidence, content []byte, err error) { | ||
| if s.scanner == nil { | ||
| return nil, nil, nil | ||
| } | ||
|
|
||
| content, err = io.ReadAll(reader) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| cov := s.scanner(content) | ||
| if cov.Percent < s.coverageThreshold { | ||
| // unknown or no licenses here | ||
| // => check return content to Search to process | ||
| return nil, content, nil | ||
| } | ||
|
|
||
| evidence = make([]Evidence, 0) | ||
| for _, m := range cov.Match { | ||
| evidence = append(evidence, Evidence{ | ||
| ID: m.ID, | ||
| Type: m.Type, | ||
| Start: m.Start, | ||
| End: m.End, | ||
| IsURL: m.IsURL, | ||
| }) | ||
| } | ||
| return evidence, content, nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package licenses | ||
|
|
||
| import ( | ||
| "context" | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "github.com/google/licensecheck" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestDefaultScanner_FindEvidence(t *testing.T) { | ||
| testCases := []struct { | ||
| name string | ||
| fixture string | ||
| wantIDs []string // expected license IDs | ||
| minMatch int // minimum # of matches required | ||
| }{ | ||
| { | ||
| name: "Single licenses are able to be recognized and returned Apache 2.0", | ||
| fixture: "test-fixtures/apache-license-2.0", | ||
| wantIDs: []string{"Apache-2.0"}, | ||
| minMatch: 1, | ||
| }, | ||
| { | ||
| name: "Multiple Licenses are returned as evidence with duplicates at different offset", | ||
| fixture: "test-fixtures/multi-license", | ||
| wantIDs: []string{ | ||
| "MIT", | ||
| "MIT", | ||
| "NCSA", | ||
| "Apache-2.0", | ||
| "Zlib", | ||
| "Unlicense", | ||
| "BSD-2-Clause", | ||
| "BSD-2-Clause", | ||
| "BSD-3-Clause", | ||
| }, | ||
| minMatch: 2, | ||
| }, | ||
| } | ||
|
|
||
| scanner := testScanner() | ||
| for _, tc := range testCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| filePath := filepath.Clean(tc.fixture) | ||
| f, err := os.Open(filePath) | ||
| require.NoError(t, err) | ||
| defer f.Close() | ||
|
|
||
| evidence, content, err := scanner.FindEvidence(context.Background(), f) | ||
| require.NoError(t, err) | ||
| require.NotEmpty(t, content) | ||
| require.GreaterOrEqual(t, len(evidence), tc.minMatch, "expected at least %d matches", tc.minMatch) | ||
|
|
||
| var foundIDs []string | ||
| for _, ev := range evidence { | ||
| foundIDs = append(foundIDs, ev.ID) | ||
| } | ||
|
|
||
| require.ElementsMatch(t, tc.wantIDs, foundIDs, "expected license IDs %v, but got %v", tc.wantIDs, foundIDs) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func testScanner() Scanner { | ||
| return &scanner{ | ||
| coverageThreshold: DefaultCoverageThreshold, | ||
| scanner: licensecheck.Scan, | ||
| } | ||
| } | ||
|
|
||
| func mustOpen(fixture string) []byte { | ||
| content, err := os.ReadFile(fixture) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| return content | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.