feat(nodejs): parse package.json files alongside package-lock.json (#2916)

Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
DmitriyLewen
2023-03-16 01:54:01 +06:00
committed by GitHub
parent d6a2d6369a
commit 52cbfebcdd
21 changed files with 917 additions and 121 deletions

View File

@@ -65,13 +65,13 @@ func TestFilesystem(t *testing.T) {
golden: "testdata/gomod-skip.json.golden",
},
{
name: "nodejs",
name: "npm",
args: args{
scanner: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/nodejs",
input: "testdata/fixtures/fs/npm",
listAllPkgs: true,
},
golden: "testdata/nodejs.json.golden",
golden: "testdata/npm.json.golden",
},
{
name: "yarn",

View File

@@ -0,0 +1,113 @@
{
"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.4.0/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.3.3",
"@babel/plugin-transform-for-of": "7.2.0",
"commitplease": "3.2.0",
"core-js": "2.6.5",
"eslint-config-jquery": "1.0.1",
"grunt": "1.0.3",
"grunt-babel": "8.0.0",
"grunt-cli": "1.3.2",
"grunt-compare-size": "0.4.2",
"grunt-contrib-uglify": "3.4.0",
"grunt-contrib-watch": "1.1.0",
"grunt-eslint": "21.0.0",
"grunt-git-authors": "3.2.0",
"grunt-jsonlint": "1.1.0",
"grunt-karma": "3.0.1",
"grunt-newer": "1.3.0",
"grunt-npmcopy": "0.1.0",
"gzip-js": "0.3.2",
"husky": "1.3.1",
"insight": "0.10.1",
"jsdom": "13.2.0",
"karma": "4.0.1",
"karma-browserstack-launcher": "1.4.0",
"karma-chrome-launcher": "2.2.0",
"karma-firefox-launcher": "1.1.0",
"karma-ie-launcher": "1.0.0",
"karma-jsdom-launcher": "7.1.0",
"karma-qunit": "3.0.0",
"load-grunt-tasks": "4.0.0",
"native-promise-only": "0.8.1",
"promises-aplus-tests": "2.1.2",
"q": "1.5.1",
"qunit": "2.9.2",
"raw-body": "2.3.3",
"requirejs": "2.3.6",
"sinon": "2.3.7",
"sizzle": "2.3.4",
"strip-json-comments": "2.0.1",
"testswarm": "1.1.0",
"uglify-js": "3.4.7"
},
"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"
},
"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? [^#])"
},
"husky": {
"hooks": {
"commit-msg": "node node_modules/commitplease",
"pre-commit": "grunt lint:newer qunit_fixture"
}
}
}

View File

@@ -0,0 +1,35 @@
{
"name": "promise",
"version": "8.0.3",
"description": "Bare bones Promises/A+ implementation",
"main": "index.js",
"scripts": {
"prepublish": "node build",
"pretest": "node build",
"pretest-resolve": "node build",
"pretest-extensions": "node build",
"pretest-memory-leak": "node build",
"test": "mocha --bail --timeout 200 --slow 99999 -R dot && npm run test-memory-leak",
"test-resolve": "mocha test/resolver-tests.js --timeout 200 --slow 999999",
"test-extensions": "mocha test/extensions-tests.js --timeout 200 --slow 999999",
"test-memory-leak": "node --expose-gc test/memory-leak.js",
"coverage": "istanbul cover node_modules/mocha/bin/_mocha -- --bail --timeout 200 --slow 99999 -R dot"
},
"repository": {
"type": "git",
"url": "https://github.com/then/promise.git"
},
"author": "ForbesLindesay",
"license": "MIT",
"devDependencies": {
"acorn": "^1.0.1",
"better-assert": "*",
"istanbul": "^0.3.13",
"mocha": "*",
"promises-aplus-tests": "*",
"rimraf": "^2.3.2"
},
"dependencies": {
"asap": "~2.0.6"
}
}

View File

@@ -0,0 +1,27 @@
{
"name": "react-is",
"version": "16.8.6",
"description": "Brand checking of React Elements.",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react-is"
},
"keywords": [
"react"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/facebook/react/issues"
},
"homepage": "https://reactjs.org/",
"files": [
"LICENSE",
"README.md",
"build-info.json",
"index.js",
"cjs/",
"umd/"
]
}

View File

@@ -0,0 +1,39 @@
{
"name": "react",
"description": "React is a JavaScript library for building user interfaces.",
"keywords": [
"react"
],
"version": "16.8.6",
"homepage": "https://reactjs.org/",
"bugs": "https://github.com/facebook/react/issues",
"license": "MIT",
"files": [
"LICENSE",
"README.md",
"build-info.json",
"index.js",
"cjs/",
"umd/"
],
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react"
},
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.13.6"
},
"browserify": {
"transform": [
"loose-envify"
]
}
}

View File

@@ -0,0 +1,105 @@
{
"name": "redux",
"version": "4.0.1",
"description": "Predictable state container for JavaScript apps",
"license": "MIT",
"homepage": "http://redux.js.org",
"repository": "github:reduxjs/redux",
"bugs": "https://github.com/reduxjs/redux/issues",
"keywords": [
"redux",
"reducer",
"state",
"predictable",
"functional",
"immutable",
"hot",
"live",
"replay",
"flux",
"elm"
],
"authors": [
"Dan Abramov <dan.abramov@me.com> (https://github.com/gaearon)",
"Andrew Clark <acdlite@me.com> (https://github.com/acdlite)"
],
"main": "lib/redux.js",
"unpkg": "dist/redux.js",
"module": "es/redux.js",
"typings": "./index.d.ts",
"files": [
"dist",
"lib",
"es",
"src",
"index.d.ts"
],
"scripts": {
"clean": "rimraf lib dist es coverage",
"format": "prettier --write \"{src,test}/**/*.{js,ts}\" index.d.ts",
"format:check": "prettier --list-different \"{src,test}/**/*.{js,ts}\" index.d.ts",
"lint": "eslint src test",
"pretest": "npm run build",
"test": "jest",
"test:watch": "npm test -- --watch",
"test:cov": "npm test -- --coverage",
"build": "rollup -c",
"prepare": "npm run clean && npm run format:check && npm run lint && npm test",
"examples:lint": "eslint examples",
"examples:test": "cross-env CI=true babel-node examples/testAll.js"
},
"dependencies": {
"loose-envify": "^1.4.0",
"symbol-observable": "^1.2.0"
},
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/node": "^7.0.0",
"@babel/plugin-external-helpers": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-flow": "^7.0.0",
"@babel/register": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^9.0.0",
"babel-jest": "^23.6.0",
"cross-env": "^5.2.0",
"eslint": "^5.6.0",
"eslint-config-react-app": "^2.1.0",
"eslint-plugin-flowtype": "^2.50.1",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-react": "^7.11.1",
"glob": "^7.1.3",
"jest": "^23.6.0",
"prettier": "^1.14.3",
"rimraf": "^2.6.2",
"rollup": "^0.66.2",
"rollup-plugin-babel": "^4.0.1",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-terser": "^3.0.0",
"rxjs": "^6.3.2",
"typescript": "^3.0.3",
"typings-tester": "^0.3.2"
},
"npmName": "redux",
"npmFileMap": [
{
"basePath": "/dist/",
"files": [
"*.js"
]
}
],
"browserify": {
"transform": [
"loose-envify"
]
},
"jest": {
"testRegex": "(/test/.*\\.spec.js)$"
},
"sideEffects": false
}

View File

@@ -8,11 +8,6 @@
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"jquery": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"SchemaVersion": 2,
"ArtifactName": "testdata/fixtures/fs/nodejs",
"ArtifactName": "testdata/fixtures/fs/npm",
"ArtifactType": "filesystem",
"Metadata": {
"ImageConfig": {
@@ -39,10 +39,13 @@
"Version": "3.3.9",
"Indirect": true,
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 16,
"EndLine": 20
"StartLine": 11,
"EndLine": 15
}
]
},
@@ -54,21 +57,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 21,
"EndLine": 25
}
]
},
{
"ID": "lodash@4.17.4",
"Name": "lodash",
"Version": "4.17.4",
"Indirect": true,
"Layer": {},
"Locations": [
{
"StartLine": 11,
"EndLine": 15
"StartLine": 16,
"EndLine": 20
}
]
},
@@ -83,8 +73,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 26,
"EndLine": 33
"StartLine": 21,
"EndLine": 28
}
]
},
@@ -96,8 +86,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 34,
"EndLine": 38
"StartLine": 29,
"EndLine": 33
}
]
},
@@ -110,10 +100,13 @@
"asap@2.0.6"
],
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 39,
"EndLine": 46
"StartLine": 34,
"EndLine": 41
}
]
},
@@ -130,8 +123,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 47,
"EndLine": 56
"StartLine": 42,
"EndLine": 51
}
]
},
@@ -147,10 +140,13 @@
"scheduler@0.13.6"
],
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 57,
"EndLine": 67
"StartLine": 52,
"EndLine": 62
}
]
},
@@ -160,10 +156,13 @@
"Version": "16.8.6",
"Indirect": true,
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 68,
"EndLine": 72
"StartLine": 63,
"EndLine": 67
}
]
},
@@ -177,10 +176,13 @@
"symbol-observable@1.2.0"
],
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 73,
"EndLine": 81
"StartLine": 68,
"EndLine": 76
}
]
},
@@ -196,8 +198,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 82,
"EndLine": 90
"StartLine": 77,
"EndLine": 85
}
]
},
@@ -209,8 +211,8 @@
"Layer": {},
"Locations": [
{
"StartLine": 91,
"EndLine": 95
"StartLine": 86,
"EndLine": 90
}
]
}
@@ -331,51 +333,6 @@
],
"PublishedDate": "2019-04-20T00:29:00Z",
"LastModifiedDate": "2021-10-20T11:15:00Z"
},
{
"VulnerabilityID": "CVE-2019-10744",
"PkgID": "lodash@4.17.4",
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "4.17.12",
"Layer": {},
"SeveritySource": "ghsa",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-10744",
"DataSource": {
"ID": "ghsa",
"Name": "GitHub Security Advisory Npm",
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm"
},
"Title": "nodejs-lodash: prototype pollution in defaultsDeep function leading to modifying properties",
"Description": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.",
"Severity": "CRITICAL",
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:L/Au:N/C:N/I:P/A:P",
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
"V2Score": 6.4,
"V3Score": 9.1
},
"redhat": {
"V3Vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
"V3Score": 9.1
}
},
"References": [
"https://access.redhat.com/errata/RHSA-2019:3024",
"https://access.redhat.com/security/cve/CVE-2019-10744",
"https://github.com/advisories/GHSA-jf85-cpcp-j695",
"https://github.com/lodash/lodash/pull/4336",
"https://nvd.nist.gov/vuln/detail/CVE-2019-10744",
"https://security.netapp.com/advisory/ntap-20191004-0005/",
"https://snyk.io/vuln/SNYK-JS-LODASH-450202",
"https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS",
"https://www.npmjs.com/advisories/1065",
"https://www.oracle.com/security-alerts/cpujan2021.html",
"https://www.oracle.com/security-alerts/cpuoct2020.html"
],
"PublishedDate": "2019-07-26T00:15:00Z",
"LastModifiedDate": "2021-03-16T13:57:00Z"
}
]
}

View File

@@ -2,40 +2,99 @@ package npm
import (
"context"
"errors"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
"golang.org/x/xerrors"
dio "github.com/aquasecurity/go-dep-parser/pkg/io"
"github.com/aquasecurity/go-dep-parser/pkg/nodejs/npm"
"github.com/aquasecurity/go-dep-parser/pkg/nodejs/packagejson"
godeptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"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"
)
func init() {
analyzer.RegisterAnalyzer(&npmLibraryAnalyzer{})
analyzer.RegisterPostAnalyzer(analyzer.TypeNpmPkgLock, newNpmLibraryAnalyzer)
}
const version = 1
const (
version = 1
)
var requiredFiles = []string{types.NpmPkgLock}
type npmLibraryAnalyzer struct {
lockParser godeptypes.Parser
packageParser godeptypes.Parser
}
type npmLibraryAnalyzer struct{}
func newNpmLibraryAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
return &npmLibraryAnalyzer{
lockParser: npm.NewParser(),
packageParser: packagejson.NewParser(),
}, nil
}
func (a npmLibraryAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
p := npm.NewParser()
res, err := language.Analyze(types.Npm, input.FilePath, input.Content, p)
if err != nil {
return nil, xerrors.Errorf("unable to parse %s: %w", input.FilePath, err)
func (a npmLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) {
// Parse package-lock.json
required := func(path string, _ fs.DirEntry) bool {
return filepath.Base(path) == types.NpmPkgLock
}
return res, nil
var apps []types.Application
err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r dio.ReadSeekerAt) error {
// Find all licenses from package.json files under node_modules dirs
licenses, err := a.findLicenses(input.FS, filePath)
if err != nil {
log.Logger.Errorf("Unable to collect licenses: %s", err)
licenses = map[string]string{}
}
app, err := a.parseNpmPkgLock(input.FS, filePath)
if err != nil {
return xerrors.Errorf("parse error: %w", err)
} else if app == nil {
return nil
}
// Fill licenses
for i, lib := range app.Libraries {
if license, ok := licenses[lib.ID]; ok {
app.Libraries[i].Licenses = []string{license}
}
}
apps = append(apps, *app)
return nil
})
if err != nil {
return nil, xerrors.Errorf("package-lock.json/package.json walk error: %w", err)
}
return &analyzer.AnalysisResult{
Applications: apps,
}, nil
}
func (a npmLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool {
fileName := filepath.Base(filePath)
return utils.StringInSlice(fileName, requiredFiles)
if fileName == types.NpmPkgLock {
return true
}
// The file path to package.json - */node_modules/<package_name>/package.json
// The path is slashed in analyzers.
dirs := strings.Split(path.Dir(filePath), "/")
if len(dirs) > 1 && dirs[len(dirs)-2] == "node_modules" && fileName == types.NpmPkg {
return true
}
return false
}
func (a npmLibraryAnalyzer) Type() analyzer.Type {
@@ -45,3 +104,59 @@ func (a npmLibraryAnalyzer) Type() analyzer.Type {
func (a npmLibraryAnalyzer) Version() int {
return version
}
func (a npmLibraryAnalyzer) parseNpmPkgLock(fsys fs.FS, path string) (*types.Application, error) {
f, err := fsys.Open(path)
if err != nil {
return nil, xerrors.Errorf("file open error: %w", err)
}
defer func() { _ = f.Close() }()
file, ok := f.(dio.ReadSeekCloserAt)
if !ok {
return nil, xerrors.Errorf("type assertion error: %w", err)
}
// parse package-lock.json file
libs, deps, err := a.lockParser.Parse(file)
if err != nil {
return nil, xerrors.Errorf("unable to parse package-lock.json: %w", err)
}
return language.ToApplication(types.Npm, path, "", libs, deps), nil
}
func (a npmLibraryAnalyzer) findLicenses(fsys fs.FS, lockPath string) (map[string]string, error) {
dir := filepath.Dir(lockPath)
root := path.Join(dir, "node_modules")
if _, err := fs.Stat(fsys, root); errors.Is(err, fs.ErrNotExist) {
log.Logger.Infof(`To collect the license information of packages in %q, "npm install" needs to be performed beforehand`, lockPath)
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 := map[string]string{}
err := fsutils.WalkDir(fsys, root, required, func(filePath string, d fs.DirEntry, r dio.ReadSeekerAt) error {
lib, _, err := a.packageParser.Parse(r)
// package.json always contains only 1 library.
// https://github.com/aquasecurity/go-dep-parser/blob/63a15cdc6bc3aaeb58c4172b275deadde4d55928/pkg/nodejs/packagejson/parse.go#L33-L37
if err != nil {
return xerrors.Errorf("unable to parse %q: %w", filePath, err)
} else if len(lib) != 1 {
return xerrors.Errorf("unable to parse %q", filePath)
}
licenses[lib[0].ID] = lib[0].License
return nil
})
if err != nil {
return nil, xerrors.Errorf("walk error: %w", err)
}
return licenses, nil
}

View File

@@ -12,23 +12,29 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
)
func TestMain(m *testing.M) {
_ = log.InitLogger(false, true)
os.Exit(m.Run())
}
func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
tests := []struct {
name string
inputFile string
want *analyzer.AnalysisResult
wantErr string
name string
dir string
want *analyzer.AnalysisResult
wantErr string
}{
{
name: "happy path",
inputFile: "testdata/package-lock.json",
name: "with node_modules",
dir: "testdata/happy",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Npm,
FilePath: "testdata/package-lock.json",
FilePath: "package-lock.json",
Libraries: []types.Package{
{
ID: "array-flatten@1.1.1",
@@ -48,6 +54,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
Version: "1.18.3",
Indirect: true,
DependsOn: []string{"debug@2.6.9"},
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 17,
@@ -61,6 +68,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
Version: "2.6.9",
Indirect: true,
DependsOn: []string{"ms@2.0.0"},
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 25,
@@ -78,6 +86,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
Version: "4.16.4",
Indirect: true,
DependsOn: []string{"debug@2.6.9"},
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 40,
@@ -90,6 +99,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
Name: "ms",
Version: "2.0.0",
Indirect: true,
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 33,
@@ -106,6 +116,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
Name: "ms",
Version: "2.1.1",
Indirect: true,
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 63,
@@ -119,26 +130,48 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) {
},
},
{
name: "sad path",
inputFile: "testdata/wrong.json",
wantErr: "unable to parse",
name: "without node_modules",
dir: "testdata/no-node_modules",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Npm,
FilePath: "package-lock.json",
Libraries: []types.Package{
{
ID: "ms@2.1.1",
Name: "ms",
Version: "2.1.1",
Indirect: true,
Locations: []types.Location{
{
StartLine: 6,
EndLine: 10,
},
},
},
},
},
},
},
},
{
name: "sad path",
dir: "testdata/sad",
wantErr: "unable to parse",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(tt.inputFile)
a, err := newNpmLibraryAnalyzer(analyzer.AnalyzerOptions{})
require.NoError(t, err)
defer func() { _ = f.Close() }()
a := npmLibraryAnalyzer{}
got, err := a.Analyze(context.Background(), analyzer.AnalysisInput{
FilePath: tt.inputFile,
Content: f,
got, err := a.PostAnalyze(context.Background(), analyzer.PostAnalysisInput{
FS: os.DirFS(tt.dir),
})
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
assert.ErrorContains(t, err, tt.wantErr)
return
}
@@ -175,13 +208,18 @@ func Test_nodePkgLibraryAnalyzer_Required(t *testing.T) {
want bool
}{
{
name: "happy path",
name: "lock file",
filePath: "npm/package-lock.json",
want: true,
},
{
name: "package.json",
filePath: "npm/node_modules/ms/package.json",
want: true,
},
{
name: "sad path",
filePath: "npm/package.json",
filePath: "npm/node_modules/package.json",
want: false,
},
}

View File

@@ -0,0 +1,49 @@
{
"name": "debug",
"version": "2.6.9",
"repository": {
"type": "git",
"url": "git://github.com/visionmedia/debug.git"
},
"description": "small debugging utility",
"keywords": [
"debug",
"log",
"debugger"
],
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Nathan Rajlich <nathan@tootallnate.net> (http://n8.io)",
"Andrew Rhyne <rhyneandrew@gmail.com>"
],
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
},
"devDependencies": {
"browserify": "9.0.3",
"chai": "^3.5.0",
"concurrently": "^3.1.0",
"coveralls": "^2.11.15",
"eslint": "^3.12.1",
"istanbul": "^0.4.5",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sinon": "^1.0.5",
"mocha": "^3.2.0",
"mocha-lcov-reporter": "^1.2.0",
"rimraf": "^2.5.4",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0"
},
"main": "./src/index.js",
"browser": "./src/browser.js",
"component": {
"scripts": {
"debug/index.js": "browser.js",
"debug/debug.js": "debug.js"
}
}
}

View File

@@ -0,0 +1,37 @@
{
"name": "ms",
"version": "2.0.0",
"description": "Tiny milisecond conversion utility",
"repository": "zeit/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": "3.19.0",
"expect.js": "0.3.1",
"husky": "0.13.3",
"lint-staged": "3.4.1",
"mocha": "3.4.1"
}
}

View File

@@ -0,0 +1,52 @@
{
"name": "body-parser",
"description": "Node.js body parsing middleware",
"version": "1.18.3",
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
],
"license": "MIT",
"repository": "expressjs/body-parser",
"dependencies": {
"bytes": "3.0.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "~1.6.3",
"iconv-lite": "0.4.23",
"on-finished": "~2.3.0",
"qs": "6.5.2",
"raw-body": "2.3.3",
"type-is": "~1.6.16"
},
"devDependencies": {
"eslint": "4.19.1",
"eslint-config-standard": "11.0.0",
"eslint-plugin-import": "2.11.0",
"eslint-plugin-markdown": "1.0.0-beta.6",
"eslint-plugin-node": "6.0.1",
"eslint-plugin-promise": "3.7.0",
"eslint-plugin-standard": "3.1.0",
"istanbul": "0.4.5",
"methods": "1.1.2",
"mocha": "2.5.3",
"safe-buffer": "5.1.2",
"supertest": "1.1.0"
},
"files": [
"lib/",
"LICENSE",
"HISTORY.md",
"index.js"
],
"engines": {
"node": ">= 0.8"
},
"scripts": {
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --require test/support/env --reporter spec --check-leaks --bail test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/"
}
}

View File

@@ -0,0 +1,49 @@
{
"name": "debug",
"version": "2.6.9",
"repository": {
"type": "git",
"url": "git://github.com/visionmedia/debug.git"
},
"description": "small debugging utility",
"keywords": [
"debug",
"log",
"debugger"
],
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Nathan Rajlich <nathan@tootallnate.net> (http://n8.io)",
"Andrew Rhyne <rhyneandrew@gmail.com>"
],
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
},
"devDependencies": {
"browserify": "9.0.3",
"chai": "^3.5.0",
"concurrently": "^3.1.0",
"coveralls": "^2.11.15",
"eslint": "^3.12.1",
"istanbul": "^0.4.5",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sinon": "^1.0.5",
"mocha": "^3.2.0",
"mocha-lcov-reporter": "^1.2.0",
"rimraf": "^2.5.4",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0"
},
"main": "./src/index.js",
"browser": "./src/browser.js",
"component": {
"scripts": {
"debug/index.js": "browser.js",
"debug/debug.js": "debug.js"
}
}
}

View File

@@ -0,0 +1,37 @@
{
"name": "ms",
"version": "2.0.0",
"description": "Tiny milisecond conversion utility",
"repository": "zeit/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": "3.19.0",
"expect.js": "0.3.1",
"husky": "0.13.3",
"lint-staged": "3.4.1",
"mocha": "3.4.1"
}
}

View File

@@ -0,0 +1,98 @@
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.16.4",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
"Ciaran Jessup <ciaranj@gmail.com>",
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Guillermo Rauch <rauchg@gmail.com>",
"Jonathan Ong <me@jongleberry.com>",
"Roman Shtylman <shtylman+expressjs@gmail.com>",
"Young Jae Sim <hanul@hanul.me>"
],
"license": "MIT",
"repository": "expressjs/express",
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
"sinatra",
"web",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
"accepts": "~1.3.5",
"array-flatten": "1.1.1",
"body-parser": "1.18.3",
"content-disposition": "0.5.2",
"content-type": "~1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.1.1",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.4",
"qs": "6.5.2",
"range-parser": "~1.2.0",
"safe-buffer": "5.1.2",
"send": "0.16.2",
"serve-static": "1.13.2",
"setprototypeof": "1.1.0",
"statuses": "~1.4.0",
"type-is": "~1.6.16",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"devDependencies": {
"after": "0.8.2",
"connect-redis": "3.4.0",
"cookie-parser": "~1.4.3",
"cookie-session": "1.3.2",
"ejs": "2.6.1",
"eslint": "2.13.1",
"express-session": "1.15.6",
"hbs": "4.0.1",
"istanbul": "0.4.5",
"marked": "0.5.1",
"method-override": "3.0.0",
"mocha": "5.2.0",
"morgan": "1.9.1",
"multiparty": "4.2.1",
"pbkdf2-password": "1.2.1",
"should": "13.2.3",
"supertest": "3.3.0",
"vhost": "~3.0.2"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"lint": "eslint .",
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
}
}

View File

@@ -0,0 +1,37 @@
{
"name": "ms",
"version": "2.1.1",
"description": "Tiny millisecond conversion utility",
"repository": "zeit/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.12.1",
"expect.js": "0.3.1",
"husky": "0.14.3",
"lint-staged": "5.0.0",
"mocha": "4.0.1"
}
}

View File

@@ -0,0 +1,12 @@
{
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
}

View File

@@ -58,6 +58,7 @@ const (
MavenPom = "pom.xml"
NpmPkg = "package.json"
NpmPkgLock = "package-lock.json"
YarnLock = "yarn.lock"
PnpmLock = "pnpm-lock.yaml"