Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(audit) Initial addition of yarn audit command. (#6409)
* WIP: audit command added. sends data to registry. * code cleanup * WIP: Added Audit command. No tests. Existing test fail. * Print audit summary when no problems found * Don't send package version to audit API if it is not in the manifest. * Add audit functions to json-reporter * WIP: First successful audit command test * added more audit tests * feat(audit): Initial addition of yarn audit command and --audit flag Added "yarn audit" command which copies the behavior of "npm audit". Unline npm, yarn does not automatically run "audit" during "add/install/upgrade" commands. Since this would cause an additional network call, it broke all existing unit tests to add this feature and have it run automatically. In the interest of getting an initial release in the hands of our users the "add/install/upgrade" commands accept a "--audit" flag that will enable the audit. If you want audit to always execute, you can add "--*.audit true" to .yarnrc fix #5808 * gzip the JSON sent to npm audit API to reduce payload * fix audit test for gzip data * Update install.js * removed audit correction suggestions due to them being unreliable * Updates the changelog
- Loading branch information
Showing
22 changed files
with
993 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* @flow */ | ||
|
||
import {NoopReporter} from '../../src/reporters/index.js'; | ||
import {run as buildRun} from './_helpers.js'; | ||
import {run as audit} from '../../src/cli/commands/audit.js'; | ||
import {promisify} from '../../src/util/promise.js'; | ||
|
||
const path = require('path'); | ||
const zlib = require('zlib'); | ||
const gunzip = promisify(zlib.gunzip); | ||
|
||
const fixturesLoc = path.join(__dirname, '..', 'fixtures', 'audit'); | ||
|
||
const setupMockRequestManager = function(config) { | ||
const apiResponse = JSON.stringify(getAuditResponse(config), null, 2); | ||
// $FlowFixMe | ||
config.requestManager.request = jest.fn(); | ||
config.requestManager.request.mockReturnValue( | ||
new Promise(resolve => { | ||
resolve(apiResponse); | ||
}), | ||
); | ||
}; | ||
|
||
const setupMockReporter = function(reporter) { | ||
// $FlowFixMe | ||
reporter.auditAdvisory = jest.fn(); | ||
// $FlowFixMe | ||
reporter.auditAction = jest.fn(); | ||
// $FlowFixMe | ||
reporter.auditSummary = jest.fn(); | ||
}; | ||
|
||
const getAuditResponse = function(config): Object { | ||
// $FlowFixMe | ||
return require(path.join(config.cwd, 'audit-api-response.json')); | ||
}; | ||
|
||
const runAudit = buildRun.bind( | ||
null, | ||
NoopReporter, | ||
fixturesLoc, | ||
async (args, flags, config, reporter, lockfile, getStdout): Promise<string> => { | ||
setupMockRequestManager(config); | ||
setupMockReporter(reporter); | ||
await audit(config, reporter, flags, args); | ||
return getStdout(); | ||
}, | ||
); | ||
|
||
test.concurrent('sends correct dependency map to audit api for single dependency.', () => { | ||
const expectedApiPost = { | ||
name: 'yarn-test', | ||
install: [], | ||
remove: [], | ||
metadata: {}, | ||
requires: { | ||
minimatch: '^3.0.0', | ||
}, | ||
dependencies: { | ||
minimatch: { | ||
version: '3.0.0', | ||
integrity: 'sha1-UjYVelHk8ATBd/s8Un/33Xjw74M=', | ||
requires: { | ||
'brace-expansion': '^1.0.0', | ||
}, | ||
dependencies: {}, | ||
}, | ||
'brace-expansion': { | ||
version: '1.1.11', | ||
integrity: 'sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==', | ||
requires: { | ||
'balanced-match': '^1.0.0', | ||
'concat-map': '0.0.1', | ||
}, | ||
dependencies: {}, | ||
}, | ||
'balanced-match': { | ||
version: '1.0.0', | ||
integrity: 'sha1-ibTRmasr7kneFk6gK4nORi1xt2c=', | ||
requires: {}, | ||
dependencies: {}, | ||
}, | ||
'concat-map': { | ||
version: '0.0.1', | ||
integrity: 'sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=', | ||
requires: {}, | ||
dependencies: {}, | ||
}, | ||
}, | ||
version: '0.0.0', | ||
}; | ||
|
||
return runAudit([], {}, 'single-vulnerable-dep-installed', 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', () => { | ||
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 temporarily removed due to inability to correctly puggest actions to the user. | ||
// test('calls reporter auditAction with correct data', () => { | ||
// return runAudit([], {}, 'single-vulnerable-dep-installed', (config, reporter) => { | ||
// const apiResponse = getAuditResponse(config); | ||
// expect(reporter.auditAction).toBeCalledWith({ | ||
// cmd: 'yarn upgrade minimatch@3.0.4', | ||
// isBreaking: false, | ||
// action: apiResponse.actions[0], | ||
// }); | ||
// }); | ||
// }); | ||
|
||
test('calls reporter auditSummary with correct data', () => { | ||
return runAudit([], {}, 'single-vulnerable-dep-installed', (config, reporter) => { | ||
const apiResponse = getAuditResponse(config); | ||
expect(reporter.auditSummary).toBeCalledWith(apiResponse.metadata); | ||
}); | ||
}); |
77 changes: 77 additions & 0 deletions
77
__tests__/fixtures/audit/single-vulnerable-dep-installed/audit-api-response.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
__tests__/fixtures/audit/single-vulnerable-dep-installed/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"name": "yarn-test", | ||
"version": "0.0.0", | ||
"dependencies": { | ||
"minimatch": "^3.0.0" | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
__tests__/fixtures/audit/single-vulnerable-dep-installed/yarn.lock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
# yarn lockfile v1 | ||
|
||
|
||
balanced-match@^1.0.0: | ||
version "1.0.0" | ||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" | ||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= | ||
|
||
brace-expansion@^1.0.0: | ||
version "1.1.11" | ||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" | ||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== | ||
dependencies: | ||
balanced-match "^1.0.0" | ||
concat-map "0.0.1" | ||
|
||
concat-map@0.0.1: | ||
version "0.0.1" | ||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | ||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | ||
|
||
minimatch@^3.0.0: | ||
version "3.0.0" | ||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.0.tgz#5236157a51e4f004c177fb3c527ff7dd78f0ef83" | ||
integrity sha1-UjYVelHk8ATBd/s8Un/33Xjw74M= | ||
dependencies: | ||
brace-expansion "^1.0.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.