mirror of
https://github.com/anchore/syft.git
synced 2026-11-05 00:46:38 +01:00
feat: 3626 add option enable license content; disable by default (#3631)
--------- Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package cataloging
|
||||
|
||||
import "github.com/anchore/syft/internal/licenses"
|
||||
|
||||
type LicenseConfig struct {
|
||||
IncludeUnkownLicenseContent bool `json:"include-unknown-license-content" yaml:"include-unknown-license-content" mapstructure:"include-unknown-license-content"`
|
||||
Coverage float64 `json:"coverage" yaml:"coverage" mapstructure:"coverage"`
|
||||
}
|
||||
|
||||
func DefaultLicenseConfig() LicenseConfig {
|
||||
return LicenseConfig{
|
||||
IncludeUnkownLicenseContent: licenses.DefaultIncludeLicenseContent,
|
||||
Coverage: licenses.DefaultCoverageThreshold,
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ type configurationAuditTrail struct {
|
||||
DataGeneration cataloging.DataGenerationConfig `json:"data-generation" yaml:"data-generation" mapstructure:"data-generation"`
|
||||
Packages pkgcataloging.Config `json:"packages" yaml:"packages" mapstructure:"packages"`
|
||||
Files filecataloging.Config `json:"files" yaml:"files" mapstructure:"files"`
|
||||
Licenses cataloging.LicenseConfig `json:"licenses" yaml:"licenses" mapstructure:"licenses"`
|
||||
Catalogers catalogerManifest `json:"catalogers" yaml:"catalogers" mapstructure:"catalogers"`
|
||||
ExtraConfigs any `json:"extra,omitempty" yaml:"extra" mapstructure:"extra"`
|
||||
}
|
||||
|
||||
+10
-2
@@ -52,6 +52,7 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) (
|
||||
DataGeneration: cfg.DataGeneration,
|
||||
Packages: cfg.Packages,
|
||||
Files: cfg.Files,
|
||||
Licenses: cfg.Licenses,
|
||||
Catalogers: *audit,
|
||||
ExtraConfigs: cfg.ToolConfiguration,
|
||||
},
|
||||
@@ -61,8 +62,15 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) (
|
||||
},
|
||||
}
|
||||
|
||||
// inject a single license scanner for all package cataloging tasks into context
|
||||
ctx = licenses.SetContextLicenseScanner(ctx, licenses.NewDefaultScanner())
|
||||
// inject a single license scanner and content config for all package cataloging tasks into context
|
||||
licenseScanner, err := licenses.NewDefaultScanner(
|
||||
licenses.WithIncludeLicenseContent(cfg.Licenses.IncludeUnkownLicenseContent),
|
||||
licenses.WithCoverage(cfg.Licenses.Coverage),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not build licenseScanner for cataloging: %w", err)
|
||||
}
|
||||
ctx = licenses.SetContextLicenseScanner(ctx, licenseScanner)
|
||||
|
||||
catalogingProgress := monitorCatalogingTask(src.ID(), taskGroups)
|
||||
packageCatalogingProgress := monitorPackageCatalogingTask()
|
||||
|
||||
@@ -26,6 +26,7 @@ type CreateSBOMConfig struct {
|
||||
Unknowns cataloging.UnknownsConfig
|
||||
DataGeneration cataloging.DataGenerationConfig
|
||||
Packages pkgcataloging.Config
|
||||
Licenses cataloging.LicenseConfig
|
||||
Files filecataloging.Config
|
||||
Parallelism int
|
||||
CatalogerSelection cataloging.SelectionRequest
|
||||
@@ -46,6 +47,7 @@ func DefaultCreateSBOMConfig() *CreateSBOMConfig {
|
||||
Relationships: cataloging.DefaultRelationshipsConfig(),
|
||||
DataGeneration: cataloging.DefaultDataGenerationConfig(),
|
||||
Packages: pkgcataloging.DefaultConfig(),
|
||||
Licenses: cataloging.DefaultLicenseConfig(),
|
||||
Files: filecataloging.DefaultConfig(),
|
||||
Parallelism: 1,
|
||||
packageTaskFactories: task.DefaultPackageTaskFactories(),
|
||||
@@ -134,6 +136,12 @@ func (c *CreateSBOMConfig) WithPackagesConfig(cfg pkgcataloging.Config) *CreateS
|
||||
return c
|
||||
}
|
||||
|
||||
// WithPackagesConfig allows for defining any specific behavior for syft-implemented catalogers.
|
||||
func (c *CreateSBOMConfig) WithLicenseConfig(cfg cataloging.LicenseConfig) *CreateSBOMConfig {
|
||||
c.Licenses = cfg
|
||||
return c
|
||||
}
|
||||
|
||||
// WithFilesConfig allows for defining file-based cataloging parameters.
|
||||
func (c *CreateSBOMConfig) WithFilesConfig(cfg filecataloging.Config) *CreateSBOMConfig {
|
||||
c.Files = cfg
|
||||
|
||||
@@ -10,6 +10,7 @@ type License struct {
|
||||
SPDXExpression string
|
||||
Type license.Type
|
||||
LicenseEvidence *LicenseEvidence // evidence from license classifier
|
||||
Contents string `hash:"ignore"`
|
||||
}
|
||||
|
||||
type LicenseEvidence struct {
|
||||
|
||||
@@ -214,7 +214,7 @@ func (c *goLicenseResolver) findLicensesInFS(ctx context.Context, scanner licens
|
||||
}
|
||||
defer internal.CloseAndLogError(rdr, filePath)
|
||||
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(file.NewLocation(filePath), rdr))
|
||||
parsed, err := scanner.PkgSearch(ctx, file.NewLocationReadCloser(file.NewLocation(filePath), rdr))
|
||||
if err != nil {
|
||||
log.Debugf("error parsing license file %s: %v", filePath, err)
|
||||
return nil
|
||||
@@ -267,7 +267,7 @@ func (c *goLicenseResolver) parseLicenseFromLocation(ctx context.Context, scanne
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(contents, l.RealPath)
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(l, contents))
|
||||
parsed, err := scanner.PkgSearch(ctx, file.NewLocationReadCloser(l, contents))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -71,7 +71,12 @@ func Test_LicenseSearch(t *testing.T) {
|
||||
|
||||
localVendorDir := filepath.Join(wd, "test-fixtures", "licenses-vendor")
|
||||
|
||||
licenseScanner := licenses.NewScanner(licensecheck.Scan, float64(75))
|
||||
sc := &licenses.ScannerConfig{
|
||||
CoverageThreshold: 75,
|
||||
Scanner: licensecheck.Scan,
|
||||
}
|
||||
licenseScanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -296,7 +301,10 @@ func Test_findVersionPath(t *testing.T) {
|
||||
|
||||
func Test_walkDirErrors(t *testing.T) {
|
||||
resolver := newGoLicenseResolver("", CatalogerConfig{})
|
||||
_, err := resolver.findLicensesInFS(context.Background(), licenses.NewScanner(licensecheck.Scan, float64(75)), "somewhere", badFS{})
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
scanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
_, err = resolver.findLicensesInFS(context.Background(), scanner, "somewhere", badFS{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -314,7 +322,9 @@ func Test_noLocalGoModDir(t *testing.T) {
|
||||
validTmp := t.TempDir()
|
||||
require.NoError(t, os.MkdirAll(filepath.Join(validTmp, "mod@ver"), 0700|os.ModeDir))
|
||||
|
||||
licenseScanner := licenses.NewScanner(licensecheck.Scan, float64(75))
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
licenseScanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
dir string
|
||||
|
||||
@@ -63,7 +63,10 @@ func newGoBinaryCataloger(opts CatalogerConfig) *goBinaryCataloger {
|
||||
func (c *goBinaryCataloger) parseGoBinary(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
licenseScanner, err := licenses.ContextLicenseScanner(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
unionReader, err := unionreader.GetUnionReader(reader.ReadCloser)
|
||||
if err != nil {
|
||||
|
||||
@@ -170,7 +170,9 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
licenseScanner := licenses.NewScanner(licensecheck.Scan, float64(75))
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
licenseScanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -35,7 +35,10 @@ func newGoModCataloger(opts CatalogerConfig) *goModCataloger {
|
||||
func (c *goModCataloger) parseGoModFile(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
packages := make(map[string]pkg.Package)
|
||||
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
licenseScanner, err := licenses.ContextLicenseScanner(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create default license scanner: %w", err)
|
||||
}
|
||||
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
|
||||
@@ -96,7 +96,10 @@ func uniquePkgKey(groupID string, p *pkg.Package) string {
|
||||
// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
|
||||
// and parse nested archives or ignore them.
|
||||
func newJavaArchiveParser(ctx context.Context, reader file.LocationReadCloser, detectNested bool, cfg ArchiveCatalogerConfig) (*archiveParser, func(), error) {
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
licenseScanner, err := licenses.ContextLicenseScanner(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not build license scanner for java archive parser: %w", err)
|
||||
}
|
||||
|
||||
// fetch the last element of the virtual path
|
||||
virtualElements := strings.Split(reader.Path(), ":")
|
||||
@@ -506,7 +509,7 @@ func (j *archiveParser) getLicenseFromFileInArchive(ctx context.Context) ([]pkg.
|
||||
for _, licenseMatch := range licenseMatches {
|
||||
licenseContents := contents[licenseMatch]
|
||||
r := strings.NewReader(licenseContents)
|
||||
parsed, err := licenses.Search(ctx, j.licenseScanner, file.NewLocationReadCloser(j.location, io.NopCloser(r)))
|
||||
parsed, err := j.licenseScanner.PkgSearch(ctx, file.NewLocationReadCloser(j.location, io.NopCloser(r)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@ import (
|
||||
|
||||
func TestSearchMavenForLicenses(t *testing.T) {
|
||||
url := maventest.MockRepo(t, "internal/maven/test-fixtures/maven-repo")
|
||||
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.NewScanner(licensecheck.Scan, float64(75)))
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
scanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), scanner)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -92,7 +94,10 @@ func TestSearchMavenForLicenses(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseJar(t *testing.T) {
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.NewScanner(licensecheck.Scan, float64(75)))
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
scanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), scanner)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1375,7 +1380,10 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_deterministicMatchingPomProperties(t *testing.T) {
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.NewScanner(licensecheck.Scan, float64(75)))
|
||||
sc := &licenses.ScannerConfig{Scanner: licensecheck.Scan, CoverageThreshold: 75}
|
||||
scanner, err := licenses.NewScanner(sc)
|
||||
require.NoError(t, err)
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), scanner)
|
||||
|
||||
tests := []struct {
|
||||
fixture string
|
||||
|
||||
@@ -109,7 +109,7 @@ func findLicenses(ctx context.Context, scanner licenses.Scanner, resolver file.R
|
||||
if len(found) > 0 {
|
||||
metadataContents, err := resolver.FileContentsByLocation(found[0])
|
||||
if err == nil {
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(m.LicenseLocation, metadataContents))
|
||||
parsed, err := scanner.PkgSearch(ctx, file.NewLocationReadCloser(m.LicenseLocation, metadataContents))
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path())
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
// parseWheelOrEgg takes the primary metadata file reference and returns the python package it represents. Contained
|
||||
// fields are governed by the PyPA core metadata specification (https://packaging.python.org/en/latest/specifications/core-metadata/).
|
||||
func parseWheelOrEgg(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
|
||||
licenseScanner, err := licenses.ContextLicenseScanner(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pd, sources, err := assembleEggOrWheelMetadata(resolver, reader.Location)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
Reference in New Issue
Block a user