From 4b8e49e7af42705d217a2c113ce65ffabe163b93 Mon Sep 17 00:00:00 2001 From: Jack Zhao Date: Thu, 1 Nov 2018 09:30:08 -0700 Subject: [PATCH] fix audit for packages without name (#6611) * fix audit for packages without name * add test * fix bad dependency version * fix bad dependency version * Update audit.js * Update CHANGELOG.md --- CHANGELOG.md | 8 ++ __tests__/commands/audit.js | 39 ++++++++++ .../private-package/audit-api-response.json | 77 +++++++++++++++++++ .../audit/private-package/package.json | 6 ++ .../fixtures/audit/private-package/yarn.lock | 8 ++ src/cli/commands/audit.js | 11 ++- 6 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 __tests__/fixtures/audit/private-package/audit-api-response.json create mode 100644 __tests__/fixtures/audit/private-package/package.json create mode 100644 __tests__/fixtures/audit/private-package/yarn.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index edb1a86287..91f609c174 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa ## Master +- Fixes an issue with `yarn audit` when the root package was missing a name + + [#6611](https://github.com/yarnpkg/yarn/pull/6611) - [**Jack Zhao**](https://github.com/bugzpodder) + +- Fixes an issue with `yarn audit` when a package was depending on an empty range + + [#6611](https://github.com/yarnpkg/yarn/pull/6611) - [**Jack Zhao**](https://github.com/bugzpodder) + ## 1.12.1 - Ensures the engine check is ran before showing the UI for `upgrade-interactive` diff --git a/__tests__/commands/audit.js b/__tests__/commands/audit.js index aaf0fa5046..9ba7c8b4c4 100644 --- a/__tests__/commands/audit.js +++ b/__tests__/commands/audit.js @@ -123,3 +123,42 @@ test('calls reporter auditSummary with correct data', () => { expect(reporter.auditSummary).toBeCalledWith(apiResponse.metadata); }); }); + +test.concurrent('sends correct dependency map to audit api for private package.', () => { + const expectedApiPost = { + install: [], + remove: [], + metadata: {}, + requires: { + 'left-pad': '^1.3.0', + }, + dependencies: { + 'left-pad': { + version: '1.3.0', + integrity: 'sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==', + requires: {}, + dependencies: {}, + }, + }, + }; + + return runAudit([], {}, 'private-package', async config => { + const calledWithPipe = config.requestManager.request.mock.calls[0][0].body; + const calledWith = JSON.parse(await gunzip(calledWithPipe)); + expect(calledWith).toEqual(expectedApiPost); + }); +}); + +test('calls reporter auditAdvisory with correct data for private package', () => { + return runAudit([], {}, 'single-vulnerable-dep-installed', (config, reporter) => { + const apiResponse = getAuditResponse(config); + expect(reporter.auditAdvisory).toBeCalledWith(apiResponse.actions[0].resolves[0], apiResponse.advisories['118']); + }); +}); + +test('calls reporter auditSummary with correct data for private package', () => { + return runAudit([], {}, 'single-vulnerable-dep-installed', (config, reporter) => { + const apiResponse = getAuditResponse(config); + expect(reporter.auditSummary).toBeCalledWith(apiResponse.metadata); + }); +}); diff --git a/__tests__/fixtures/audit/private-package/audit-api-response.json b/__tests__/fixtures/audit/private-package/audit-api-response.json new file mode 100644 index 0000000000..e0d4605b3e --- /dev/null +++ b/__tests__/fixtures/audit/private-package/audit-api-response.json @@ -0,0 +1,77 @@ +{ + "actions": [ + { + "action": "install", + "module": "minimatch", + "target": "3.0.4", + "isMajor": false, + "resolves": [ + { + "id": 118, + "path": "minimatch", + "dev": false, + "optional": false, + "bundled": false + } + ] + } + ], + "advisories": { + "118": { + "findings": [ + { + "version": "3.0.0", + "paths": [ + "minimatch" + ], + "dev": false, + "optional": false, + "bundled": false + } + ], + "id": 118, + "created": "2016-05-25T16:37:20.000Z", + "updated": "2018-03-01T21:58:01.072Z", + "deleted": null, + "title": "Regular Expression Denial of Service", + "found_by": { + "name": "Nick Starke" + }, + "reported_by": { + "name": "Nick Starke" + }, + "module_name": "minimatch", + "cves": [ + "CVE-2016-10540" + ], + "vulnerable_versions": "<=3.0.1", + "patched_versions": ">=3.0.2", + "overview": "Affected versions of `minimatch` are vulnerable to regular expression denial of service attacks when user input is passed into the `pattern` argument of `minimatch(path, pattern)`.\n\n\n## Proof of Concept\n```\nvar minimatch = require(“minimatch”);\n\n// utility function for generating long strings\nvar genstr = function (len, chr) {\n var result = “”;\n for (i=0; i<=len; i++) {\n result = result + chr;\n }\n return result;\n}\n\nvar exploit = “[!” + genstr(1000000, “\\\\”) + “A”;\n\n// minimatch exploit.\nconsole.log(“starting minimatch”);\nminimatch(“foo”, exploit);\nconsole.log(“finishing minimatch”);\n```", + "recommendation": "Update to version 3.0.2 or later.", + "references": "", + "access": "public", + "severity": "high", + "cwe": "CWE-400", + "metadata": { + "module_type": "Multi.Library", + "exploitability": 4, + "affected_components": "Internal::Code::Function::minimatch({type:'args', key:0, vector:{type:'string'}})" + }, + "url": "https://nodesecurity.io/advisories/118" + } + }, + "muted": [], + "metadata": { + "vulnerabilities": { + "info": 0, + "low": 0, + "moderate": 0, + "high": 1, + "critical": 0 + }, + "dependencies": 5, + "devDependencies": 0, + "optionalDependencies": 0, + "totalDependencies": 5 + } +} diff --git a/__tests__/fixtures/audit/private-package/package.json b/__tests__/fixtures/audit/private-package/package.json new file mode 100644 index 0000000000..f16c191691 --- /dev/null +++ b/__tests__/fixtures/audit/private-package/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "left-pad": "^1.3.0" + } +} diff --git a/__tests__/fixtures/audit/private-package/yarn.lock b/__tests__/fixtures/audit/private-package/yarn.lock new file mode 100644 index 0000000000..9660884091 --- /dev/null +++ b/__tests__/fixtures/audit/private-package/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== diff --git a/src/cli/commands/audit.js b/src/cli/commands/audit.js index b9faa70381..4505976f28 100644 --- a/src/cli/commands/audit.js +++ b/src/cli/commands/audit.js @@ -160,13 +160,18 @@ export default class Audit { _mapHoistedNodes(auditNode: AuditNode, hoistedNodes: HoistedTrees) { for (const node of hoistedNodes) { const pkg = node.manifest.pkg; + const requires = Object.assign({}, pkg.dependencies || {}, pkg.optionalDependencies || {}); + for (const name of Object.keys(requires)) { + if (!requires[name]) { + requires[name] = '*'; + } + } auditNode.dependencies[node.name] = { version: node.version, integrity: pkg._remote ? pkg._remote.integrity || '' : '', - requires: Object.assign({}, pkg.dependencies || {}, pkg.optionalDependencies || {}), + requires, dependencies: {}, }; - if (node.children) { this._mapHoistedNodes(auditNode.dependencies[node.name], node.children); } @@ -175,7 +180,7 @@ export default class Audit { _mapHoistedTreesToAuditTree(manifest: Object, hoistedTrees: HoistedTrees): AuditTree { const auditTree: AuditTree = { - name: manifest.name, + name: manifest.name || undefined, version: manifest.version || undefined, install: [], remove: [],