feat: license file search (#4327)

Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
Keith Zantow
2025-11-03 14:16:05 -05:00
committed by GitHub
parent 7c154e7c37
commit a400c675fc
32 changed files with 616 additions and 210 deletions
+13 -13
View File
@@ -16,9 +16,10 @@ import (
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/licenses"
)
func newPackageJSONPackage(ctx context.Context, u packageJSON, indexLocation file.Location) pkg.Package {
func newPackageJSONPackage(ctx context.Context, resolver file.Resolver, u packageJSON, indexLocation file.Location) pkg.Package {
licenseCandidates, err := u.licensesFromJSON()
if err != nil {
log.Debugf("unable to extract licenses from javascript package.json: %+v", err)
@@ -79,6 +80,9 @@ func newPackageJSONPackage(ctx context.Context, u packageJSON, indexLocation fil
p.SetID()
// if license not specified, search for license files
p = licenses.RelativeToPackage(ctx, resolver, p)
return p
}
@@ -103,8 +107,7 @@ func newPackageLockV1Package(ctx context.Context, cfg CatalogerConfig, resolver
if cfg.SearchRemoteLicenses {
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
if err == nil && license != "" {
licenses := pkg.NewLicensesFromValuesWithContext(ctx, license)
licenseSet = pkg.NewLicenseSet(licenses...)
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
}
if err != nil {
log.Debugf("unable to extract licenses from javascript package-lock.json for package %s:%s: %+v", name, version, err)
@@ -136,8 +139,7 @@ func newPackageLockV2Package(ctx context.Context, cfg CatalogerConfig, resolver
} else if cfg.SearchRemoteLicenses {
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, u.Version)
if err == nil && license != "" {
licenses := pkg.NewLicensesFromValuesWithContext(ctx, license)
licenseSet = pkg.NewLicenseSet(licenses...)
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
}
if err != nil {
log.Debugf("unable to extract licenses from javascript package-lock.json for package %s:%s: %+v", name, u.Version, err)
@@ -167,8 +169,7 @@ func newPnpmPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Reso
if cfg.SearchRemoteLicenses {
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
if err == nil && license != "" {
licenses := pkg.NewLicensesFromValuesWithContext(ctx, license)
licenseSet = pkg.NewLicenseSet(licenses...)
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
}
if err != nil {
log.Debugf("unable to extract licenses from javascript pnpm-lock.yaml for package %s:%s: %+v", name, version, err)
@@ -196,8 +197,7 @@ func newYarnLockPackage(ctx context.Context, cfg CatalogerConfig, resolver file.
if cfg.SearchRemoteLicenses {
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
if err == nil && license != "" {
licenses := pkg.NewLicensesFromValuesWithContext(ctx, license)
licenseSet = pkg.NewLicenseSet(licenses...)
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
}
if err != nil {
log.Debugf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
@@ -305,11 +305,11 @@ func addLicenses(name string, resolver file.Resolver, location file.Location) (a
}
for _, l := range locations {
licenses, err := parseLicensesFromLocation(l, resolver, pkgFile)
foundLicenses, err := parseLicensesFromLocation(l, resolver, pkgFile)
if err != nil {
return allLicenses
}
allLicenses = append(allLicenses, licenses...)
allLicenses = append(allLicenses, foundLicenses...)
}
return allLicenses
@@ -336,12 +336,12 @@ func parseLicensesFromLocation(l file.Location, resolver file.Resolver, pkgFile
return nil, err
}
licenses, err := pkgJSON.licensesFromJSON()
out, err := pkgJSON.licensesFromJSON()
if err != nil {
log.Debugf("error getting licenses from %s: %v", pkgFile, err)
return nil, err
}
return licenses, nil
return out, nil
}
// packageURL returns the PURL for the specific NPM package (see https://github.com/package-url/purl-spec)
@@ -57,7 +57,7 @@ type repository struct {
var authorPattern = regexp.MustCompile(`^\s*(?P<name>[^<(]*)(\s+<(?P<email>.*)>)?(\s\((?P<url>.*)\))?\s*$`)
// parsePackageJSON parses a package.json and returns the discovered JavaScript packages.
func parsePackageJSON(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
func parsePackageJSON(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package
dec := json.NewDecoder(reader)
@@ -73,7 +73,7 @@ func parsePackageJSON(ctx context.Context, _ file.Resolver, _ *generic.Environme
// a compliance filter later will remove these packages based on compliance rules
pkgs = append(
pkgs,
newPackageJSONPackage(ctx, p, reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
newPackageJSONPackage(ctx, resolver, p, reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
)
}