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

Commit

Permalink
Issue 32 fix json output compatibility (#38)
Browse files Browse the repository at this point in the history
* Stash changes

* Fixed JSON output with 0 vulnerabilities

* Bumped version

* Fixed output for JSON
  • Loading branch information
InfoSec812 authored May 22, 2019
1 parent 6854b78 commit 0cf541b
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 18 deletions.
2 changes: 1 addition & 1 deletion bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const { exec } = require('child_process');
const { parse_audit_results } = require('../lib/parser');
const { parse_args, validThresholds, check_npm_version } = require('../lib/parse_args');

const { threshold, ignoreDev, json_output, registry, whitelist } = parse_args();
const { threshold, ignoreDev, json_output, registry, whitelist } = parse_args(process.argv);

if (!check_npm_version()) {
console.error('NPM Version does not support npm audit. Install a version >= 6.0.0');
Expand Down
14 changes: 14 additions & 0 deletions jest.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
"testPathIgnorePatterns": [
"<rootDir>/.stryker-tmp/"
],
"testMatch": [
"**/?(*.)+(spec|test).[jt]s?(x)"
],
"reporters": [
"default",
["./node_modules/jest-html-reporter", {
"pageTitle": "Test Report"
}]
]
};
6 changes: 3 additions & 3 deletions lib/parse_args.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

const argv = require( 'argv' );
const argv = require('argv');
const util = require('util');

const exec = util.promisify(require('child_process').exec);
Expand Down Expand Up @@ -80,7 +80,7 @@ async function check_npm_version() {
* Parse CLI arguments and extract configuration for application
* @param {string[]} cli_args
*/
function parse_args(cli_args = process.argv) {
function parse_args(cli_args) {
let args = argv.option( options ).run(cli_args);

// Check to see if this script should ignore dev dependencies
Expand Down Expand Up @@ -111,4 +111,4 @@ module.exports = {
'parse_args': parse_args,
'validThresholds': validThresholds,
'check_npm_version': check_npm_version
}
};
15 changes: 11 additions & 4 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,27 @@ const { validThresholds } = require('./parse_args');
function parse_audit_results(err, stdout, threshold, ignoreDev, json_output = false, whitelist = []) {
let exitCode = 0;
let cli_output = "";
const data = JSON.parse(stdout);
if (err === null) {
cli_output += 'No vulnerabilities found.\n';
if (json_output) {
data['advisories'] = {};
data['actions'] = [];
data['muted'] = [];
cli_output = JSON.stringify(data, null, 2) + "\n";
} else {
cli_output += 'No vulnerabilities found.\n';
}
} else {
let data = JSON.parse(stdout);
let advisories = Object.entries(data.advisories);

let flaggedDepenencies = 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 = data;
var retVal = JSON.parse(JSON.stringify(data));
retVal.advisories = {};
retVal.advisories = flaggedDepenencies;
cli_output = JSON.stringify(retVal) + '\n';
cli_output = JSON.stringify(retVal, null, 2) + '\n';
} else { // If any vulnerabilities exceed the threshold and are not filtered, print the details and fail the build.
if (flaggedDepenencies.length > 0) {
cli_output += 'There are vulnerable dependencies which exceed the selected threshold and scope:\n';
Expand Down
49 changes: 49 additions & 0 deletions lib/parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,48 @@ test('Validate when err is NULL', () => {
expect(exitCode).toBe(0);
});

/*
* When err is NULL, and JSON is requested, expect default JSON output as well
*/
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 expectedOutput = {
"actions": [],
"advisories": {},
"muted": [],
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 0,
"critical": 0
},
"dependencies": 879278,
"devDependencies": 387,
"optionalDependencies": 9709,
"totalDependencies": 889374
},
"runId": "3fdcb3d6-c9f3-4e6f-9e4f-c77d1e0dac86"
}
const actualObject = JSON.parse(cli_output);
expect(actualObject.actions).toEqual([]);
expect(actualObject.advisories).toEqual({});
expect(actualObject.muted).toEqual([]);
expect(actualObject.metadata.vulnerabilities.info).toEqual(0);
expect(actualObject.metadata.vulnerabilities.low).toEqual(0);
expect(actualObject.metadata.vulnerabilities.moderate).toEqual(0);
expect(actualObject.metadata.vulnerabilities.high).toEqual(0);
expect(actualObject.metadata.vulnerabilities.critical).toEqual(0);
expect(actualObject.metadata.dependencies).toBeDefined();
expect(actualObject.metadata.devDependencies).toBeDefined();
expect(actualObject.metadata.optionalDependencies).toBeDefined();
expect(actualObject.metadata.totalDependencies).toBeDefined();
expect(actualObject.runId).toBeDefined();
expect(exitCode).toBe(0);
});

/*
* When there are 0 vulnerable dependencies, expect a 0 exit code
*/
Expand Down Expand Up @@ -61,10 +103,17 @@ test('Validate run with 7 vulnerabilities', () => {
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');
expect(actualObject.metadata.dependencies).toBeDefined();
expect(actualObject.metadata.devDependencies).toBeDefined();
expect(actualObject.metadata.optionalDependencies).toBeDefined();
expect(actualObject.metadata.totalDependencies).toBeDefined();
expect(actualObject.runId).toBeDefined();
expect(exitCode).toBe(0);
});

Expand Down
12 changes: 3 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.2.0",
"version": "2.2.1",
"description": "A wrapper for 'npm audit' which can be configurable for use in a CI/CD tool like Jenkins",
"keywords": [
"npm",
Expand All @@ -17,14 +17,6 @@
"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"
},
"jest": {
"testPathIgnorePatterns": [
"<rootDir>/.stryker-tmp/"
],
"testMatch": [
"**/?(*.)+(spec|test).[jt]s?(x)"
]
},
"author": "Deven Phillips <deven.phillips@redhat.com>",
"repository": {
"type": "git",
Expand All @@ -44,6 +36,8 @@
"@stryker-mutator/jest-runner": "^1.0.2",
"capture-stdout": "^1.0.0",
"jest": "^24.1.0",
"jest-cli": "^24.8.0",
"jest-html-reporter": "^2.5.0",
"stryker-cli": "^1.0.0",
"stryker-jest-runner": "^1.4.1"
}
Expand Down
17 changes: 16 additions & 1 deletion test_data/vue_js_app.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,5 +312,20 @@
},
"url": "https://npmjs.com/advisories/755"
}
}
},
"muted": [],
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 0,
"critical": 0
},
"dependencies": 1,
"devDependencies": 74642,
"optionalDependencies": 396,
"totalDependencies": 74643
},
"runId": "13b24789-ae58-468a-83ff-7eb3faafa8ae"
}

0 comments on commit 0cf541b

Please sign in to comment.