better-npm-audit
Advanced tools
Comparing version 3.7.0 to 3.7.1
{ | ||
"name": "better-npm-audit", | ||
"version": "3.7.0", | ||
"version": "3.7.1", | ||
"author": "Jee Mok <jee.ict@hotmail.com>", | ||
@@ -20,3 +20,3 @@ "description": "Reshape into a better npm audit for the community and encourage more people to include security audit into their process.", | ||
"preaudit": "npm run build", | ||
"audit": "node lib audit -x 1004946,1006897", | ||
"audit": "node lib audit -x 1064843,1067245", | ||
"test": "mocha -r ts-node/register test/**/*.test.ts", | ||
@@ -23,0 +23,0 @@ "lint": "eslint .", |
@@ -9,5 +9,5 @@ # Better NPM Audit | ||
## NPM version 6 and 7 | ||
## NPM version 6 and 7, and 8 | ||
NPM has upgraded to version 7 in late 2020 and has breaking changes on the `npm audit`. The output of npm audit has significantly changed both in the human-readable and `--json` output styles. We have added handling so it works properly in both npm versions. | ||
NPM has upgraded to version 7 in late 2020 and has breaking changes on the `npm audit`. The output of npm audit has significantly changed both in the human-readable and `--json` output styles. Even more unfortunately, when NPM changed the JSON output in npm v7, they removed many of the other useful identifiers (`cves`, `cwe`, `github_advisory_id`) and the only thing left is the URL. We are trying our best to handle each version and provide consistent functionality to all of them. Related docs on v6 and v7 changes: | ||
@@ -108,4 +108,5 @@ | Docs | Link | | ||
}, | ||
"980": "Ignored since we don't use xxx method", | ||
"GHSA-ww39-953v-wcq6": "GHSA ID is acceptable too" | ||
"CWE-471": "CWE ID is acceptable", | ||
"GHSA-ww39-953v-wcq6": "GHSA ID is acceptable", | ||
"https://npmjs.com/advisories/1213": "Full or partial URL is acceptable too" | ||
} | ||
@@ -138,10 +139,7 @@ ``` | ||
## Special mentions | ||
## Contributors | ||
- [@IanWright](https://github.com/IPWright83) for his solutions in improving the vulnerability validation for us to have the minimum-audit-level and production-mode flags. | ||
[Ian Wright](https://github.com/IPWright83), [Edwin Taylor](https://github.com/alertme-edwin), [Maarten Hus](https://github.com/MrHus), [Alex Burkowsky](https://github.com/alexburkowskypolysign), [David M. Lee](https://github.com/leedm777), [Kyle Clark](https://github.com/kyle-clark1824), [Guillermo Pincay](https://github.com/guillermaster), [Grzegorz Pawłowski](https://github.com/GrzesiekP), [CSLTech](https://github.com/CSLTech), [Paul Clarkin](https://github.com/paulclarkin), [mgdodge](https://github.com/mgdodge), [Ricky Sullivan](https://github.com/rickysullivan), [Sam Gregory](https://github.com/samgregory88), [Tristan WAGNER](https://github.com/tristanwagner) | ||
- [@EdwinTaylor](https://github.com/alertme-edwin) for all the bug reports and improvement suggestions. | ||
- [@MrHus](https://github.com/MrHus) for the logging of unused exceptions from the .nsprc file and -ignore flags. Courtesy of 42 BV. | ||
<br /> | ||
@@ -148,0 +146,0 @@ |
@@ -7,10 +7,9 @@ "use strict"; | ||
* Process and analyze the NPM audit JSON | ||
* @param {String} jsonBuffer NPM audit stringified JSON payload | ||
* @param {Number} auditLevel The level of vulnerabilities we care about | ||
* @param {Array} exceptionIds List of vulnerability IDs to exclude | ||
* @param {Array} modulesToIgnore List of vulnerable modules to ignore in audit results | ||
* @return {undefined} | ||
* @param {String} jsonBuffer NPM audit stringified JSON payload | ||
* @param {Number} auditLevel The level of vulnerabilities we care about | ||
* @param {Array} exceptionIds List of vulnerability IDs to exclude | ||
* @param {Array} exceptionModules List of vulnerable modules to ignore in audit results | ||
*/ | ||
function handleFinish(jsonBuffer, auditLevel, exceptionIds, modulesToIgnore) { | ||
var _a = vulnerability_1.processAuditJson(jsonBuffer, auditLevel, exceptionIds, modulesToIgnore), unhandledIds = _a.unhandledIds, vulnerabilityIds = _a.vulnerabilityIds, vulnerabilityModules = _a.vulnerabilityModules, report = _a.report, failed = _a.failed; | ||
function handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules) { | ||
var _a = vulnerability_1.processAuditJson(jsonBuffer, auditLevel, exceptionIds, exceptionModules), unhandledIds = _a.unhandledIds, report = _a.report, failed = _a.failed, unusedExceptionIds = _a.unusedExceptionIds, unusedExceptionModules = _a.unusedExceptionModules; | ||
// If unable to process the audit JSON | ||
@@ -27,16 +26,4 @@ if (failed) { | ||
} | ||
// Grab any un-filtered vulnerabilities at the appropriate level | ||
var unusedExceptionIds = exceptionIds.filter(function (id) { return !vulnerabilityIds.includes(id); }); | ||
var unusedIgnoredModules = modulesToIgnore.filter(function (moduleName) { return !vulnerabilityModules.includes(moduleName); }); | ||
var messages = [ | ||
unusedExceptionIds.length + " of the excluded vulnerabilities did not match any of the found vulnerabilities: " + unusedExceptionIds.join(', ') + ".", | ||
(unusedExceptionIds.length > 1 ? 'They' : 'It') + " can be removed from the .nsprc file or --exclude -x flags.", | ||
]; | ||
// Display the unused exceptionId's | ||
if (unusedExceptionIds.length) { | ||
if (unusedIgnoredModules.length) { | ||
messages.push(unusedIgnoredModules.length + " of the ignored modules did not match any of the found vulnerabilites: " + unusedIgnoredModules.join(', ') + ".", (unusedIgnoredModules.length > 1 ? 'They' : 'It') + " can be removed from the --module-ignore -m flags."); | ||
} | ||
console.warn(messages.join(' ')); | ||
} | ||
// Handle unused exceptions | ||
vulnerability_1.handleUnusedExceptions(unusedExceptionIds, unusedExceptionModules); | ||
// Display the found unhandled vulnerabilities | ||
@@ -43,0 +30,0 @@ if (unhandledIds.length) { |
@@ -11,3 +11,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.processExceptions = exports.getExceptionsIds = exports.processAuditJson = exports.validateV7Vulnerability = exports.validateV6Vulnerability = exports.mapLevelToNumber = void 0; | ||
exports.handleUnusedExceptions = exports.processExceptions = exports.getExceptionsIds = exports.processAuditJson = exports.validateV7Vulnerability = exports.validateV6Vulnerability = exports.mapLevelToNumber = void 0; | ||
var lodash_get_1 = __importDefault(require("lodash.get")); | ||
@@ -45,22 +45,27 @@ var common_1 = require("./common"); | ||
* @param {Array} exceptionIds Exception IDs | ||
* @return {Boolean} If this vulnerability should be ignored | ||
* @return {Object} Validation result | ||
*/ | ||
function validateV6Vulnerability(vulnerability, exceptionIds) { | ||
// check if ID matches | ||
if (exceptionIds.some(function (id) { return id === String(vulnerability.id); })) { | ||
return true; | ||
} | ||
// check if any of the CVEs matches | ||
if (exceptionIds.some(function (id) { return Array.isArray(vulnerability.cves) && vulnerability.cves.includes(id); })) { | ||
return true; | ||
} | ||
// check if the CWE matches | ||
if (exceptionIds.some(function (id) { return vulnerability.cwe === id; })) { | ||
return true; | ||
} | ||
// check if the URL matches | ||
if (exceptionIds.some(function (id) { return vulnerability.url && vulnerability.url.includes(id); })) { | ||
return true; | ||
} | ||
return false; | ||
return exceptionIds.reduce(function (acc, id) { | ||
// check if ID matches | ||
if (id === String(vulnerability.id)) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
// check if any of the CVEs matches | ||
if (Array.isArray(vulnerability.cves) && vulnerability.cves.includes(id)) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
// check if the CWE matches | ||
if (vulnerability.cwe === id) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
// check if the URL matches | ||
if (vulnerability.url && vulnerability.url.includes(id)) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
return acc; | ||
}, { | ||
isExcepted: false, | ||
usedExceptionKey: '', | ||
}); | ||
} | ||
@@ -75,11 +80,16 @@ exports.validateV6Vulnerability = validateV6Vulnerability; | ||
function validateV7Vulnerability(vulnerability, exceptionIds) { | ||
// check if ID matches | ||
if (exceptionIds.some(function (id) { return id === String(vulnerability.source); })) { | ||
return true; | ||
} | ||
// check if the URL matches | ||
if (exceptionIds.some(function (id) { return vulnerability.url && vulnerability.url.includes(id); })) { | ||
return true; | ||
} | ||
return false; | ||
return exceptionIds.reduce(function (acc, id) { | ||
// check if ID matches | ||
if (id === String(vulnerability.source)) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
// check if the URL matches | ||
if (vulnerability.url && vulnerability.url.includes(id)) { | ||
return { isExcepted: true, usedExceptionKey: id }; | ||
} | ||
return acc; | ||
}, { | ||
isExcepted: false, | ||
usedExceptionKey: '', | ||
}); | ||
} | ||
@@ -91,11 +101,11 @@ exports.validateV7Vulnerability = validateV7Vulnerability; | ||
* @param {String} auditLevel User's target audit level | ||
* @param {Array} exceptionIds User's exception IDs | ||
* @param {Array} modulesToIgnore Users modules to ignore | ||
* @param {Array} exceptionIds Exception IDs (ID to be ignored) | ||
* @param {Array} exceptionModules Exception modules (modules to be ignored) | ||
* @return {Object} Processed vulnerabilities details | ||
*/ | ||
function processAuditJson(jsonBuffer, auditLevel, exceptionIds, modulesToIgnore) { | ||
function processAuditJson(jsonBuffer, auditLevel, exceptionIds, exceptionModules) { | ||
if (jsonBuffer === void 0) { jsonBuffer = ''; } | ||
if (auditLevel === void 0) { auditLevel = 'info'; } | ||
if (exceptionIds === void 0) { exceptionIds = []; } | ||
if (modulesToIgnore === void 0) { modulesToIgnore = []; } | ||
if (exceptionModules === void 0) { exceptionModules = []; } | ||
if (!common_1.isJsonString(jsonBuffer)) { | ||
@@ -106,2 +116,4 @@ return { | ||
vulnerabilityModules: [], | ||
unusedExceptionIds: exceptionIds, | ||
unusedExceptionModules: exceptionModules, | ||
report: [], | ||
@@ -119,13 +131,21 @@ failed: true, | ||
var shouldAudit = mapLevelToNumber(cur.severity) >= mapLevelToNumber(auditLevel); | ||
var isExcepted = validateV6Vulnerability(cur, exceptionIds); | ||
var isIgnoredModule = modulesToIgnore.includes(cur.module_name); | ||
var _a = validateV6Vulnerability(cur, exceptionIds), isIdExcepted = _a.isExcepted, usedExceptionKey = _a.usedExceptionKey; | ||
var isModuleExcepted = exceptionModules.includes(cur.module_name); | ||
var isExcepted = isIdExcepted || isModuleExcepted; | ||
// Record used exception ID/module | ||
if (isIdExcepted) { | ||
acc.unusedExceptionIds = acc.unusedExceptionIds.filter(function (id) { return id !== usedExceptionKey; }); | ||
} | ||
if (isModuleExcepted) { | ||
acc.unusedExceptionModules = acc.unusedExceptionModules.filter(function (module) { return module !== cur.module_name; }); | ||
} | ||
// Record this vulnerability into the report, and highlight it using yellow color if it's new | ||
acc.report.push([ | ||
color_1.color(cur.id.toString(), isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(cur.module_name, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(cur.title, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(common_1.trimArray(cur.findings.reduce(function (a, c) { return __spreadArray(__spreadArray([], a), c.paths); }, []), MAX_PATHS_SIZE).join('\n'), isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(cur.severity, isExcepted || isIgnoredModule ? '' : 'yellow', color_1.getSeverityBgColor(cur.severity)), | ||
color_1.color(cur.url, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
isExcepted || isIgnoredModule ? 'y' : color_1.color('n', 'yellow'), | ||
color_1.color(cur.id.toString(), isExcepted ? '' : 'yellow'), | ||
color_1.color(cur.module_name, isExcepted ? '' : 'yellow'), | ||
color_1.color(cur.title, isExcepted ? '' : 'yellow'), | ||
color_1.color(common_1.trimArray(cur.findings.reduce(function (a, c) { return __spreadArray(__spreadArray([], a), c.paths); }, []), MAX_PATHS_SIZE).join('\n'), isExcepted ? '' : 'yellow'), | ||
color_1.color(cur.severity, isExcepted ? '' : 'yellow', color_1.getSeverityBgColor(cur.severity)), | ||
color_1.color(cur.url, isExcepted ? '' : 'yellow'), | ||
isExcepted ? 'y' : color_1.color('n', 'yellow'), | ||
]); | ||
@@ -137,3 +157,3 @@ acc.vulnerabilityIds.push(cur.id.toString()); | ||
// Found unhandled vulnerabilities | ||
if (shouldAudit && !isExcepted && !isIgnoredModule) { | ||
if (shouldAudit && !isExcepted) { | ||
acc.unhandledIds.push(cur.id.toString()); | ||
@@ -146,2 +166,4 @@ } | ||
vulnerabilityModules: [], | ||
unusedExceptionIds: exceptionIds, | ||
unusedExceptionModules: exceptionModules, | ||
report: [], | ||
@@ -163,13 +185,21 @@ }); | ||
var shouldAudit = mapLevelToNumber(vul.severity) >= mapLevelToNumber(auditLevel); | ||
var isExcepted = validateV7Vulnerability(vul, exceptionIds); | ||
var isIgnoredModule = modulesToIgnore.includes(moduleName); | ||
var _a = validateV7Vulnerability(vul, exceptionIds), isIdExcepted = _a.isExcepted, usedExceptionKey = _a.usedExceptionKey; | ||
var isModuleExcepted = exceptionModules.includes(moduleName); | ||
var isExcepted = isIdExcepted || isModuleExcepted; | ||
// Record used exception ID/module | ||
if (isIdExcepted) { | ||
acc.unusedExceptionIds = acc.unusedExceptionIds.filter(function (id) { return id !== usedExceptionKey; }); | ||
} | ||
if (isModuleExcepted) { | ||
acc.unusedExceptionModules = acc.unusedExceptionModules.filter(function (module) { return module !== moduleName; }); | ||
} | ||
// Record this vulnerability into the report, and highlight it using yellow color if it's new | ||
acc.report.push([ | ||
color_1.color(String(id), isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(vul.name, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(vul.title, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(common_1.trimArray(lodash_get_1.default(cur, 'nodes', []).map(common_1.shortenNodePath), MAX_PATHS_SIZE).join('\n'), isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
color_1.color(vul.severity, isExcepted || isIgnoredModule ? '' : 'yellow', color_1.getSeverityBgColor(vul.severity)), | ||
color_1.color(vul.url, isExcepted || isIgnoredModule ? '' : 'yellow'), | ||
isExcepted || isIgnoredModule ? 'y' : color_1.color('n', 'yellow'), | ||
color_1.color(String(id), isExcepted ? '' : 'yellow'), | ||
color_1.color(vul.name, isExcepted ? '' : 'yellow'), | ||
color_1.color(vul.title, isExcepted ? '' : 'yellow'), | ||
color_1.color(common_1.trimArray(lodash_get_1.default(cur, 'nodes', []).map(common_1.shortenNodePath), MAX_PATHS_SIZE).join('\n'), isExcepted ? '' : 'yellow'), | ||
color_1.color(vul.severity, isExcepted ? '' : 'yellow', color_1.getSeverityBgColor(vul.severity)), | ||
color_1.color(vul.url, isExcepted ? '' : 'yellow'), | ||
isExcepted ? 'y' : color_1.color('n', 'yellow'), | ||
]); | ||
@@ -181,4 +211,4 @@ acc.vulnerabilityIds.push(String(id)); | ||
// Found unhandled vulnerabilities | ||
if (shouldAudit && !isExcepted && !isIgnoredModule) { | ||
acc.unhandledIds.push(id); | ||
if (shouldAudit && !isExcepted) { | ||
acc.unhandledIds.push(String(id)); | ||
} | ||
@@ -191,2 +221,4 @@ }); | ||
vulnerabilityModules: [], | ||
unusedExceptionIds: exceptionIds, | ||
unusedExceptionModules: exceptionModules, | ||
report: [], | ||
@@ -199,2 +231,4 @@ }); | ||
vulnerabilityModules: [], | ||
unusedExceptionIds: exceptionIds, | ||
unusedExceptionModules: exceptionModules, | ||
report: [], | ||
@@ -273,1 +307,24 @@ failed: true, | ||
exports.processExceptions = processExceptions; | ||
/** | ||
* Handle unused exceptions from user: console log them | ||
* @param {Array} unusedExceptionIds List of unused exception IDs | ||
* @param {Array} unusedExceptionModules List of unused exception module names | ||
*/ | ||
function handleUnusedExceptions(unusedExceptionIds, unusedExceptionModules) { | ||
var message = [ | ||
unusedExceptionIds.length && | ||
unusedExceptionIds.length + " of the excluded vulnerabilities did not match any of the found vulnerabilities: " + unusedExceptionIds.join(', ') + ".", | ||
unusedExceptionIds.length && | ||
(unusedExceptionIds.length > 1 ? 'They' : 'It') + " can be removed from the .nsprc file or --exclude -x flags.", | ||
unusedExceptionModules.length && | ||
unusedExceptionModules.length + " of the ignored modules did not match any of the found vulnerabilities: " + unusedExceptionModules.join(', ') + ".", | ||
unusedExceptionModules.length && | ||
(unusedExceptionModules.length > 1 ? 'They' : 'It') + " can be removed from the --module-ignore -m flags.", | ||
] | ||
.filter(Boolean) | ||
.join(' '); | ||
if (message) { | ||
console.warn(message); | ||
} | ||
} | ||
exports.handleUnusedExceptions = handleUnusedExceptions; |
40638
737
149