Skip to content

Commit 0f05203

Browse files
antrewarcanis
authored andcommitted
Return semantic exit code for audit (#6819)
1 parent f3fb110 commit 0f05203

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa
2828

2929
[#6712](https://github.com/yarnpkg/yarn/pull/6712) - [**Maël Nison**](https://twitter.com/arcanis)
3030

31+
- Fixes yarn audit exit code overflow
32+
33+
[#6748](https://github.com/yarnpkg/yarn/issues/6748) - [**Andrey Vetlugin**](https://github.com/antrew)
34+
3135
- Stops automatically unplugging packages with postinstall script when running under `--ignore-scripts`
3236

3337
[#6820](https://github.com/yarnpkg/yarn/pull/6820) - [**Maël Nison**](https://twitter.com/arcanis)

__tests__/commands/audit.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import {NoopReporter} from '../../src/reporters/index.js';
44
import {run as buildRun} from './_helpers.js';
5+
import * as auditModule from '../../src/cli/commands/audit.js';
56
import {run as audit} from '../../src/cli/commands/audit.js';
67
import {promisify} from '../../src/util/promise.js';
8+
import * as lockfileModule from '../../src/lockfile/index.js';
9+
import * as installModule from '../../src/cli/commands/install.js';
710

811
const path = require('path');
912
const zlib = require('zlib');
@@ -163,6 +166,47 @@ test('calls reporter auditSummary with correct data for private package', () =>
163166
});
164167
});
165168

169+
describe('returns semantic exit codes', () => {
170+
beforeAll(() => {
171+
// mock unrelated stuff
172+
jest.spyOn(lockfileModule.default, 'fromDirectory').mockImplementation(jest.fn());
173+
jest.spyOn(installModule, 'Install').mockImplementation(() => {
174+
return {
175+
fetchRequestFromCwd: jest.fn(() => {
176+
return {};
177+
}),
178+
resolver: {
179+
init: jest.fn(),
180+
},
181+
linker: {
182+
init: jest.fn(),
183+
},
184+
};
185+
});
186+
});
187+
188+
const exitCodeTestCases = [
189+
[0, {}, 'zero when no vulnerabilities'],
190+
[1, {info: 77}, '1 for info'],
191+
[2, {low: 77}, '2 for low'],
192+
[4, {moderate: 77}, '4 for moderate'],
193+
[8, {high: 77}, '8 for high'],
194+
[16, {critical: 77}, '16 for critical'],
195+
[17, {info: 55, critical: 77}, 'different categories sum up'],
196+
];
197+
exitCodeTestCases.forEach(([expectedExitCode, foundVulnerabilities, description]) => {
198+
test(description, async () => {
199+
jest.spyOn(auditModule.default.prototype, 'performAudit').mockImplementation(() => {
200+
return foundVulnerabilities;
201+
});
202+
const configMock: any = {};
203+
const reporterMock: any = {};
204+
const exitCode = await audit(configMock, reporterMock, {}, []);
205+
expect(exitCode).toEqual(expectedExitCode);
206+
});
207+
});
208+
});
209+
166210
test.concurrent('sends correct dependency map to audit api for workspaces.', () => {
167211
const expectedApiPost = {
168212
dependencies: {

src/cli/commands/audit.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,27 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
131131
});
132132

133133
const vulnerabilities = await audit.performAudit(manifest, install.resolver, install.linker, patterns);
134-
const totalVulnerabilities =
135-
vulnerabilities.info +
136-
vulnerabilities.low +
137-
vulnerabilities.moderate +
138-
vulnerabilities.high +
139-
vulnerabilities.critical;
134+
135+
const EXIT_INFO = 1;
136+
const EXIT_LOW = 2;
137+
const EXIT_MODERATE = 4;
138+
const EXIT_HIGH = 8;
139+
const EXIT_CRITICAL = 16;
140+
141+
const exitCode =
142+
(vulnerabilities.info ? EXIT_INFO : 0) +
143+
(vulnerabilities.low ? EXIT_LOW : 0) +
144+
(vulnerabilities.moderate ? EXIT_MODERATE : 0) +
145+
(vulnerabilities.high ? EXIT_HIGH : 0) +
146+
(vulnerabilities.critical ? EXIT_CRITICAL : 0);
140147

141148
if (flags.summary) {
142149
audit.summary();
143150
} else {
144151
audit.report();
145152
}
146153

147-
return totalVulnerabilities;
154+
return exitCode;
148155
}
149156

150157
export default class Audit {

0 commit comments

Comments
 (0)