diff --git a/__tests__/commands/audit.js b/__tests__/commands/audit.js index c796527a2e..63354a12ff 100644 --- a/__tests__/commands/audit.js +++ b/__tests__/commands/audit.js @@ -98,6 +98,20 @@ test.concurrent('sends correct dependency map to audit api for single dependency }); }); +test('calls reporter auditAdvisory when using --level high flag', () => { + return runAudit([], {level: 'high'}, 'single-vulnerable-dep-installed', (config, reporter) => { + const apiResponse = getAuditResponse(config); + expect(reporter.auditAdvisory).toBeCalledWith(apiResponse.actions[0].resolves[0], apiResponse.advisories['118']); + }); +}); + +test(`doesn't call reporter auditAdvisory when using --level critical flag`, () => { + return runAudit([], {level: 'critical'}, 'single-vulnerable-dep-installed', (config, reporter) => { + const apiResponse = getAuditResponse(config); + expect(reporter.auditAdvisory).not.toHaveBeenCalled(); + }); +}); + test('calls reporter auditAdvisory with correct data', () => { return runAudit([], {}, 'single-vulnerable-dep-installed', (config, reporter) => { const apiResponse = getAuditResponse(config); diff --git a/src/cli/commands/audit.js b/src/cli/commands/audit.js index 14c20d4a1f..f11f4c9337 100644 --- a/src/cli/commands/audit.js +++ b/src/cli/commands/audit.js @@ -15,6 +15,10 @@ import {YARN_REGISTRY} from '../../constants'; const zlib = require('zlib'); const gzip = promisify(zlib.gzip); +export type AuditOptions = { + level: ?string, +}; + export type AuditNode = { version: ?string, integrity: ?string, @@ -115,6 +119,11 @@ export type AuditActionRecommendation = { export function setFlags(commander: Object) { commander.description('Checks for known security issues with the installed packages.'); commander.option('--summary', 'Only print the summary.'); + commander.option( + '--level ', + 'Only print advisories with vulnerability severity greater than or equal to one of the following: info|low|moderate|high|critical', + 'info', + ); } export function hasWrapper(commander: Object, args: Array): boolean { @@ -122,7 +131,7 @@ export function hasWrapper(commander: Object, args: Array): boolean { } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { - const audit = new Audit(config, reporter); + const audit = new Audit(config, reporter, {level: flags.level}); const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); const install = new Install({}, config, reporter, lockfile); const {manifest, requests, patterns, workspaceLayout} = await install.fetchRequestFromCwd(); @@ -148,13 +157,17 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg } export default class Audit { - constructor(config: Config, reporter: Reporter) { + severityLevels = ['info', 'low', 'moderate', 'high', 'critical']; + + constructor(config: Config, reporter: Reporter, options?: AuditOptions = {level: 'info'}) { this.config = config; this.reporter = reporter; + this.options = options; } config: Config; reporter: Reporter; + options: AuditOptions; auditData: AuditReport; _mapHoistedNodes(auditNode: AuditNode, hoistedNodes: HoistedTrees) { @@ -268,9 +281,14 @@ export default class Audit { return; } + const startLoggingAt: number = Math.max(0, this.severityLevels.indexOf(this.options.level)); + const reportAdvisory = (resolution: AuditResolution) => { const advisory = this.auditData.advisories[resolution.id.toString()]; - this.reporter.auditAdvisory(resolution, advisory); + + if (this.severityLevels.indexOf(advisory.severity) >= startLoggingAt) { + this.reporter.auditAdvisory(resolution, advisory); + } }; if (Object.keys(this.auditData.advisories).length !== 0) {