From 59fe303e85330fc6d6f3b6ff79834018715cd1e8 Mon Sep 17 00:00:00 2001 From: Toure Dunnon Date: Wed, 14 Oct 2020 16:04:52 -0400 Subject: [PATCH] Add support for package.json #200 Signed-off-by: Toure Dunnon --- schema/README.md | 9 + syft/cataloger/cataloger.go | 8 +- syft/cataloger/javascript/cataloger.go | 15 +- .../javascript/parse_package_json.go | 54 +++ .../javascript/parse_package_json_test.go | 43 +++ syft/cataloger/javascript/parse_yarn_lock.go | 2 +- .../javascript/parse_yarn_lock_test.go | 14 +- .../test-fixtures/pkg-json/package.json | 314 ++++++++++++++++++ syft/pkg/npm_metadata.go | 12 + syft/pkg/package_test.go | 8 - syft/pkg/type.go | 16 +- test/integration/distro_test.go | 2 - test/integration/json_schema_test.go | 2 - .../{pkg_cases.go => pkg_cases_test.go} | 35 +- test/integration/pkg_coverage_test.go | 40 ++- .../javascript/package-json/package.json | 314 ++++++++++++++++++ 16 files changed, 812 insertions(+), 76 deletions(-) create mode 100644 schema/README.md create mode 100644 syft/cataloger/javascript/parse_package_json.go create mode 100644 syft/cataloger/javascript/parse_package_json_test.go create mode 100644 syft/cataloger/javascript/test-fixtures/pkg-json/package.json create mode 100644 syft/pkg/npm_metadata.go rename test/integration/{pkg_cases.go => pkg_cases_test.go} (96%) create mode 100644 test/integration/test-fixtures/image-pkg-coverage/javascript/package-json/package.json diff --git a/schema/README.md b/schema/README.md new file mode 100644 index 000000000000..c853322b85db --- /dev/null +++ b/schema/README.md @@ -0,0 +1,9 @@ +## Updating the JSON schema +Today the JSON schema is generated from integration test data. Specifically, when integration tests are run, the `/schema/json/examples` directory is populated with syft JSON output data. This examples directory is used to drive automatically generating the JSON schema. +The caveats with this approach is: +1) the JSON schema is only as good as the examples provided +2) there is an integration test that ensures that the JSON schema is valid relative to what the code currently generates. +This means to update the JSON schema you need to +1) Open up `test/integration/json_schema_test.go` and comment out invocations of the `validateAgainstV1Schema` function. +2) From the root of the repo run `generate-json-schema`. Now there should be a new schema generated at `/schema/json/schema.json` +3) Uncomment the `validateAgainstV1Schema` function. \ No newline at end of file diff --git a/syft/cataloger/cataloger.go b/syft/cataloger/cataloger.go index 85e0f77bcd93..9b6b5cd0a690 100644 --- a/syft/cataloger/cataloger.go +++ b/syft/cataloger/cataloger.go @@ -37,8 +37,8 @@ type Cataloger interface { func ImageCatalogers() []Cataloger { return []Cataloger{ ruby.NewGemSpecCataloger(), - python.NewPythonCataloger(), // TODO: split and replace me - javascript.NewJavascriptCataloger(), // TODO: split and replace me + python.NewPythonCataloger(), // TODO: split and replace me + javascript.NewJavascriptPackageCataloger(), deb.NewDpkgdbCataloger(), rpmdb.NewRpmdbCataloger(), java.NewJavaCataloger(), @@ -51,8 +51,8 @@ func ImageCatalogers() []Cataloger { func DirectoryCatalogers() []Cataloger { return []Cataloger{ ruby.NewGemFileLockCataloger(), - python.NewPythonCataloger(), // TODO: split and replace me - javascript.NewJavascriptCataloger(), // TODO: split and replace me + python.NewPythonCataloger(), // TODO: split and replace me + javascript.NewJavascriptLockCataloger(), deb.NewDpkgdbCataloger(), rpmdb.NewRpmdbCataloger(), java.NewJavaCataloger(), diff --git a/syft/cataloger/javascript/cataloger.go b/syft/cataloger/javascript/cataloger.go index 86aeb1acdd1a..fe709d458e74 100644 --- a/syft/cataloger/javascript/cataloger.go +++ b/syft/cataloger/javascript/cataloger.go @@ -7,12 +7,21 @@ import ( "github.com/anchore/syft/syft/cataloger/common" ) -// NewJavascriptCataloger returns a new JavaScript cataloger object. -func NewJavascriptCataloger() *common.GenericCataloger { +// NewJavascriptPackageCataloger returns a new JavaScript cataloger object based on detection of npm based packages. +func NewJavascriptPackageCataloger() *common.GenericCataloger { + globParsers := map[string]common.ParserFn{ + "**/package.json": parsePackageJSON, + } + + return common.NewGenericCataloger(nil, globParsers, "javascript-package-cataloger") +} + +// NewJavascriptLockCataloger returns a new Javascript cataloger object base on package lock files. +func NewJavascriptLockCataloger() *common.GenericCataloger { globParsers := map[string]common.ParserFn{ "**/package-lock.json": parsePackageLock, "**/yarn.lock": parseYarnLock, } - return common.NewGenericCataloger(nil, globParsers, "javascript-cataloger") + return common.NewGenericCataloger(nil, globParsers, "javascript-lock-cataloger") } diff --git a/syft/cataloger/javascript/parse_package_json.go b/syft/cataloger/javascript/parse_package_json.go new file mode 100644 index 000000000000..83642e4513f0 --- /dev/null +++ b/syft/cataloger/javascript/parse_package_json.go @@ -0,0 +1,54 @@ +package javascript + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg" +) + +// integrity check +var _ common.ParserFn = parsePackageLock + +// PackageJSON represents a JavaScript package.json file +type PackageJSON struct { + Version string `json:"version"` + Latest []string `json:"latest"` + Author string `json:"author"` + License string `json:"license"` + Name string `json:"name"` + Homepage string `json:"homepage"` + Description string `json:"description"` + Dependencies map[string]string `json:"dependencies"` +} + +// parsePackageJson parses a package.json and returns the discovered JavaScript packages. +func parsePackageJSON(_ string, reader io.Reader) ([]pkg.Package, error) { + packages := make([]pkg.Package, 0) + dec := json.NewDecoder(reader) + + for { + var p PackageJSON + if err := dec.Decode(&p); err == io.EOF { + break + } else if err != nil { + return nil, fmt.Errorf("failed to parse package.json file: %w", err) + } + + packages = append(packages, pkg.Package{ + Name: p.Name, + Version: p.Version, + Licenses: []string{p.License}, + Language: pkg.JavaScript, + Type: pkg.NpmPkg, + Metadata: pkg.NpmMetadata{ + Author: p.Author, + Homepage: p.Homepage, + }, + }) + } + + return packages, nil +} diff --git a/syft/cataloger/javascript/parse_package_json_test.go b/syft/cataloger/javascript/parse_package_json_test.go new file mode 100644 index 000000000000..f8e7b92fb2ee --- /dev/null +++ b/syft/cataloger/javascript/parse_package_json_test.go @@ -0,0 +1,43 @@ +package javascript + +import ( + "os" + "testing" + + "github.com/anchore/syft/syft/pkg" + "github.com/go-test/deep" +) + +func TestParsePackageJSON(t *testing.T) { + expected := pkg.Package{ + Name: "npm", + Version: "6.14.6", + Type: pkg.NpmPkg, + Licenses: []string{"Artistic-2.0"}, + Language: pkg.JavaScript, + Metadata: pkg.NpmMetadata{ + Author: "Isaac Z. Schlueter (http://blog.izs.me)", + Homepage: "https://docs.npmjs.com/", + }, + } + fixture, err := os.Open("test-fixtures/pkg-json/package.json") + if err != nil { + t.Fatalf("failed to open fixture: %+v", err) + } + + actual, err := parsePackageJSON(fixture.Name(), fixture) + if err != nil { + t.Fatalf("failed to parse package-lock.json: %+v", err) + } + if len(actual) != 1 { + for _, a := range actual { + t.Log(" ", a) + } + t.Fatalf("unexpected package count: %d!=1", len(actual)) + } + + for _, d := range deep.Equal(actual[0], expected) { + t.Errorf("diff: %+v", d) + } + +} diff --git a/syft/cataloger/javascript/parse_yarn_lock.go b/syft/cataloger/javascript/parse_yarn_lock.go index 6ede34fa9cb4..0c637f9e7c0c 100644 --- a/syft/cataloger/javascript/parse_yarn_lock.go +++ b/syft/cataloger/javascript/parse_yarn_lock.go @@ -66,7 +66,7 @@ func parseYarnLock(_ string, reader io.Reader) ([]pkg.Package, error) { Name: currentName, Version: strings.Trim(version, "\""), Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }) } } diff --git a/syft/cataloger/javascript/parse_yarn_lock_test.go b/syft/cataloger/javascript/parse_yarn_lock_test.go index 3decbb86ae04..6ea75cb7196e 100644 --- a/syft/cataloger/javascript/parse_yarn_lock_test.go +++ b/syft/cataloger/javascript/parse_yarn_lock_test.go @@ -13,43 +13,43 @@ func TestParseYarnLock(t *testing.T) { Name: "@babel/code-frame", Version: "7.10.4", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "@types/minimatch": { Name: "@types/minimatch", Version: "3.0.3", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "@types/qs": { Name: "@types/qs", Version: "6.9.4", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "ajv": { Name: "ajv", Version: "6.12.3", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "atob": { Name: "atob", Version: "2.1.2", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "aws-sdk": { Name: "aws-sdk", Version: "2.706.0", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, "jhipster-core": { Name: "jhipster-core", Version: "7.3.4", Language: pkg.JavaScript, - Type: pkg.YarnPkg, + Type: pkg.NpmPkg, }, } fixture, err := os.Open("test-fixtures/yarn/yarn.lock") diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package.json b/syft/cataloger/javascript/test-fixtures/pkg-json/package.json new file mode 100644 index 000000000000..aba48c6bd3d3 --- /dev/null +++ b/syft/cataloger/javascript/test-fixtures/pkg-json/package.json @@ -0,0 +1,314 @@ +{ + "version": "6.14.6", + "name": "npm", + "description": "a package manager for JavaScript", + "keywords": [ + "install", + "modules", + "package manager", + "package.json" + ], + "preferGlobal": true, + "config": { + "publishtest": false + }, + "homepage": "https://docs.npmjs.com/", + "author": "Isaac Z. Schlueter (http://blog.izs.me)", + "repository": { + "type": "git", + "url": "https://github.com/npm/cli" + }, + "bugs": { + "url": "https://npm.community/c/bugs" + }, + "directories": { + "bin": "./bin", + "doc": "./doc", + "lib": "./lib", + "man": "./man" + }, + "main": "./lib/npm.js", + "bin": { + "npm": "./bin/npm-cli.js", + "npx": "./bin/npx-cli.js" + }, + "dependencies": { + "JSONStream": "^1.3.5", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.7", + "bluebird": "^3.5.5", + "byte-size": "^5.0.1", + "cacache": "^12.0.3", + "call-limit": "^1.1.1", + "chownr": "^1.1.4", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.12", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.0", + "glob": "^7.1.6", + "graceful-fs": "^4.2.4", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.8", + "iferr": "^1.0.2", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^3.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.7", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.2", + "lock-verify": "^2.1.0", + "lockfile": "^1.0.4", + "lodash._baseuniq": "~4.6.0", + "lodash.clonedeep": "~4.5.0", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.5", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.1.0", + "nopt": "^4.0.3", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.2", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.4", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.8", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.4", + "npm-registry-fetch": "^4.0.5", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.1", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.8.2", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.1", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.6.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "^2.7.1", + "safe-buffer": "^5.1.2", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.1", + "stringify-package": "^1.0.1", + "tar": "^4.4.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.3", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "bundleDependencies": [ + "abbrev", + "ansicolors", + "ansistyles", + "aproba", + "archy", + "bin-links", + "bluebird", + "byte-size", + "cacache", + "call-limit", + "chownr", + "ci-info", + "cli-columns", + "cli-table3", + "cmd-shim", + "columnify", + "config-chain", + "debuglog", + "detect-indent", + "detect-newline", + "dezalgo", + "editor", + "figgy-pudding", + "find-npm-prefix", + "fs-vacuum", + "fs-write-stream-atomic", + "gentle-fs", + "glob", + "graceful-fs", + "has-unicode", + "hosted-git-info", + "iferr", + "imurmurhash", + "infer-owner", + "inflight", + "inherits", + "ini", + "init-package-json", + "is-cidr", + "json-parse-better-errors", + "JSONStream", + "lazy-property", + "libcipm", + "libnpm", + "libnpmaccess", + "libnpmhook", + "libnpmorg", + "libnpmsearch", + "libnpmteam", + "libnpx", + "lock-verify", + "lockfile", + "lodash._baseindexof", + "lodash._baseuniq", + "lodash._bindcallback", + "lodash._cacheindexof", + "lodash._createcache", + "lodash._getnative", + "lodash.clonedeep", + "lodash.restparam", + "lodash.union", + "lodash.uniq", + "lodash.without", + "lru-cache", + "meant", + "mississippi", + "mkdirp", + "move-concurrently", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-cache-filename", + "npm-install-checks", + "npm-lifecycle", + "npm-package-arg", + "npm-packlist", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "once", + "opener", + "osenv", + "pacote", + "path-is-inside", + "promise-inflight", + "qrcode-terminal", + "query-string", + "qw", + "read-cmd-shim", + "read-installed", + "read-package-json", + "read-package-tree", + "read", + "readable-stream", + "readdir-scoped-modules", + "request", + "retry", + "rimraf", + "safe-buffer", + "semver", + "sha", + "slide", + "sorted-object", + "sorted-union-stream", + "ssri", + "stringify-package", + "tar", + "text-table", + "tiny-relative-date", + "uid-number", + "umask", + "unique-filename", + "unpipe", + "update-notifier", + "uuid", + "validate-npm-package-license", + "validate-npm-package-name", + "which", + "worker-farm", + "write-file-atomic" + ], + "devDependencies": { + "deep-equal": "^1.0.1", + "get-stream": "^4.1.0", + "licensee": "^7.0.3", + "marked": "^0.6.3", + "marked-man": "^0.6.0", + "npm-registry-couchapp": "^2.7.4", + "npm-registry-mock": "^1.3.1", + "require-inject": "^1.4.4", + "sprintf-js": "^1.1.2", + "standard": "^11.0.1", + "tacks": "^1.3.0", + "tap": "^12.7.0", + "tar-stream": "^2.1.0" + }, + "scripts": { + "dumpconf": "env | grep npm | sort | uniq", + "prepare": "node bin/npm-cli.js rebuild && node bin/npm-cli.js --no-audit --no-timing prune --prefix=. --no-global && rimraf test/*/*/node_modules && make -j4 mandocs", + "preversion": "bash scripts/update-authors.sh && git add AUTHORS && git commit -m \"update AUTHORS\" || true", + "licenses": "licensee --production --errors-only", + "tap": "tap -J --timeout 300 --no-esm", + "tap-cover": "tap -J --nyc-arg=--cache --coverage --timeout 600 --no-esm", + "lint": "standard", + "pretest": "npm run lint", + "test": "npm run test-tap --", + "test:nocleanup": "NO_TEST_CLEANUP=1 npm run test --", + "sudotest": "sudo npm run tap -- \"test/tap/*.js\"", + "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run tap -- \"test/tap/*.js\"", + "posttest": "rimraf test/npm_cache*", + "test-coverage": "npm run tap-cover -- \"test/tap/*.js\" \"test/network/*.js\"", + "test-tap": "npm run tap -- \"test/tap/*.js\" \"test/network/*.js\"", + "test-node": "tap --timeout 240 \"test/tap/*.js\" \"test/network/*.js\"" + }, + "license": "Artistic-2.0", + "engines": { + "node": "6 >=6.2.0 || 8 || >=9.3.0" + } +} \ No newline at end of file diff --git a/syft/pkg/npm_metadata.go b/syft/pkg/npm_metadata.go new file mode 100644 index 000000000000..af683120b692 --- /dev/null +++ b/syft/pkg/npm_metadata.go @@ -0,0 +1,12 @@ +package pkg + +// NpmMetadata holds extra information that is used in pkg.Package +type NpmMetadata struct { + Name string `mapstructure:"name" json:"name"` + Version string `mapstructure:"version" json:"version"` + Files []string `mapstructure:"files" json:"files"` + Author string `mapstructure:"author" json:"author"` + License string `mapstructure:"license" json:"license"` + Homepage string `mapstructure:"homepage" json:"homepage"` + Description string `mapstructure:"description" json:"description"` +} diff --git a/syft/pkg/package_test.go b/syft/pkg/package_test.go index 220146725ad4..1fec05b4b7ba 100644 --- a/syft/pkg/package_test.go +++ b/syft/pkg/package_test.go @@ -69,14 +69,6 @@ func TestPackage_pURL(t *testing.T) { }, expected: "pkg:npm/name@v0.1.0", }, - { - pkg: Package{ - Name: "name", - Version: "v0.1.0", - Type: YarnPkg, - }, - expected: "pkg:npm/name@v0.1.0", - }, { distro: distro.Distro{ Type: distro.Ubuntu, diff --git a/syft/pkg/type.go b/syft/pkg/type.go index 61ed2487884c..3d7ff672bbd0 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -6,17 +6,15 @@ import "github.com/package-url/packageurl-go" type Type string const ( - UnknownPkg Type = "UnknownPackage" - ApkPkg Type = "apk" - GemPkg Type = "gem" - DebPkg Type = "deb" - EggPkg Type = "egg" - // PacmanPkg Type = "pacman" + UnknownPkg Type = "UnknownPackage" + ApkPkg Type = "apk" + GemPkg Type = "gem" + DebPkg Type = "deb" + EggPkg Type = "egg" RpmPkg Type = "rpm" WheelPkg Type = "wheel" PoetryPkg Type = "poetry" NpmPkg Type = "npm" - YarnPkg Type = "yarn" PythonRequirementsPkg Type = "python-requirements" PythonSetupPkg Type = "python-setup" JavaPkg Type = "java-archive" @@ -29,11 +27,9 @@ var AllPkgs = []Type{ GemPkg, DebPkg, EggPkg, - // PacmanPkg, RpmPkg, WheelPkg, NpmPkg, - YarnPkg, PythonRequirementsPkg, PythonSetupPkg, JavaPkg, @@ -51,7 +47,7 @@ func (t Type) PackageURLType() string { return "deb" case EggPkg, WheelPkg, PythonRequirementsPkg, PythonSetupPkg: return packageurl.TypePyPi - case NpmPkg, YarnPkg: + case NpmPkg: return packageurl.TypeNPM case JavaPkg, JenkinsPluginPkg: return packageurl.TypeMaven diff --git a/test/integration/distro_test.go b/test/integration/distro_test.go index f3bf1dae69d5..11b92a90dd29 100644 --- a/test/integration/distro_test.go +++ b/test/integration/distro_test.go @@ -1,5 +1,3 @@ -// +build integration - package integration import ( diff --git a/test/integration/json_schema_test.go b/test/integration/json_schema_test.go index 8545c0978279..6c49605b37b6 100644 --- a/test/integration/json_schema_test.go +++ b/test/integration/json_schema_test.go @@ -1,5 +1,3 @@ -// +build integration - package integration import ( diff --git a/test/integration/pkg_cases.go b/test/integration/pkg_cases_test.go similarity index 96% rename from test/integration/pkg_cases.go rename to test/integration/pkg_cases_test.go index 54762a15164a..3eb83e45ec60 100644 --- a/test/integration/pkg_cases.go +++ b/test/integration/pkg_cases_test.go @@ -1,5 +1,3 @@ -// +build integration - package integration import "github.com/anchore/syft/syft/pkg" @@ -20,6 +18,14 @@ var imageOnlyTestCases = []testCase{ "bundler": "2.1.4", }, }, + { + name: "find npm package", + pkgType: pkg.NpmPkg, + pkgLanguage: pkg.JavaScript, + pkgInfo: map[string]string{ + "npm": "6.14.6", + }, + }, } var dirOnlyTestCases = []testCase{ @@ -81,6 +87,15 @@ var dirOnlyTestCases = []testCase{ "unicorn": "4.8.3", }, }, + { + name: "find javascript npm packages (yarn.lock & package-lock.json)", + pkgType: pkg.NpmPkg, + pkgLanguage: pkg.JavaScript, + pkgInfo: map[string]string{ + "@babel/code-frame": "7.10.4", + "get-stdin": "8.0.0", + }, + }, } var commonTestCases = []testCase{ @@ -125,22 +140,6 @@ var commonTestCases = []testCase{ "requests": "2.10.0", }, }, - { - name: "find javascript npm packages", - pkgType: pkg.NpmPkg, - pkgLanguage: pkg.JavaScript, - pkgInfo: map[string]string{ - "get-stdin": "8.0.0", - }, - }, - { - name: "find javascript yarn packages", - pkgType: pkg.YarnPkg, - pkgLanguage: pkg.JavaScript, - pkgInfo: map[string]string{ - "@babel/code-frame": "7.10.4", - }, - }, { name: "find python egg packages", pkgType: pkg.EggPkg, diff --git a/test/integration/pkg_coverage_test.go b/test/integration/pkg_coverage_test.go index f79fbd55da43..974421a96091 100644 --- a/test/integration/pkg_coverage_test.go +++ b/test/integration/pkg_coverage_test.go @@ -1,5 +1,3 @@ -// +build integration - package integration import ( @@ -123,39 +121,39 @@ func TestPkgCoverageDirectory(t *testing.T) { cases = append(cases, commonTestCases...) cases = append(cases, dirOnlyTestCases...) - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - pkgCount := 0 + for _, test := range cases { + t.Run(test.name, func(t *testing.T) { + actualPkgCount := 0 - for a := range catalog.Enumerate(c.pkgType) { + for actualPkg := range catalog.Enumerate(test.pkgType) { - observedLanguages.Add(a.Language.String()) - observedPkgs.Add(string(a.Type)) + observedLanguages.Add(actualPkg.Language.String()) + observedPkgs.Add(string(actualPkg.Type)) - expectedVersion, ok := c.pkgInfo[a.Name] + expectedVersion, ok := test.pkgInfo[actualPkg.Name] if !ok { - t.Errorf("unexpected package found: %s", a.Name) + t.Errorf("unexpected package found: %s", actualPkg.Name) } - if expectedVersion != a.Version { - t.Errorf("unexpected package version (pkg=%s): %s", a.Name, a.Version) + if expectedVersion != actualPkg.Version { + t.Errorf("unexpected package version (pkg=%s): %s", actualPkg.Name, actualPkg.Version) } - if a.Language != c.pkgLanguage { - t.Errorf("bad language (pkg=%+v): %+v", a.Name, a.Language) + if actualPkg.Language != test.pkgLanguage { + t.Errorf("bad language (pkg=%+v): %+v", actualPkg.Name, actualPkg.Language) } - if a.Type != c.pkgType { - t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type) + if actualPkg.Type != test.pkgType { + t.Errorf("bad package type (pkg=%+v): %+v", actualPkg.Name, actualPkg.Type) } - pkgCount++ + actualPkgCount++ } - if pkgCount != len(c.pkgInfo) { - for a := range catalog.Enumerate(c.pkgType) { - t.Log(" ", a) + if actualPkgCount != len(test.pkgInfo) { + for actualPkg := range catalog.Enumerate(test.pkgType) { + t.Log(" ", actualPkg) } - t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo)) + t.Fatalf("unexpected package count: %d!=%d", actualPkgCount, len(test.pkgInfo)) } }) diff --git a/test/integration/test-fixtures/image-pkg-coverage/javascript/package-json/package.json b/test/integration/test-fixtures/image-pkg-coverage/javascript/package-json/package.json new file mode 100644 index 000000000000..aba48c6bd3d3 --- /dev/null +++ b/test/integration/test-fixtures/image-pkg-coverage/javascript/package-json/package.json @@ -0,0 +1,314 @@ +{ + "version": "6.14.6", + "name": "npm", + "description": "a package manager for JavaScript", + "keywords": [ + "install", + "modules", + "package manager", + "package.json" + ], + "preferGlobal": true, + "config": { + "publishtest": false + }, + "homepage": "https://docs.npmjs.com/", + "author": "Isaac Z. Schlueter (http://blog.izs.me)", + "repository": { + "type": "git", + "url": "https://github.com/npm/cli" + }, + "bugs": { + "url": "https://npm.community/c/bugs" + }, + "directories": { + "bin": "./bin", + "doc": "./doc", + "lib": "./lib", + "man": "./man" + }, + "main": "./lib/npm.js", + "bin": { + "npm": "./bin/npm-cli.js", + "npx": "./bin/npx-cli.js" + }, + "dependencies": { + "JSONStream": "^1.3.5", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.7", + "bluebird": "^3.5.5", + "byte-size": "^5.0.1", + "cacache": "^12.0.3", + "call-limit": "^1.1.1", + "chownr": "^1.1.4", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.12", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.0", + "glob": "^7.1.6", + "graceful-fs": "^4.2.4", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.8", + "iferr": "^1.0.2", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^3.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.7", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.2", + "lock-verify": "^2.1.0", + "lockfile": "^1.0.4", + "lodash._baseuniq": "~4.6.0", + "lodash.clonedeep": "~4.5.0", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.5", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.1.0", + "nopt": "^4.0.3", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.2", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.4", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.8", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.4", + "npm-registry-fetch": "^4.0.5", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.1", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.8.2", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.1", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.6.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "^2.7.1", + "safe-buffer": "^5.1.2", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.1", + "stringify-package": "^1.0.1", + "tar": "^4.4.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.3", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "bundleDependencies": [ + "abbrev", + "ansicolors", + "ansistyles", + "aproba", + "archy", + "bin-links", + "bluebird", + "byte-size", + "cacache", + "call-limit", + "chownr", + "ci-info", + "cli-columns", + "cli-table3", + "cmd-shim", + "columnify", + "config-chain", + "debuglog", + "detect-indent", + "detect-newline", + "dezalgo", + "editor", + "figgy-pudding", + "find-npm-prefix", + "fs-vacuum", + "fs-write-stream-atomic", + "gentle-fs", + "glob", + "graceful-fs", + "has-unicode", + "hosted-git-info", + "iferr", + "imurmurhash", + "infer-owner", + "inflight", + "inherits", + "ini", + "init-package-json", + "is-cidr", + "json-parse-better-errors", + "JSONStream", + "lazy-property", + "libcipm", + "libnpm", + "libnpmaccess", + "libnpmhook", + "libnpmorg", + "libnpmsearch", + "libnpmteam", + "libnpx", + "lock-verify", + "lockfile", + "lodash._baseindexof", + "lodash._baseuniq", + "lodash._bindcallback", + "lodash._cacheindexof", + "lodash._createcache", + "lodash._getnative", + "lodash.clonedeep", + "lodash.restparam", + "lodash.union", + "lodash.uniq", + "lodash.without", + "lru-cache", + "meant", + "mississippi", + "mkdirp", + "move-concurrently", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-cache-filename", + "npm-install-checks", + "npm-lifecycle", + "npm-package-arg", + "npm-packlist", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "once", + "opener", + "osenv", + "pacote", + "path-is-inside", + "promise-inflight", + "qrcode-terminal", + "query-string", + "qw", + "read-cmd-shim", + "read-installed", + "read-package-json", + "read-package-tree", + "read", + "readable-stream", + "readdir-scoped-modules", + "request", + "retry", + "rimraf", + "safe-buffer", + "semver", + "sha", + "slide", + "sorted-object", + "sorted-union-stream", + "ssri", + "stringify-package", + "tar", + "text-table", + "tiny-relative-date", + "uid-number", + "umask", + "unique-filename", + "unpipe", + "update-notifier", + "uuid", + "validate-npm-package-license", + "validate-npm-package-name", + "which", + "worker-farm", + "write-file-atomic" + ], + "devDependencies": { + "deep-equal": "^1.0.1", + "get-stream": "^4.1.0", + "licensee": "^7.0.3", + "marked": "^0.6.3", + "marked-man": "^0.6.0", + "npm-registry-couchapp": "^2.7.4", + "npm-registry-mock": "^1.3.1", + "require-inject": "^1.4.4", + "sprintf-js": "^1.1.2", + "standard": "^11.0.1", + "tacks": "^1.3.0", + "tap": "^12.7.0", + "tar-stream": "^2.1.0" + }, + "scripts": { + "dumpconf": "env | grep npm | sort | uniq", + "prepare": "node bin/npm-cli.js rebuild && node bin/npm-cli.js --no-audit --no-timing prune --prefix=. --no-global && rimraf test/*/*/node_modules && make -j4 mandocs", + "preversion": "bash scripts/update-authors.sh && git add AUTHORS && git commit -m \"update AUTHORS\" || true", + "licenses": "licensee --production --errors-only", + "tap": "tap -J --timeout 300 --no-esm", + "tap-cover": "tap -J --nyc-arg=--cache --coverage --timeout 600 --no-esm", + "lint": "standard", + "pretest": "npm run lint", + "test": "npm run test-tap --", + "test:nocleanup": "NO_TEST_CLEANUP=1 npm run test --", + "sudotest": "sudo npm run tap -- \"test/tap/*.js\"", + "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run tap -- \"test/tap/*.js\"", + "posttest": "rimraf test/npm_cache*", + "test-coverage": "npm run tap-cover -- \"test/tap/*.js\" \"test/network/*.js\"", + "test-tap": "npm run tap -- \"test/tap/*.js\" \"test/network/*.js\"", + "test-node": "tap --timeout 240 \"test/tap/*.js\" \"test/network/*.js\"" + }, + "license": "Artistic-2.0", + "engines": { + "node": "6 >=6.2.0 || 8 || >=9.3.0" + } +} \ No newline at end of file