mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Adding the ability to retrieve remote licenses from package.lock (#2708)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
This commit is contained in:
parent
0d5ebed74a
commit
f4e18961b9
@ -17,8 +17,9 @@ func NewPackageCataloger() pkg.Cataloger {
|
|||||||
// NewLockCataloger returns a new cataloger object for NPM (and NPM-adjacent, such as yarn) lock files.
|
// NewLockCataloger returns a new cataloger object for NPM (and NPM-adjacent, such as yarn) lock files.
|
||||||
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||||
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
||||||
|
packageLockAdapter := newGenericPackageLockAdapter(cfg)
|
||||||
return generic.NewCataloger("javascript-lock-cataloger").
|
return generic.NewCataloger("javascript-lock-cataloger").
|
||||||
WithParserByGlobs(parsePackageLock, "**/package-lock.json").
|
WithParserByGlobs(packageLockAdapter.parsePackageLock, "**/package-lock.json").
|
||||||
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
||||||
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
|
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ func newPackageJSONPackage(u packageJSON, indexLocation file.Location) pkg.Packa
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackageLockV1Package(resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
func newPackageLockV1Package(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
||||||
version := u.Version
|
version := u.Version
|
||||||
|
|
||||||
const aliasPrefixPackageLockV1 = "npm:"
|
const aliasPrefixPackageLockV1 = "npm:"
|
||||||
@ -63,12 +63,26 @@ func newPackageLockV1Package(resolver file.Resolver, location file.Location, nam
|
|||||||
version = canonicalPackageAndVersion[versionSeparator+1:]
|
version = canonicalPackageAndVersion[versionSeparator+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var licenseSet pkg.LicenseSet
|
||||||
|
|
||||||
|
if cfg.SearchRemoteLicenses {
|
||||||
|
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
||||||
|
if err == nil && license != "" {
|
||||||
|
licenses := pkg.NewLicensesFromValues(license)
|
||||||
|
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
resolver,
|
resolver,
|
||||||
location,
|
location,
|
||||||
pkg.Package{
|
pkg.Package{
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
Licenses: licenseSet,
|
||||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||||
PURL: packageURL(name, version),
|
PURL: packageURL(name, version),
|
||||||
Language: pkg.JavaScript,
|
Language: pkg.JavaScript,
|
||||||
@ -78,7 +92,22 @@ func newPackageLockV1Package(resolver file.Resolver, location file.Location, nam
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackageLockV2Package(resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
func newPackageLockV2Package(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
||||||
|
var licenseSet pkg.LicenseSet
|
||||||
|
|
||||||
|
if u.License != nil {
|
||||||
|
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(location, u.License...)...)
|
||||||
|
} else if cfg.SearchRemoteLicenses {
|
||||||
|
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, u.Version)
|
||||||
|
if err == nil && license != "" {
|
||||||
|
licenses := pkg.NewLicensesFromValues(license)
|
||||||
|
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, u.Version, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
resolver,
|
resolver,
|
||||||
location,
|
location,
|
||||||
@ -86,7 +115,7 @@ func newPackageLockV2Package(resolver file.Resolver, location file.Location, nam
|
|||||||
Name: name,
|
Name: name,
|
||||||
Version: u.Version,
|
Version: u.Version,
|
||||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(location, u.License...)...),
|
Licenses: licenseSet,
|
||||||
PURL: packageURL(name, u.Version),
|
PURL: packageURL(name, u.Version),
|
||||||
Language: pkg.JavaScript,
|
Language: pkg.JavaScript,
|
||||||
Type: pkg.NpmPkg,
|
Type: pkg.NpmPkg,
|
||||||
|
|||||||
@ -15,9 +15,6 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// integrity check
|
|
||||||
var _ generic.Parser = parsePackageLock
|
|
||||||
|
|
||||||
// packageLock represents a JavaScript package.lock json file
|
// packageLock represents a JavaScript package.lock json file
|
||||||
type packageLock struct {
|
type packageLock struct {
|
||||||
Requires bool `json:"requires"`
|
Requires bool `json:"requires"`
|
||||||
@ -44,8 +41,18 @@ type lockPackage struct {
|
|||||||
// packageLockLicense
|
// packageLockLicense
|
||||||
type packageLockLicense []string
|
type packageLockLicense []string
|
||||||
|
|
||||||
|
type genericPackageLockAdapter struct {
|
||||||
|
cfg CatalogerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGenericPackageLockAdapter(cfg CatalogerConfig) genericPackageLockAdapter {
|
||||||
|
return genericPackageLockAdapter{
|
||||||
|
cfg: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.
|
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.
|
||||||
func parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
// in the case we find package-lock.json files in the node_modules directories, skip those
|
// in the case we find package-lock.json files in the node_modules directories, skip those
|
||||||
// as the whole purpose of the lock file is for the specific dependencies of the root project
|
// as the whole purpose of the lock file is for the specific dependencies of the root project
|
||||||
if pathContainsNodeModulesDirectory(reader.Path()) {
|
if pathContainsNodeModulesDirectory(reader.Path()) {
|
||||||
@ -66,7 +73,7 @@ func parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Envi
|
|||||||
|
|
||||||
if lock.LockfileVersion == 1 {
|
if lock.LockfileVersion == 1 {
|
||||||
for name, pkgMeta := range lock.Dependencies {
|
for name, pkgMeta := range lock.Dependencies {
|
||||||
pkgs = append(pkgs, newPackageLockV1Package(resolver, reader.Location, name, pkgMeta))
|
pkgs = append(pkgs, newPackageLockV1Package(a.cfg, resolver, reader.Location, name, pkgMeta))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +93,7 @@ func parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Envi
|
|||||||
|
|
||||||
pkgs = append(
|
pkgs = append(
|
||||||
pkgs,
|
pkgs,
|
||||||
newPackageLockV2Package(resolver, reader.Location, getNameFromPath(name), pkgMeta),
|
newPackageLockV2Package(a.cfg, resolver, reader.Location, getNameFromPath(name), pkgMeta),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,8 @@ func TestParsePackageLock(t *testing.T) {
|
|||||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePackageLockV2(t *testing.T) {
|
func TestParsePackageLockV2(t *testing.T) {
|
||||||
@ -169,7 +170,8 @@ func TestParsePackageLockV2(t *testing.T) {
|
|||||||
for i := range expectedPkgs {
|
for i := range expectedPkgs {
|
||||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||||
}
|
}
|
||||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePackageLockV3(t *testing.T) {
|
func TestParsePackageLockV3(t *testing.T) {
|
||||||
@ -220,7 +222,8 @@ func TestParsePackageLockV3(t *testing.T) {
|
|||||||
for i := range expectedPkgs {
|
for i := range expectedPkgs {
|
||||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||||
}
|
}
|
||||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePackageLockAlias(t *testing.T) {
|
func TestParsePackageLockAlias(t *testing.T) {
|
||||||
@ -279,7 +282,8 @@ func TestParsePackageLockAlias(t *testing.T) {
|
|||||||
for i := range expected {
|
for i := range expected {
|
||||||
expected[i].Locations.Add(file.NewLocation(pl))
|
expected[i].Locations.Add(file.NewLocation(pl))
|
||||||
}
|
}
|
||||||
pkgtest.TestFileParser(t, pl, parsePackageLock, expected, expectedRelationships)
|
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, pl, adapter.parsePackageLock, expected, expectedRelationships)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,5 +330,6 @@ func TestParsePackageLockLicenseWithArray(t *testing.T) {
|
|||||||
for i := range expectedPkgs {
|
for i := range expectedPkgs {
|
||||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||||
}
|
}
|
||||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user