Skip to content
This repository has been archived by the owner on Feb 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #42 from InfoSec812/Issue_41-_-Fix_issues_with_lar…
Browse files Browse the repository at this point in the history
…ge_audit_data_response

Issue 41: Fix issues with large audit data response
  • Loading branch information
InfoSec812 authored Oct 23, 2019
2 parents f38c6e9 + 9b6907f commit 9113ae6
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 63 deletions.
53 changes: 38 additions & 15 deletions bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
/**
* Copyright [2018] [Joseph B. Phillips]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const { exec } = require('child_process');
const { exec, spawn } = require('child_process');
const { parse_audit_results } = require('../lib/parser');
const { parse_args, validThresholds, check_npm_version } = require('../lib/parse_args');

Expand All @@ -33,15 +33,38 @@ if (threshold === -1) {
}

// Build the npm audit command
command = 'npm audit --json'
if( registry !== null ) {
command += ' --registry=' + registry
var command = 'npm';
var command_args = ['audit', '--json'];
if ( registry !== null ) {
command_args.push(' --registry=' + registry);
}

var stdout = '';
var stderr = '';

const audit_proc = spawn(command, command_args, { stdio: ['ignore', 'pipe', 'pipe'], detached: false });

audit_proc.stdout.on('data', (data) => {
var holder = stdout;
stdout = holder.concat(data);
});

audit_proc.stderr.on('data', (data) => {
var holder = stderr;
stderr = holder.concat(data);
});

audit_proc.on('close', (exit_code) => {
const { exitCode, cliOutput } = parse_audit_results(stderr, stdout, threshold, ignoreDev, json_output, whitelist);
console.log(cliOutput);
process.exit(exitCode);
});

//
// Execute and capture the output for processing
exec(command, {maxBuffer: 500 * 1024}, (err, stdout, stderr) => {
const { exitCode, cli_output } = parse_audit_results(err, stdout, threshold, ignoreDev, json_output, whitelist);
console.log(cli_output);
process.exit(exitCode);
});
// exec(command, {maxBuffer: 5000 * 1024}, (err, stdout, stderr) => {
// const { exitCode, cli_output } = parse_audit_results(err, stdout, threshold, ignoreDev, json_output, whitelist);
// console.log(cli_output);
// process.exit(exitCode);
// });

32 changes: 16 additions & 16 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,49 +24,50 @@ const { validThresholds } = require('./parse_args');
* @param {string} stdout The output from the command provided to `exec`
* @param {number} threshold The severity threshold to filter on
* @param {boolean} ignoreDev Boolean which determines if dev dependencies should be considered
* @returns {object} A tuple of the exitCode and cliOutput
*/
function parse_audit_results(err, stdout, threshold, ignoreDev, json_output = false, whitelist = []) {
let exitCode = 0;
let cli_output = "";
let cliOutput = "";
const data = JSON.parse(stdout);
if (err === null) {
if (json_output) {
data['advisories'] = {};
data['actions'] = [];
data['muted'] = [];
cli_output = JSON.stringify(data, null, 2) + "\n";
cliOutput = JSON.stringify(data, null, 2) + "\n";
} else {
cli_output += 'No vulnerabilities found.\n';
cliOutput += 'No vulnerabilities found.\n';
}
} else {
let advisories = Object.entries(data.advisories);

let flaggedDepenencies = filter_advisories(advisories, ignoreDev, threshold, whitelist);
let flaggedDependencies = filter_advisories(advisories, ignoreDev, threshold, whitelist);

// If `-j` or `--json` passed, return the json data with the appropriate filters applied
if (json_output) {
var retVal = JSON.parse(JSON.stringify(data));
retVal.advisories = {};
retVal.advisories = flaggedDepenencies;
cli_output = JSON.stringify(retVal, null, 2) + '\n';
} else if (flaggedDepenencies.length > 0) {
retVal.advisories = flaggedDependencies;
cliOutput = JSON.stringify(retVal, null, 2) + '\n';
} else if (flaggedDependencies.length > 0) {
// If any vulnerabilities exceed the threshold and are not filtered, print the details and fail the build.

cli_output += ignoreDev ? (
cliOutput += ignoreDev ? (
"The following production vulnerabilities "
) : (
"The following vulnerabilities "
)
);

cli_output += "are " + validThresholds[threshold] + " severity or higher:\n"
cliOutput += "are " + validThresholds[threshold] + " severity or higher:\n"

exitCode = 1;

const flagTable = new Table({
head: ["module", "severity", "overview"]
})
});

flaggedDepenencies.forEach((advisory) => { // Print out dependencies which exceed the threshold
flaggedDependencies.forEach((advisory) => { // Print out dependencies which exceed the threshold
let libraryName = advisory[1].module_name;
let libraryVersion = advisory[1].findings[0].version;
let advisoryOverview = 'https://www.npmjs.com/advisories/' + advisory[0];
Expand All @@ -78,11 +79,10 @@ function parse_audit_results(err, stdout, threshold, ignoreDev, json_output = fa
])
});

cli_output += flagTable.toString() + "\n"
cliOutput += flagTable.toString() + "\n"
}
}

return { exitCode, cli_output };
return { exitCode, cliOutput };
}

/**
Expand All @@ -91,7 +91,7 @@ function parse_audit_results(err, stdout, threshold, ignoreDev, json_output = fa
* @param {boolean} ignoreDev Should dev dependencies be ignored?
* @param {number} threshold The severity threshold above which a vulnerability will not be ignored
* @param {string[]} whitelist A (possibly empty) list of modules/versions which should be ignored
* @returns An array (posssibly empty) of advisory objects
* @returns An array (possibly empty) of advisory objects
*/
function filter_advisories(advisories, ignoreDev, threshold, whitelist = []) {
const filteredByThreshold = advisories.filter((advisory, idx) => {
Expand Down
45 changes: 22 additions & 23 deletions lib/parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const CRIT_THRESHOLD = 3;
*/
test('Validate when err is NULL', () => {
const test_data = readFileSync('test_data/zero_vulnerabilities.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results(null, test_data, LOW_THRESHOLD, false);
expect(cli_output).toBe('No vulnerabilities found.\n');
let { exitCode, cliOutput } = parse_audit_results(null, test_data, LOW_THRESHOLD, false);
expect(cliOutput).toBe('No vulnerabilities found.\n');
expect(exitCode).toBe(0);
});

Expand All @@ -37,7 +37,7 @@ test('Validate when err is NULL', () => {
*/
test('Validate when err is NULL and JSON output is desired', () => {
const test_data = readFileSync('test_data/zero_vulnerabilities.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results(null, test_data, LOW_THRESHOLD, false, true);
const { exitCode, cliOutput } = parse_audit_results(null, test_data, LOW_THRESHOLD, false, true);
const expectedOutput = {
"actions": [],
"advisories": {},
Expand All @@ -57,7 +57,7 @@ test('Validate when err is NULL and JSON output is desired', () => {
},
"runId": "3fdcb3d6-c9f3-4e6f-9e4f-c77d1e0dac86"
}
const actualObject = JSON.parse(cli_output);
const actualObject = JSON.parse(cliOutput);
expect(actualObject.actions).toEqual([]);
expect(actualObject.advisories).toEqual({});
expect(actualObject.muted).toEqual([]);
Expand All @@ -79,8 +79,8 @@ test('Validate when err is NULL and JSON output is desired', () => {
*/
test('Validate run with 0 vulnerabilities', () => {
const test_data = readFileSync('test_data/zero_vulnerabilities.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results("", test_data, LOW_THRESHOLD, false);
expect(cli_output).toBe('');
let { exitCode, cliOutput } = parse_audit_results("", test_data, LOW_THRESHOLD, false);
expect(cliOutput).toBe('');
expect(exitCode).toBe(0);
});

Expand All @@ -90,11 +90,11 @@ test('Validate run with 0 vulnerabilities', () => {
*/
test('Validate run with 7 vulnerabilities', () => {
const test_data = readFileSync('test_data/vue_js_app.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results("", test_data, LOW_THRESHOLD, false);
expect(cli_output).not.toContain('{');
expect(cli_output).toContain("growl");
expect(cli_output).toContain('https://www.npmjs.com/advisories/');
expect(cli_output).toContain('The following vulnerabilities are low severity or higher:');
let { exitCode, cliOutput } = parse_audit_results("", test_data, LOW_THRESHOLD, false);
expect(cliOutput).not.toContain('{');
expect(cliOutput).toContain("growl");
expect(cliOutput).toContain('https://www.npmjs.com/advisories/');
expect(cliOutput).toContain('The following vulnerabilities are low severity or higher:');
expect(exitCode).toBe(1);
});

Expand All @@ -104,11 +104,11 @@ test('Validate run with 7 vulnerabilities', () => {
*/
test('Validate run with 7 vulnerabilities, a high severity cutoff, and production-only', () => {
const test_data = readFileSync('test_data/vue_js_app.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results("", test_data, HIGH_THRESHOLD, true);
expect(cli_output).not.toContain('{');
expect(cli_output).toContain("[email protected]");
expect(cli_output).toContain('https://www.npmjs.com/advisories/');
expect(cli_output).toContain('The following production vulnerabilities are high severity or higher:');
let { exitCode, cliOutput } = parse_audit_results("", test_data, HIGH_THRESHOLD, true);
expect(cliOutput).not.toContain('{');
expect(cliOutput).toContain("[email protected]");
expect(cliOutput).toContain('https://www.npmjs.com/advisories/');
expect(cliOutput).toContain('The following production vulnerabilities are high severity or higher:');
expect(exitCode).toBe(1);
});

Expand All @@ -117,13 +117,12 @@ test('Validate run with 7 vulnerabilities, a high severity cutoff, and productio
*/
test('Validate run with 7 vulnerabilities and JSON output', () => {
const test_data = readFileSync('test_data/vue_js_app.json', 'utf8');
let { exitCode, cli_output } = parse_audit_results("", test_data, LOW_THRESHOLD, true, true);
const actualObject = JSON.parse(cli_output);
console.log(cli_output+"\n\n");
expect(cli_output).toContain('"https-proxy-agent"');
expect(cli_output).toContain('"version"');
expect(cli_output).toContain('"module_name"');
expect(cli_output.substring((cli_output.length - 1), cli_output.length)).toBe('\n');
let { exitCode, cliOutput } = parse_audit_results("", test_data, LOW_THRESHOLD, true, true);
const actualObject = JSON.parse(cliOutput);
expect(cliOutput).toContain('"https-proxy-agent"');
expect(cliOutput).toContain('"version"');
expect(cliOutput).toContain('"module_name"');
expect(cliOutput.substring((cliOutput.length - 1), cliOutput.length)).toBe('\n');
expect(actualObject.metadata.dependencies).toBeDefined();
expect(actualObject.metadata.devDependencies).toBeDefined();
expect(actualObject.metadata.optionalDependencies).toBeDefined();
Expand Down
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "npm-audit-ci-wrapper",
"version": "2.3.0",
"version": "2.4.0",
"description": "A wrapper for 'npm audit' which can be configurable for use in a CI/CD tool like Jenkins",
"keywords": [
"npm",
Expand All @@ -13,6 +13,7 @@
],
"main": "index.js",
"scripts": {
"audit": "node bin/index.js -t low",
"test": "jest --collect-coverage",
"sonar": "sonar-scanner -Dsonar.host.url=https://sonarcloud.io/ -Dsonar.login=$(cat ~/.sonar_token) -Dsonar.projectVersion=$npm_package_version",
"stryker": "node_modules/stryker-cli/bin/stryker-cli run"
Expand All @@ -24,21 +25,21 @@
},
"license": "Apache-2.0",
"dependencies": {
"argv": "0.0.2",
"argv": "^0.0.2",
"cli-table": "^0.3.1"
},
"bin": {
"npm-audit-ci-wrapper": "./bin/index.js"
},
"devDependencies": {
"@stryker-mutator/core": "^1.0.2",
"@stryker-mutator/html-reporter": "^1.0.2",
"@stryker-mutator/javascript-mutator": "^1.0.2",
"@stryker-mutator/jest-runner": "^1.0.2",
"@stryker-mutator/core": "^2.1.0",
"@stryker-mutator/html-reporter": "^2.1.0",
"@stryker-mutator/javascript-mutator": "^2.1.0",
"@stryker-mutator/jest-runner": "^2.1.0",
"capture-stdout": "^1.0.0",
"jest": "^24.1.0",
"jest-cli": "^24.8.0",
"jest-html-reporter": "^2.5.0",
"jest": "^24.9.0",
"jest-cli": "^24.9.0",
"jest-html-reporter": "^2.6.2",
"stryker-cli": "^1.0.0",
"stryker-jest-runner": "^1.4.1"
}
Expand Down

0 comments on commit 9113ae6

Please sign in to comment.