mirror of
https://github.com/anchore/syft.git
synced 2026-11-02 23:46:35 +01:00
perf(javascript): cache npm registry license lookups across runs (#5297)
When javascript.search-remote-licenses is enabled, the lock catalogers query registry.npmjs.org once per package occurrence, on every run, with nothing in front of the network call. The same name@version is fetched again for every lockfile that mentions it, and again on the next scan. This adds a javascriptLicenseResolver that resolves licenses through syft's on-disk cache, keyed on "<name>/<version>" and namespaced as javascript/v1, and routes the package-lock v1, package-lock v2, pnpm, yarn and bun package constructors through it, leaving getLicenseFromNpmRegistry itself unchanged. Failed lookups are not cached: a transient registry failure or a name that 404s must not be able to blank out licenses for the lifetime of the cache entry, since a missing license silently weakens downstream license policy checks. A successful lookup that returns an empty license is a real answer and is still cached. Signed-off-by: Anže Pečar <anze@pecar.me>
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
package javascript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/cache"
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// javascriptLicenseResolver resolves licenses for a package from the npm registry, backed by syft's
|
||||||
|
// on-disk cache so that the same package/version is only fetched once -- both within a single run
|
||||||
|
// (the same dependency is commonly present in several lockfiles) and across runs.
|
||||||
|
//
|
||||||
|
// This mirrors the python cataloger's license resolver (see syft/pkg/cataloger/python/license.go)
|
||||||
|
// with one deliberate difference: errors are not cached (cache.GetResolver rather than
|
||||||
|
// cache.GetResolverCachingErrors). A missing license silently weakens downstream license policy
|
||||||
|
// checks, so a transient registry failure (a 429, an outage) or a private package name that 404s
|
||||||
|
// against the public registry must not be able to blank out licenses for the lifetime of the cache
|
||||||
|
// entry. A successful lookup that returns an empty license is a real answer and is still cached.
|
||||||
|
type javascriptLicenseResolver struct {
|
||||||
|
catalogerConfig CatalogerConfig
|
||||||
|
licenseCache cache.Resolver[string]
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJavascriptLicenseResolver(config CatalogerConfig) javascriptLicenseResolver {
|
||||||
|
return javascriptLicenseResolver{
|
||||||
|
licenseCache: cache.GetResolver[string]("javascript", "v1"),
|
||||||
|
catalogerConfig: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lr *javascriptLicenseResolver) getLicenses(ctx context.Context, packageName string, packageVersion string) pkg.LicenseSet {
|
||||||
|
var licenseSet pkg.LicenseSet
|
||||||
|
|
||||||
|
if lr.catalogerConfig.SearchRemoteLicenses {
|
||||||
|
license, err := lr.getLicensesFromRemote(packageName, packageVersion)
|
||||||
|
if err == nil && license != "" {
|
||||||
|
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("unable to extract licenses from npm registry for package %s:%s: %+v", packageName, packageVersion, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return licenseSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lr *javascriptLicenseResolver) getLicensesFromRemote(packageName string, packageVersion string) (string, error) {
|
||||||
|
return lr.licenseCache.Resolve(fmt.Sprintf("%s/%s", packageName, packageVersion), func() (string, error) {
|
||||||
|
return getLicenseFromNpmRegistry(lr.catalogerConfig.NPMBaseURL, packageName, packageVersion)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
package javascript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/cache"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// useInMemoryCache installs a real (in-memory) cache manager for the duration of the test. By
|
||||||
|
// default syft's cache manager is bypassed, which is what keeps the rest of the cataloger tests
|
||||||
|
// isolated from one another; these tests need a functioning cache to observe caching behavior.
|
||||||
|
func useInMemoryCache(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
prev := cache.GetManager()
|
||||||
|
cache.SetManager(cache.NewInMemory(time.Hour))
|
||||||
|
t.Cleanup(func() { cache.SetManager(prev) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// npmRegistryStub is a stand-in for registry.npmjs.org that counts the requests it serves.
|
||||||
|
type npmRegistryStub struct {
|
||||||
|
*httptest.Server
|
||||||
|
requests atomic.Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNpmRegistryStub(t *testing.T, handler http.HandlerFunc) *npmRegistryStub {
|
||||||
|
t.Helper()
|
||||||
|
stub := &npmRegistryStub{}
|
||||||
|
stub.Server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
stub.requests.Add(1)
|
||||||
|
handler(w, r)
|
||||||
|
}))
|
||||||
|
t.Cleanup(stub.Close)
|
||||||
|
return stub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *npmRegistryStub) config() CatalogerConfig {
|
||||||
|
return CatalogerConfig{SearchRemoteLicenses: true, NPMBaseURL: s.URL}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_cachesSuccessfulLookups(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"license": "MIT"}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
lr := newJavascriptLicenseResolver(stub.config())
|
||||||
|
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
license, err := lr.getLicensesFromRemote("@babel/code-frame", "7.10.4")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "MIT", license)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), stub.requests.Load(), "expected only the first lookup to reach the registry")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_cacheIsSharedAcrossResolvers(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"license": "MIT"}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// the same package/version is commonly present in more than one lockfile, each of which is
|
||||||
|
// parsed by a different adapter with its own resolver -- the cache is still shared
|
||||||
|
first := newJavascriptLicenseResolver(stub.config())
|
||||||
|
second := newJavascriptLicenseResolver(stub.config())
|
||||||
|
|
||||||
|
license, err := first.getLicensesFromRemote("lodash", "4.17.21")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "MIT", license)
|
||||||
|
|
||||||
|
license, err = second.getLicensesFromRemote("lodash", "4.17.21")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "MIT", license)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), stub.requests.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_cachesEmptyLicense(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
// a package that genuinely publishes no license field is a real answer, not a failure
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"name": "no-license-pkg"}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
lr := newJavascriptLicenseResolver(stub.config())
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
license, err := lr.getLicensesFromRemote("no-license-pkg", "1.0.0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "", license)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), stub.requests.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_doesNotCacheErrors(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
// unlike the python cataloger we intentionally do not cache failed lookups: a transient
|
||||||
|
// registry failure must not be able to blank out licenses for the lifetime of the cache entry
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusTooManyRequests)
|
||||||
|
fmt.Fprintf(w, `too many requests`) // not valid JSON
|
||||||
|
})
|
||||||
|
|
||||||
|
lr := newJavascriptLicenseResolver(stub.config())
|
||||||
|
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
_, err := lr.getLicensesFromRemote("@babel/code-frame", "7.10.4")
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), stub.requests.Load(), "expected every lookup to be retried against the registry")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_keyIncludesNameAndVersion(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"license": %q}`, r.URL.Path)
|
||||||
|
})
|
||||||
|
|
||||||
|
lr := newJavascriptLicenseResolver(stub.config())
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{name: "lodash", version: "4.17.21", expected: "/lodash/4.17.21"},
|
||||||
|
{name: "lodash", version: "4.17.20", expected: "/lodash/4.17.20"},
|
||||||
|
{name: "@babel/code-frame", version: "7.10.4", expected: "/@babel/code-frame/7.10.4"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
license, err := lr.getLicensesFromRemote(tt.name, tt.version)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.expected, license)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(len(tests)), stub.requests.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavascriptLicenseResolver_getLicenses(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
searchRemote bool
|
||||||
|
response string
|
||||||
|
expected pkg.LicenseSet
|
||||||
|
expectedRequests int64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "remote search disabled makes no request",
|
||||||
|
searchRemote: false,
|
||||||
|
response: `{"license": "MIT"}`,
|
||||||
|
expected: pkg.LicenseSet{},
|
||||||
|
expectedRequests: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remote search returns the license from the registry",
|
||||||
|
searchRemote: true,
|
||||||
|
response: `{"license": "MIT"}`,
|
||||||
|
expected: pkg.NewLicenseSet(pkg.NewLicenseWithContext(ctx, "MIT")),
|
||||||
|
expectedRequests: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "an empty license yields an empty license set",
|
||||||
|
searchRemote: true,
|
||||||
|
response: `{"name": "no-license-pkg"}`,
|
||||||
|
expected: pkg.LicenseSet{},
|
||||||
|
expectedRequests: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
useInMemoryCache(t)
|
||||||
|
|
||||||
|
stub := newNpmRegistryStub(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprint(w, tt.response)
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg := stub.config()
|
||||||
|
cfg.SearchRemoteLicenses = tt.searchRemote
|
||||||
|
lr := newJavascriptLicenseResolver(cfg)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.expected, lr.getLicenses(ctx, "some-pkg", "1.0.0"))
|
||||||
|
assert.Equal(t, tt.expectedRequests, stub.requests.Load())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,7 +85,7 @@ func newPackageJSONPackage(ctx context.Context, resolver file.Resolver, u packag
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackageLockV1Package(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
func newPackageLockV1Package(ctx context.Context, licenseResolver javascriptLicenseResolver, resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
||||||
version := u.Version
|
version := u.Version
|
||||||
|
|
||||||
const aliasPrefixPackageLockV1 = "npm:"
|
const aliasPrefixPackageLockV1 = "npm:"
|
||||||
@@ -101,17 +101,7 @@ func newPackageLockV1Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
version = canonicalPackageAndVersion[versionSeparator+1:]
|
version = canonicalPackageAndVersion[versionSeparator+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
var licenseSet pkg.LicenseSet
|
licenseSet := licenseResolver.getLicenses(ctx, name, version)
|
||||||
|
|
||||||
if cfg.SearchRemoteLicenses {
|
|
||||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
|
||||||
if err == nil && license != "" {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -130,19 +120,13 @@ func newPackageLockV1Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackageLockV2Package(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
func newPackageLockV2Package(ctx context.Context, licenseResolver javascriptLicenseResolver, resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
||||||
var licenseSet pkg.LicenseSet
|
var licenseSet pkg.LicenseSet
|
||||||
|
|
||||||
if u.License != nil {
|
if u.License != nil {
|
||||||
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocationWithContext(ctx, location, u.License...)...)
|
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocationWithContext(ctx, location, u.License...)...)
|
||||||
} else if cfg.SearchRemoteLicenses {
|
} else {
|
||||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, u.Version)
|
licenseSet = licenseResolver.getLicenses(ctx, name, u.Version)
|
||||||
if err == nil && license != "" {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
@@ -162,18 +146,9 @@ func newPackageLockV2Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPnpmPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string, integrity string, dependencies map[string]string) pkg.Package {
|
func newPnpmPackage(ctx context.Context, licenseResolver javascriptLicenseResolver, resolver file.Resolver, location file.Location, name, version string, integrity string, dependencies map[string]string) pkg.Package {
|
||||||
var licenseSet pkg.LicenseSet
|
licenseSet := licenseResolver.getLicenses(ctx, name, version)
|
||||||
|
|
||||||
if cfg.SearchRemoteLicenses {
|
|
||||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
|
||||||
if err == nil && license != "" {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
ctx,
|
ctx,
|
||||||
resolver,
|
resolver,
|
||||||
@@ -191,18 +166,9 @@ func newPnpmPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Reso
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newYarnLockPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string, resolved string, integrity string, dependencies map[string]string) pkg.Package {
|
func newYarnLockPackage(ctx context.Context, licenseResolver javascriptLicenseResolver, resolver file.Resolver, location file.Location, name, version string, resolved string, integrity string, dependencies map[string]string) pkg.Package {
|
||||||
var licenseSet pkg.LicenseSet
|
licenseSet := licenseResolver.getLicenses(ctx, name, version)
|
||||||
|
|
||||||
if cfg.SearchRemoteLicenses {
|
|
||||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
|
||||||
if err == nil && license != "" {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
ctx,
|
ctx,
|
||||||
resolver,
|
resolver,
|
||||||
@@ -220,18 +186,9 @@ func newYarnLockPackage(ctx context.Context, cfg CatalogerConfig, resolver file.
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBunPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string, integrity string, metadata bunPackageMetadata) pkg.Package {
|
func newBunPackage(ctx context.Context, licenseResolver javascriptLicenseResolver, resolver file.Resolver, location file.Location, name, version string, integrity string, metadata bunPackageMetadata) pkg.Package {
|
||||||
var licenseSet pkg.LicenseSet
|
licenseSet := licenseResolver.getLicenses(ctx, name, version)
|
||||||
|
|
||||||
if cfg.SearchRemoteLicenses {
|
|
||||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
|
||||||
if err == nil && license != "" {
|
|
||||||
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, license)...)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("unable to extract licenses from javascript bun.lock for package %s:%s: %+v", name, version, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
ctx,
|
ctx,
|
||||||
resolver,
|
resolver,
|
||||||
|
|||||||
@@ -53,12 +53,14 @@ type bunWorkspace struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type genericBunLockAdapter struct {
|
type genericBunLockAdapter struct {
|
||||||
cfg CatalogerConfig
|
cfg CatalogerConfig
|
||||||
|
licenseResolver javascriptLicenseResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGenericBunLockAdapter(cfg CatalogerConfig) genericBunLockAdapter {
|
func newGenericBunLockAdapter(cfg CatalogerConfig) genericBunLockAdapter {
|
||||||
return genericBunLockAdapter{
|
return genericBunLockAdapter{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
licenseResolver: newJavascriptLicenseResolver(cfg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ func (a genericBunLockAdapter) parseBunLock(ctx context.Context, resolver file.R
|
|||||||
if devOnlyPkgs[p.Name] && !a.cfg.IncludeDevDependencies {
|
if devOnlyPkgs[p.Name] && !a.cfg.IncludeDevDependencies {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
packages = append(packages, newBunPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Metadata))
|
packages = append(packages, newBunPackage(ctx, a.licenseResolver, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg.Sort(packages)
|
pkg.Sort(packages)
|
||||||
|
|||||||
@@ -48,12 +48,14 @@ type lockPackage struct {
|
|||||||
type packageLockLicense []string
|
type packageLockLicense []string
|
||||||
|
|
||||||
type genericPackageLockAdapter struct {
|
type genericPackageLockAdapter struct {
|
||||||
cfg CatalogerConfig
|
cfg CatalogerConfig
|
||||||
|
licenseResolver javascriptLicenseResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGenericPackageLockAdapter(cfg CatalogerConfig) genericPackageLockAdapter {
|
func newGenericPackageLockAdapter(cfg CatalogerConfig) genericPackageLockAdapter {
|
||||||
return genericPackageLockAdapter{
|
return genericPackageLockAdapter{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
licenseResolver: newJavascriptLicenseResolver(cfg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +102,7 @@ func (a genericPackageLockAdapter) parsePackageLock(ctx context.Context, resolve
|
|||||||
name = pkgMeta.Name
|
name = pkgMeta.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
newPkg := newPackageLockV2Package(ctx, a.cfg, resolver, reader.Location, getNameFromPath(name), pkgMeta)
|
newPkg := newPackageLockV2Package(ctx, a.licenseResolver, resolver, reader.Location, getNameFromPath(name), pkgMeta)
|
||||||
pkgs = append(pkgs, newPkg)
|
pkgs = append(pkgs, newPkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +124,7 @@ func (a genericPackageLockAdapter) packageLockV1Packages(ctx context.Context, re
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
p := newPackageLockV1Package(ctx, a.cfg, resolver, location, name, pkgMeta)
|
p := newPackageLockV1Package(ctx, a.licenseResolver, resolver, location, name, pkgMeta)
|
||||||
if _, exists := seen[p.PURL]; !exists {
|
if _, exists := seen[p.PURL]; !exists {
|
||||||
pkgs = append(pkgs, p)
|
pkgs = append(pkgs, p)
|
||||||
seen[p.PURL] = struct{}{}
|
seen[p.PURL] = struct{}{}
|
||||||
|
|||||||
@@ -74,12 +74,14 @@ type pnpmV9LockYaml struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type genericPnpmLockAdapter struct {
|
type genericPnpmLockAdapter struct {
|
||||||
cfg CatalogerConfig
|
cfg CatalogerConfig
|
||||||
|
licenseResolver javascriptLicenseResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGenericPnpmLockAdapter(cfg CatalogerConfig) genericPnpmLockAdapter {
|
func newGenericPnpmLockAdapter(cfg CatalogerConfig) genericPnpmLockAdapter {
|
||||||
return genericPnpmLockAdapter{
|
return genericPnpmLockAdapter{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
licenseResolver: newJavascriptLicenseResolver(cfg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +218,7 @@ func (a genericPnpmLockAdapter) parsePnpmLock(ctx context.Context, resolver file
|
|||||||
if p.Dev && !a.cfg.IncludeDevDependencies {
|
if p.Dev && !a.cfg.IncludeDevDependencies {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
packages = append(packages, newPnpmPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Dependencies))
|
packages = append(packages, newPnpmPackage(ctx, a.licenseResolver, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Dependencies))
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = unknown.Join(errs, unknown.IfEmptyf(packages, "unable to determine packages"))
|
errs = unknown.Join(errs, unknown.IfEmptyf(packages, "unable to determine packages"))
|
||||||
|
|||||||
@@ -67,12 +67,14 @@ type yarnV2PackageEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type genericYarnLockAdapter struct {
|
type genericYarnLockAdapter struct {
|
||||||
cfg CatalogerConfig
|
cfg CatalogerConfig
|
||||||
|
licenseResolver javascriptLicenseResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGenericYarnLockAdapter(cfg CatalogerConfig) genericYarnLockAdapter {
|
func newGenericYarnLockAdapter(cfg CatalogerConfig) genericYarnLockAdapter {
|
||||||
return genericYarnLockAdapter{
|
return genericYarnLockAdapter{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
licenseResolver: newJavascriptLicenseResolver(cfg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +309,7 @@ func (a genericYarnLockAdapter) parseYarnLock(ctx context.Context, resolver file
|
|||||||
if devOnlyPkgs[p.Name] && !a.cfg.IncludeDevDependencies {
|
if devOnlyPkgs[p.Name] && !a.cfg.IncludeDevDependencies {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
packages = append(packages, newYarnLockPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version, p.Resolved, p.Integrity, p.Dependencies))
|
packages = append(packages, newYarnLockPackage(ctx, a.licenseResolver, resolver, reader.Location, p.Name, p.Version, p.Resolved, p.Integrity, p.Dependencies))
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg.Sort(packages)
|
pkg.Sort(packages)
|
||||||
|
|||||||
Reference in New Issue
Block a user