Skip to content

Commit

Permalink
Add mute option to yarn audit
Browse files Browse the repository at this point in the history
The mute option allows a user to mute advisories that are not fixable,
or not relevant to the project

Fixes yarnpkg#6669
  • Loading branch information
stephane-arista committed Jul 8, 2020
1 parent ac21dbf commit 664266d
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 2 deletions.
52 changes: 50 additions & 2 deletions src/cli/commands/audit.js
Expand Up @@ -19,6 +19,7 @@ const gzip = promisify(zlib.gzip);
export type AuditOptions = {
groups: Array<string>,
level?: string,
muteIssues?: string[],
};

export type AuditNode = {
Expand Down Expand Up @@ -134,6 +135,11 @@ export function setFlags(commander: Object) {
info|low|moderate|high|critical. Default: info`,
'info',
);
commander.option(
'--mute <advisory> [<advisory> ...]',
`Mute any of the specified advisory ids`,
muteIssues => muteIssues && muteIssues.split(','),
);
}

export function hasWrapper(commander: Object, args: Array<string>): boolean {
Expand All @@ -145,6 +151,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
const audit = new Audit(config, reporter, {
groups: flags.groups || OWNED_DEPENDENCY_TYPES,
level: flags.level || DEFAULT_LOG_LEVEL,
muteIssues: flags.mute,
});
const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter);
const install = new Install({}, config, reporter, lockfile);
Expand Down Expand Up @@ -260,8 +267,45 @@ export default class Audit {
if (!responseJson.metadata) {
throw new Error(`Unexpected audit response (Missing Metadata): ${JSON.stringify(responseJson, null, 2)}`);
}
this.reporter.verbose(`Audit Response: ${JSON.stringify(responseJson, null, 2)}`);
return responseJson;
const filteredResponse = responseJson;
if (this.options.muteIssues && this.options.muteIssues.length) {
const newAdvisories = {};
const newActions = [];
const newMuted = [];
const newVulnerabilities = Object.assign({}, responseJson.metadata.vulnerabilities);
for (const [key, value] of Object.entries(responseJson.advisories)) {
if (this.options.muteIssues && this.options.muteIssues.includes(key)) {
newMuted.push(value);
responseJson.actions.forEach(action => {
const newResolves = action.resolves.filter(resolve => {
if (key == resolve.id.toString() && value && value.severity) {
newVulnerabilities[value.severity] -= 1;
return false;
}
return true;
});
if (newResolves.length) {
newActions.push({
action: action.action,
module: action.module,
resolves: newResolves,
});
}
});
} else {
newAdvisories[key] = value;
}
}
Object.assign(filteredResponse, responseJson, {
muted: newMuted,
advisories: newAdvisories,
actions: newActions,
metadata: Object.assign(responseJson.metadata, {vulnerabilities: newVulnerabilities}),
});
}
this.reporter.verbose(`Audit Response: ${JSON.stringify(filteredResponse, null, 2)}`);

return filteredResponse;
}

_insertWorkspacePackagesIntoManifest(manifest: Object, resolver: PackageResolver) {
Expand Down Expand Up @@ -309,6 +353,9 @@ export default class Audit {

const reportAdvisory = (resolution: AuditResolution) => {
const advisory = this.auditData.advisories[resolution.id.toString()];
if (!advisory) {
return;
}

if (this.severityLevels.indexOf(advisory.severity) >= startLoggingAt) {
this.reporter.auditAdvisory(resolution, advisory);
Expand Down Expand Up @@ -349,5 +396,6 @@ export default class Audit {
}

this.summary();
this.reporter.auditMute(this.auditData.muted);
}
}
3 changes: 3 additions & 0 deletions src/reporters/base-reporter.js
Expand Up @@ -240,6 +240,9 @@ export default class BaseReporter {
// summary for security audit report
auditSummary(auditMetadata: AuditMetadata) {}

// mutted advisories for security audit report
auditMute(mutedAdvisories: AuditAdvisory[]) {}

// render an activity spinner and return a function that will trigger an update
activity(): ReporterSpinner {
return {
Expand Down
9 changes: 9 additions & 0 deletions src/reporters/console/console-reporter.js
Expand Up @@ -516,6 +516,15 @@ export default class ConsoleReporter extends BaseReporter {
}
}

auditMute(mutedAdvisories: AuditAdvisory[]) {
const message = this.lang(
'auditMute',
this.rawText(chalk.yellow(mutedAdvisories.length.toString())),
this.rawText(mutedAdvisories.map(advisory => advisory.id).join(', ')),
);
this._log(message);
}

auditAction(recommendation: AuditActionRecommendation) {
const label = recommendation.action.resolves.length === 1 ? 'vulnerability' : 'vulnerabilities';
this._log(
Expand Down
4 changes: 4 additions & 0 deletions src/reporters/json-reporter.js
Expand Up @@ -173,4 +173,8 @@ export default class JSONReporter extends BaseReporter {
auditSummary(auditMetadata: AuditMetadata) {
this._dump('auditSummary', auditMetadata);
}

auditMute(mutedAdvisories: AuditAdvisory[]) {
this._dump(mutedAdvisories);
}
}
1 change: 1 addition & 0 deletions src/reporters/lang/en.js
Expand Up @@ -424,6 +424,7 @@ const messages = {
auditRunning: 'Auditing packages',
auditSummary: '$0 vulnerabilities found - Packages audited: $1',
auditSummarySeverity: 'Severity:',
auditMute: '$0 vulnerabilities muted - Advisory ids: ($1)',
auditCritical: '$0 Critical',
auditHigh: '$0 High',
auditModerate: '$0 Moderate',
Expand Down

0 comments on commit 664266d

Please sign in to comment.