feat: add the ability to run with '--json' and output the result (#78)

* addition-of-json-flag

* Set output of npn audit
This commit is contained in:
sgkiokas
2020-12-12 13:56:05 +02:00
committed by GitHub
parent 3868af0215
commit c4cd169835
8 changed files with 133 additions and 10 deletions

View File

@@ -24,6 +24,7 @@ If vulnerabilities are found by `npm audit`, Action triggered by push, schedule
|:--:|:--:|:--:|:--|
|audit_level|false|low|The value of `--audit-level` flag|
|production_flag|false|false|Runnning `npm audit` with `--production`|
|json_flag|false|false|Runnning `npm audit` with `--json`|
|issue_assignees|false|N/A|Issue assignees (separated by commma)|
|issue_labels|false|N/A|Issue labels (separated by commma)|
|issue_title|false|npm audit found vulnerabilities|Issue title|
@@ -33,7 +34,9 @@ If vulnerabilities are found by `npm audit`, Action triggered by push, schedule
### Outputs
N/A
|Parameter name|Description|
|:--:|:--|
|npm_audit|The output of the npm audit report in a text format|
## Example Workflow

View File

@@ -30,7 +30,7 @@ describe('run', () => {
}
})
audit.run('low', 'false')
audit.run('low', 'false', 'false')
expect(audit.foundVulnerability()).toBeTruthy()
})
@@ -51,7 +51,28 @@ describe('run', () => {
}
})
audit.run('low', 'true')
audit.run('low', 'true', 'false')
expect(audit.foundVulnerability()).toBeTruthy()
})
test('finds vulnerabilities with json flag enabled', () => {
mocked(child_process).spawnSync.mockImplementation((): any => {
const stdout = fs.readFileSync(
path.join(__dirname, 'testdata/audit/error.json')
)
return {
pid: 100,
output: [stdout],
stdout,
stderr: '',
status: 1,
signal: null,
error: null
}
})
audit.run('low', 'false', 'true')
expect(audit.foundVulnerability()).toBeTruthy()
})
@@ -72,7 +93,7 @@ describe('run', () => {
}
})
audit.run('low', 'false')
audit.run('low', 'false', 'false')
expect(audit.foundVulnerability()).toBeFalsy()
})
@@ -91,7 +112,7 @@ describe('run', () => {
expect.assertions(1)
const e = new Error('Something is wrong')
expect(() => audit.run('low', 'false')).toThrowError(e)
expect(() => audit.run('low', 'false', 'false')).toThrowError(e)
})
test('throws an error if status is null', () => {
@@ -109,7 +130,7 @@ describe('run', () => {
expect.assertions(1)
const e = new Error('the subprocess terminated due to a signal.')
expect(() => audit.run('low', 'false')).toThrowError(e)
expect(() => audit.run('low', 'false', 'false')).toThrowError(e)
})
test('throws an error if stderr is null', () => {
@@ -127,6 +148,6 @@ describe('run', () => {
expect.assertions(1)
const e = new Error('Something is wrong')
expect(() => audit.run('low', 'false')).toThrowError(e)
expect(() => audit.run('low', 'false', 'false')).toThrowError(e)
})
})

View File

@@ -16,6 +16,7 @@ describe('run', () => {
process.env.INPUT_AUDIT_LEVEL = 'low'
process.env.INPUT_PRODUCTION_FLAG = 'false'
process.env.INPUT_JSON_FLAG = 'false'
process.env.INPUT_GITHUB_CONTEXT =
'{ "event_name": "pull_request", "event": { "number": 100} }'
process.env.INPUT_GITHUB_TOKEN = '***'

73
__tests__/testdata/audit/error.json vendored Normal file
View File

@@ -0,0 +1,73 @@
{
"actions": [
{
"isMajor": false,
"action": "install",
"resolves": [
{
"id": 532,
"path": "moment",
"dev": false,
"optional": false,
"bundled": false
}
],
"module": "moment",
"target": "2.29.1"
}
],
"advisories": {
"532": {
"findings": [
{
"version": "2.19.2",
"paths": [
"moment"
]
}
],
"id": 532,
"created": "2017-09-21T20:40:00.889Z",
"updated": "2019-06-24T15:10:05.868Z",
"deleted": null,
"title": "Regular Expression Denial of Service",
"found_by": {
"name": "Cristian-Alexandru Staicu"
},
"reported_by": {
"name": "Cristian-Alexandru Staicu"
},
"module_name": "moment",
"cves": [],
"vulnerable_versions": "<2.19.3",
"patched_versions": ">=2.19.3",
"overview": "Affected versions of `moment` are vulnerable to a low severity regular expression denial of service when parsing dates as strings.",
"recommendation": "Update to version 2.19.3 or later.",
"references": "- [Issue #4163](https://github.com/moment/moment/issues/4163)\n- [PR #4326](https://github.com/moment/moment/pull/4326)",
"access": "public",
"severity": "low",
"cwe": "CWE-400",
"metadata": {
"module_type": "",
"exploitability": 5,
"affected_components": ""
},
"url": "https://npmjs.com/advisories/532"
}
},
"muted": [],
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 7,
"moderate": 1,
"high": 5,
"critical": 0
},
"dependencies": 659,
"devDependencies": 0,
"optionalDependencies": 0,
"totalDependencies": 659
},
"runId": "88c86b12-b4a4-4827-9d3c-d58ae74384c5"
}

View File

@@ -10,6 +10,10 @@ inputs:
description: 'Run npm audit with --production'
default: 'false'
required: false
json_flag:
description: 'Run npm audit with --json'
default: 'false'
required: false
github_context:
description: 'The `github` context'
default: ${{ toJson(github) }}
@@ -34,6 +38,9 @@ inputs:
description: 'Flag to de-dupe against open issues'
default: 'false'
required: false
outputs:
npm_audit:
description: 'The output of the npm audit report in a text format'
runs:
using: 'node12'
main: 'dist/index.js'

9
dist/index.js vendored
View File

@@ -556,12 +556,15 @@ class Audit {
this.stdout = '';
this.status = null;
}
run(auditLevel, productionFlag) {
run(auditLevel, productionFlag, jsonFlag) {
try {
const auditOptions = ['audit', '--audit-level', auditLevel];
if (productionFlag === 'true') {
auditOptions.push('--production');
}
if (jsonFlag === 'true') {
auditOptions.push('--json');
}
const result = child_process_1.spawnSync('npm', auditOptions, {
encoding: 'utf-8',
maxBuffer: SPAWN_PROCESS_BUFFER_SIZE
@@ -1435,6 +1438,10 @@ function run() {
if (!['true', 'false'].includes(productionFlag)) {
throw new Error('Invalid input: production_flag');
}
const jsonFlag = core.getInput('json_flag', { required: false });
if (!['true', 'false'].includes(jsonFlag)) {
throw new Error('Invalid input: json_flag');
}
// run `npm audit`
const audit = new audit_1.Audit();
audit.run(auditLevel, productionFlag);

View File

@@ -7,7 +7,7 @@ export class Audit {
stdout = ''
private status: number | null = null
public run(auditLevel: string, productionFlag: string): void {
public run(auditLevel: string, productionFlag: string, jsonFlag: string): void {
try {
const auditOptions: Array<string> = ['audit', '--audit-level', auditLevel]
@@ -15,6 +15,10 @@ export class Audit {
auditOptions.push('--production')
}
if (jsonFlag === 'true') {
auditOptions.push('--json')
}
const result: SpawnSyncReturns<string> = spawnSync('npm', auditOptions, {
encoding: 'utf-8',
maxBuffer: SPAWN_PROCESS_BUFFER_SIZE

View File

@@ -30,10 +30,17 @@ export async function run(): Promise<void> {
throw new Error('Invalid input: production_flag')
}
const jsonFlag = core.getInput('json_flag', {required: false})
if (!['true', 'false'].includes(jsonFlag)) {
throw new Error('Invalid input: json_flag')
}
// run `npm audit`
const audit = new Audit()
audit.run(auditLevel, productionFlag)
audit.run(auditLevel, productionFlag, jsonFlag)
core.info(audit.stdout)
core.setOutput('npm_audit', audit.stdout);
if (audit.foundVulnerability()) {
// vulnerabilities are found