diff --git a/docs/docs/coverage/language/nodejs.md b/docs/docs/coverage/language/nodejs.md index ded9ea144535..623f54d0ca6c 100644 --- a/docs/docs/coverage/language/nodejs.md +++ b/docs/docs/coverage/language/nodejs.md @@ -8,7 +8,7 @@ The following scanners are supported. |----------|:----:|:-------------:|:-------:| | npm | ✓ | ✓ | ✓ | | Yarn | ✓ | ✓ | ✓ | -| pnpm | ✓ | ✓ | - | +| pnpm | ✓ | ✓ | ✓ | | Bun | ✓ | ✓ | ✓ | The following table provides an outline of the features Trivy offers. @@ -54,6 +54,7 @@ By default, Trivy doesn't report development dependencies. Use the `--include-de ### pnpm Trivy parses `pnpm-lock.yaml`, then finds production dependencies and builds a [tree][dependency-graph] of dependencies with vulnerabilities. +To identify licenses, you need to download dependencies to `node_modules` beforehand. Trivy analyzes `node_modules` for licenses. #### lock file v9 version Trivy supports `Dev` field for `pnpm-lock.yaml` v9 or later. Use the `--include-dev-deps` flag to include the developer's dependencies in the result. diff --git a/integration/repo_test.go b/integration/repo_test.go index e07b48b950b7..b95b4f4f461d 100644 --- a/integration/repo_test.go +++ b/integration/repo_test.go @@ -105,8 +105,9 @@ func TestRepository(t *testing.T) { { name: "pnpm", args: args{ - scanner: types.VulnerabilityScanner, - input: "testdata/fixtures/repo/pnpm", + scanner: types.VulnerabilityScanner, + input: "testdata/fixtures/repo/pnpm", + listAllPkgs: true, }, golden: "testdata/pnpm.json.golden", }, diff --git a/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/jquery@3.3.9/node_modules/jquery/package.json b/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/jquery@3.3.9/node_modules/jquery/package.json new file mode 100644 index 000000000000..54dd7c03a0bd --- /dev/null +++ b/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/jquery@3.3.9/node_modules/jquery/package.json @@ -0,0 +1,108 @@ +{ + "name": "jquery", + "title": "jQuery", + "description": "JavaScript library for DOM operations", + "version": "3.3.9", + "main": "dist/jquery.js", + "homepage": "https://jquery.com", + "author": { + "name": "JS Foundation and other contributors", + "url": "https://github.com/jquery/jquery/blob/3.3.1/AUTHORS.txt" + }, + "repository": { + "type": "git", + "url": "https://github.com/jquery/jquery.git" + }, + "keywords": [ + "jquery", + "javascript", + "browser", + "library" + ], + "bugs": { + "url": "https://github.com/jquery/jquery/issues" + }, + "license": "MIT", + "dependencies": {}, + "devDependencies": { + "babel-core": "7.0.0-beta.0", + "babel-plugin-transform-es2015-for-of": "7.0.0-beta.0", + "commitplease": "2.7.10", + "core-js": "2.4.1", + "eslint-config-jquery": "1.0.1", + "grunt": "1.0.1", + "grunt-babel": "7.0.0", + "grunt-cli": "1.2.0", + "grunt-compare-size": "0.4.2", + "grunt-contrib-uglify": "3.0.1", + "grunt-contrib-watch": "1.0.0", + "grunt-eslint": "20.0.0", + "grunt-git-authors": "3.2.0", + "grunt-jsonlint": "1.1.0", + "grunt-karma": "2.0.0", + "grunt-newer": "1.3.0", + "grunt-npmcopy": "0.1.0", + "gzip-js": "0.3.2", + "husky": "0.14.3", + "insight": "0.8.4", + "jsdom": "5.6.1", + "karma": "1.7.0", + "karma-browserstack-launcher": "1.3.0", + "karma-chrome-launcher": "2.2.0", + "karma-firefox-launcher": "1.0.1", + "karma-qunit": "1.2.1", + "load-grunt-tasks": "3.5.2", + "native-promise-only": "0.8.1", + "promises-aplus-tests": "2.1.2", + "q": "1.5.0", + "qunit-assert-step": "1.0.3", + "qunitjs": "1.23.1", + "raw-body": "2.2.0", + "requirejs": "2.3.3", + "sinon": "2.3.7", + "sizzle": "2.3.3", + "strip-json-comments": "2.0.1", + "testswarm": "1.1.0", + "uglify-js": "3.3.4" + }, + "scripts": { + "build": "npm install && grunt", + "start": "grunt watch", + "test:browserless": "grunt && grunt test:slow", + "test:browser": "grunt && grunt karma:main", + "test": "grunt && grunt test:slow && grunt karma:main", + "jenkins": "npm run test:browserless", + "precommit": "grunt lint:newer qunit_fixture", + "commitmsg": "node node_modules/commitplease" + }, + "commitplease": { + "nohook": true, + "components": [ + "Docs", + "Tests", + "Build", + "Support", + "Release", + "Core", + "Ajax", + "Attributes", + "Callbacks", + "CSS", + "Data", + "Deferred", + "Deprecated", + "Dimensions", + "Effects", + "Event", + "Manipulation", + "Offset", + "Queue", + "Selector", + "Serialize", + "Traversing", + "Wrap" + ], + "markerPattern": "^((clos|fix|resolv)(e[sd]|ing))|^(refs?)", + "ticketPattern": "^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])" + } +} \ No newline at end of file diff --git a/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/lodash@4.17.4/node_modules/lodash/package.json b/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/lodash@4.17.4/node_modules/lodash/package.json new file mode 100644 index 000000000000..3fa8669cb337 --- /dev/null +++ b/integration/testdata/fixtures/repo/pnpm/node_modules/.pnpm/lodash@4.17.4/node_modules/lodash/package.json @@ -0,0 +1,17 @@ +{ + "name": "lodash", + "version": "4.17.4", + "description": "Lodash modular utilities.", + "keywords": "modules, stdlib, util", + "homepage": "https://lodash.com/", + "repository": "lodash/lodash", + "icon": "https://lodash.com/icon.svg", + "license": "MIT", + "main": "lodash.js", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Mathias Bynens (https://mathiasbynens.be/)" + ], + "scripts": { "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" } +} \ No newline at end of file diff --git a/integration/testdata/fixtures/repo/pnpm/pnpm-lock.yaml b/integration/testdata/fixtures/repo/pnpm/pnpm-lock.yaml index be652ed3a442..f2b129bc448d 100644 --- a/integration/testdata/fixtures/repo/pnpm/pnpm-lock.yaml +++ b/integration/testdata/fixtures/repo/pnpm/pnpm-lock.yaml @@ -1,19 +1,23 @@ -lockfileVersion: 5.4 +lockfileVersion: '6.0' -specifiers: - jquery: 3.3.9 - lodash: 4.17.4 +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false dependencies: - jquery: 3.3.9 - lodash: 4.17.4 + jquery: + specifier: ^3.3.9 + version: 3.3.9 + lodash: + specifier: ^4.17.4 + version: 4.17.4 packages: - /jquery/3.3.9: + /jquery@3.3.9: resolution: {integrity: sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ==} dev: false - /lodash/4.17.4: + /lodash@4.17.4: resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=} dev: false diff --git a/integration/testdata/pnpm.json.golden b/integration/testdata/pnpm.json.golden index 1ae0c6400db0..3edd379d10cb 100644 --- a/integration/testdata/pnpm.json.golden +++ b/integration/testdata/pnpm.json.golden @@ -20,6 +20,36 @@ "Target": "pnpm-lock.yaml", "Class": "lang-pkgs", "Type": "pnpm", + "Packages": [ + { + "ID": "jquery@3.3.9", + "Name": "jquery", + "Identifier": { + "PURL": "pkg:npm/jquery@3.3.9", + "UID": "53ca18565a4b6a47" + }, + "Version": "3.3.9", + "Licenses": [ + "MIT" + ], + "Relationship": "direct", + "Layer": {} + }, + { + "ID": "lodash@4.17.4", + "Name": "lodash", + "Identifier": { + "PURL": "pkg:npm/lodash@4.17.4", + "UID": "31eadfcf58a6b128" + }, + "Version": "4.17.4", + "Licenses": [ + "MIT" + ], + "Relationship": "direct", + "Layer": {} + } + ], "Vulnerabilities": [ { "VulnerabilityID": "CVE-2019-11358", @@ -27,7 +57,7 @@ "PkgName": "jquery", "PkgIdentifier": { "PURL": "pkg:npm/jquery@3.3.9", - "UID": "d002d4ebac4ee286" + "UID": "53ca18565a4b6a47" }, "InstalledVersion": "3.3.9", "FixedVersion": "3.4.0", @@ -160,7 +190,7 @@ "PkgName": "lodash", "PkgIdentifier": { "PURL": "pkg:npm/lodash@4.17.4", - "UID": "68507e8301071074" + "UID": "31eadfcf58a6b128" }, "InstalledVersion": "4.17.4", "FixedVersion": "4.17.12", diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go index 594e5e02a82e..9c8f51a38265 100644 --- a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go @@ -2,45 +2,141 @@ package pnpm import ( "context" + "errors" + "io" + "io/fs" "os" + "path" "path/filepath" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/packagejson" "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/pnpm" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" - "github.com/aquasecurity/trivy/pkg/fanal/utils" + "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/utils/fsutils" + xpath "github.com/aquasecurity/trivy/pkg/x/path" ) func init() { - analyzer.RegisterAnalyzer(&pnpmLibraryAnalyzer{}) + analyzer.RegisterPostAnalyzer(analyzer.TypePnpm, newPnpmAnalyzer) } -const version = 1 +const version = 2 -var requiredFiles = []string{types.PnpmLock} +type pnpmAnalyzer struct { + logger *log.Logger + packageJsonParser *packagejson.Parser + lockParser language.Parser +} + +func newPnpmAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { + return &pnpmAnalyzer{ + logger: log.WithPrefix("pnpm"), + packageJsonParser: packagejson.NewParser(), + lockParser: pnpm.NewParser(), + }, nil +} + +func (a pnpmAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) { + var apps []types.Application + + required := func(path string, d fs.DirEntry) bool { + return filepath.Base(path) == types.PnpmLock + } -type pnpmLibraryAnalyzer struct{} + err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { + // Find licenses + licenses, err := a.findLicenses(input.FS, filePath) + if err != nil { + a.logger.Error("Unable to collect licenses", log.Err(err)) + licenses = make(map[string][]string) + } -func (a pnpmLibraryAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { - res, err := language.Analyze(types.Pnpm, input.FilePath, input.Content, pnpm.NewParser()) + // Parse pnpm-lock.yaml + app, err := language.Parse(types.Pnpm, filePath, r, a.lockParser) + if err != nil { + return xerrors.Errorf("parse error: %w", err) + } else if app == nil { + return nil + } + + // Fill licenses + for i, lib := range app.Packages { + if l, ok := licenses[lib.ID]; ok { + app.Packages[i].Licenses = l + } + } + + apps = append(apps, *app) + + return nil + }) if err != nil { - return nil, xerrors.Errorf("unable to parse %s: %w", input.FilePath, err) + return nil, xerrors.Errorf("pnpm walk error: %w", err) } - return res, nil + + return &analyzer.AnalysisResult{ + Applications: apps, + }, nil } -func (a pnpmLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool { +func (a pnpmAnalyzer) Required(filePath string, _ os.FileInfo) bool { fileName := filepath.Base(filePath) - return utils.StringInSlice(fileName, requiredFiles) + // Don't save pnpm-lock.yaml from the `node_modules` directory to avoid duplication and mistakes. + if fileName == types.PnpmLock && !xpath.Contains(filePath, "node_modules") { + return true + } + + // Save package.json files only from the `node_modules` directory. + // Required to search for licenses. + if fileName == types.NpmPkg && xpath.Contains(filePath, "node_modules") { + return true + } + + return false } -func (a pnpmLibraryAnalyzer) Type() analyzer.Type { +func (a pnpmAnalyzer) Type() analyzer.Type { return analyzer.TypePnpm } -func (a pnpmLibraryAnalyzer) Version() int { +func (a pnpmAnalyzer) Version() int { return version } + +func (a pnpmAnalyzer) findLicenses(fsys fs.FS, lockPath string) (map[string][]string, error) { + dir := path.Dir(lockPath) + root := path.Join(dir, "node_modules") + if _, err := fs.Stat(fsys, root); errors.Is(err, fs.ErrNotExist) { + a.logger.Info(`To collect the license information of packages, "pnpm install" needs to be performed beforehand`, + log.String("dir", root)) + return nil, nil + } + + // Parse package.json + required := func(path string, _ fs.DirEntry) bool { + return filepath.Base(path) == types.NpmPkg + } + + // Traverse node_modules dir and find licenses + // Note that fs.FS is always slashed regardless of the platform, + // and path.Join should be used rather than filepath.Join. + licenses := make(map[string][]string) + err := fsutils.WalkDir(fsys, root, required, func(filePath string, d fs.DirEntry, r io.Reader) error { + pkg, err := a.packageJsonParser.Parse(r) + if err != nil { + return xerrors.Errorf("unable to parse %q: %w", filePath, err) + } + + licenses[pkg.ID] = pkg.Licenses + return nil + }) + if err != nil { + return nil, xerrors.Errorf("walk error: %w", err) + } + return licenses, nil +} diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go index 4fe9fd75874e..b0623b3f609e 100644 --- a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go @@ -3,6 +3,7 @@ package pnpm import ( "context" "os" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -14,24 +15,24 @@ import ( func Test_pnpmPkgLibraryAnalyzer_Analyze(t *testing.T) { tests := []struct { - name string - inputFile string - want *analyzer.AnalysisResult - wantErr string + name string + dir string + want *analyzer.AnalysisResult }{ { - name: "happy path", - inputFile: "testdata/pnpm-lock.yaml", + name: "with node_modules", + dir: "testdata/happy", want: &analyzer.AnalysisResult{ Applications: []types.Application{ { Type: types.Pnpm, - FilePath: "testdata/pnpm-lock.yaml", + FilePath: "pnpm-lock.yaml", Packages: types.Packages{ { - ID: "lodash@4.17.21", - Name: "lodash", - Version: "4.17.21", + ID: "ms@2.1.3", + Name: "ms", + Version: "2.1.3", + Licenses: []string{"MIT"}, Relationship: types.RelationshipDirect, }, }, @@ -39,27 +40,123 @@ func Test_pnpmPkgLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, + { + name: "without node_modules", + dir: "testdata/no-node_modules", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.Pnpm, + FilePath: "pnpm-lock.yaml", + Packages: types.Packages{ + { + ID: "@babel/parser@7.24.7", + Name: "@babel/parser", + Version: "7.24.7", + Relationship: types.RelationshipDirect, + DependsOn: []string{"@babel/types@7.24.7"}, + }, + { + ID: "ms@2.1.3", + Name: "ms", + Version: "2.1.3", + Relationship: types.RelationshipDirect, + }, + { + ID: "@babel/helper-string-parser@7.24.7", + Name: "@babel/helper-string-parser", + Version: "7.24.7", + Relationship: types.RelationshipIndirect, + Indirect: true, + }, + { + ID: "@babel/helper-validator-identifier@7.24.7", + Name: "@babel/helper-validator-identifier", + Version: "7.24.7", + Relationship: types.RelationshipIndirect, + Indirect: true, + }, + { + ID: "@babel/types@7.24.7", + Name: "@babel/types", + Version: "7.24.7", + Relationship: types.RelationshipIndirect, + Indirect: true, + DependsOn: []string{ + "@babel/helper-string-parser@7.24.7", + "@babel/helper-validator-identifier@7.24.7", + "to-fast-properties@2.0.0", + }, + }, + { + ID: "to-fast-properties@2.0.0", + Name: "to-fast-properties", + Version: "2.0.0", + Relationship: types.RelationshipIndirect, + Indirect: true, + }, + }, + }, + }, + }, + }, + { + name: "sad path", + dir: "testdata/sad", + want: &analyzer.AnalysisResult{}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f, err := os.Open(tt.inputFile) + a, err := newPnpmAnalyzer(analyzer.AnalyzerOptions{}) require.NoError(t, err) - defer f.Close() - a := pnpmLibraryAnalyzer{} - ctx := context.Background() - got, err := a.Analyze(ctx, analyzer.AnalysisInput{ - FilePath: tt.inputFile, - Content: f, + got, err := a.PostAnalyze(context.Background(), analyzer.PostAnalysisInput{ + FS: os.DirFS(tt.dir), }) - if tt.wantErr != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.wantErr) - return + require.NoError(t, err) + if len(got.Applications) > 0 { + sort.Sort(got.Applications[0].Packages) } + assert.Equal(t, tt.want, got) + }) + } +} +func Test_pnpmPkgLibraryAnalyzer_Required(t *testing.T) { + tests := []struct { + name string + filePath string + want bool + }{ + { + name: "lock file", + filePath: "pnpm/pnpm-lock.yaml", + want: true, + }, + { + name: "lock file in node_modules", + filePath: "pnpm/node_modules/html2canvas/pnpm-lock.yaml", + want: false, + }, + { + name: "package.json in node_modules", + filePath: "pnpm/node_modules/ms/package.json", + want: true, + }, + { + name: "sad path", + filePath: "pnpm/package.json", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a, err := newPnpmAnalyzer(analyzer.AnalyzerOptions{}) require.NoError(t, err) + + got := a.Required(tt.filePath, nil) assert.Equal(t, tt.want, got) }) } diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/node_modules/.pnpm/ms@2.1.3/node_modules/ms/package.json b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/node_modules/.pnpm/ms@2.1.3/node_modules/ms/package.json new file mode 100644 index 000000000000..49971890df8e --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/node_modules/.pnpm/ms@2.1.3/node_modules/ms/package.json @@ -0,0 +1,38 @@ +{ + "name": "ms", + "version": "2.1.3", + "description": "Tiny millisecond conversion utility", + "repository": "vercel/ms", + "main": "./index", + "files": [ + "index.js" + ], + "scripts": { + "precommit": "lint-staged", + "lint": "eslint lib/* bin/*", + "test": "mocha tests.js" + }, + "eslintConfig": { + "extends": "eslint:recommended", + "env": { + "node": true, + "es6": true + } + }, + "lint-staged": { + "*.js": [ + "npm run lint", + "prettier --single-quote --write", + "git add" + ] + }, + "license": "MIT", + "devDependencies": { + "eslint": "4.18.2", + "expect.js": "0.3.1", + "husky": "0.14.3", + "lint-staged": "5.0.0", + "mocha": "4.0.1", + "prettier": "2.0.5" + } +} diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/pnpm-lock.yaml b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/pnpm-lock.yaml new file mode 100644 index 000000000000..50dfa1c43db3 --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/happy/pnpm-lock.yaml @@ -0,0 +1,16 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + ms: + specifier: ^2.1.3 + version: 2.1.3 + +packages: + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/no-node_modules/pnpm-lock.yaml b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/no-node_modules/pnpm-lock.yaml new file mode 100644 index 000000000000..31997b0756cf --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/no-node_modules/pnpm-lock.yaml @@ -0,0 +1,51 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@babel/parser': + specifier: ^7.24.7 + version: 7.24.7 + ms: + specifier: ^2.1.3 + version: 2.1.3 + +packages: + + /@babel/helper-string-parser@7.24.7: + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/parser@7.24.7: + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.7 + dev: false + + /@babel/types@7.24.7: + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + dev: false + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: false diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml deleted file mode 100644 index a319ff8e7d4f..000000000000 --- a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml +++ /dev/null @@ -1,13 +0,0 @@ -lockfileVersion: 5.4 - -specifiers: - lodash: ^4.17.21 - -dependencies: - lodash: 4.17.21 - -packages: - - /lodash/4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false \ No newline at end of file diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/sad/pnpm-lock.yaml b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/sad/pnpm-lock.yaml new file mode 100644 index 000000000000..80c4ed2eb6fa --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/sad/pnpm-lock.yaml @@ -0,0 +1 @@ +{broken} \ No newline at end of file