Skip to content

Commit

Permalink
feat(vulnerabilities): handle medium and unknown severities (#22257)
Browse files Browse the repository at this point in the history
Co-authored-by: Jamie Magee <jamie.magee@gmail.com>
  • Loading branch information
setchy and JamieMagee committed May 16, 2023
1 parent e1e5f7f commit 1c82218
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 15 deletions.
11 changes: 11 additions & 0 deletions lib/util/string.ts
Expand Up @@ -56,3 +56,14 @@ export function looseEquals(
export function isDockerDigest(input: string): boolean {
return /^sha256:[a-f0-9]{64}$/i.test(input);
}

export function titleCase(input: string): string {
const words = input.toLowerCase().split(' ');

for (let i = 0; i < words.length; i++) {
const word = words[i];
words[i] = word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}

return words.join(' ');
}
2 changes: 1 addition & 1 deletion lib/util/template/index.ts
Expand Up @@ -145,7 +145,7 @@ export const allowedFields = {
versioning: 'The versioning scheme in use',
versions: 'An array of ChangeLogRelease objects in the upgrade',
vulnerabilitySeverity:
'The severity for a vulnerability alert upgrade (eg: LOW, MODERATE, HIGH, CRITICAL)',
'The severity for a vulnerability alert upgrade (LOW, MEDIUM, MODERATE, HIGH, CRITICAL, UNKNOWN)',
};

const prBodyFields = [
Expand Down
28 changes: 28 additions & 0 deletions lib/util/vulnerability/utils.spec.ts
Expand Up @@ -85,6 +85,20 @@ describe('util/vulnerability/utils', () => {
expect(severity).toBe('MODERATE');
});

it('child MEDIUM vulnerability severity rating is maintained', () => {
const parentConfig = {
vulnerabilitySeverity: 'LOW',
};

const childConfig = {
vulnerabilitySeverity: 'MEDIUM',
};

const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig);

expect(severity).toBe('MEDIUM');
});

it('parent LOW vulnerability severity rating is maintained', () => {
const parentConfig = {
vulnerabilitySeverity: 'LOW',
Expand Down Expand Up @@ -113,6 +127,20 @@ describe('util/vulnerability/utils', () => {
expect(severity).toBe('LOW');
});

it('child UNKNOWN vulnerability severity rating is maintained', () => {
const parentConfig = {
vulnerabilitySeverity: 'CRITICAL',
};

const childConfig = {
vulnerabilitySeverity: 'UNKNOWN',
};

const severity = getHighestVulnerabilitySeverity(parentConfig, childConfig);

expect(severity).toBe('UNKNOWN');
});

it('handled undefined parent and child vulnerability severity', () => {
const parentConfig = {
vulnerabilitySeverity: undefined,
Expand Down
2 changes: 2 additions & 0 deletions lib/util/vulnerability/utils.ts
@@ -1,8 +1,10 @@
const severityOrder: Record<string, number> = {
LOW: 1,
MEDIUM: 2,
MODERATE: 2,
HIGH: 3,
CRITICAL: 4,
UNKNOWN: 5,
};

export function getHighestVulnerabilitySeverity<
Expand Down
2 changes: 1 addition & 1 deletion lib/workers/repository/process/types.ts
Expand Up @@ -21,5 +21,5 @@ export interface DependencyVulnerabilities {
export interface SeverityDetails {
cvssVector: string;
score: string;
severityLevel?: string;
severityLevel: string;
}
2 changes: 1 addition & 1 deletion lib/workers/repository/process/vulnerabilities.spec.ts
Expand Up @@ -944,7 +944,7 @@ describe('workers/repository/process/vulnerabilities', () => {
No details.
#### Severity
Unknown severity.
Unknown
#### References
No references.
Expand Down
22 changes: 10 additions & 12 deletions lib/workers/repository/process/vulnerabilities.ts
Expand Up @@ -18,6 +18,7 @@ import {
import { sanitizeMarkdown } from '../../../util/markdown';
import * as p from '../../../util/promises';
import { regEx } from '../../../util/regex';
import { titleCase } from '../../../util/string';
import type {
DependencyVulnerabilities,
SeverityDetails,
Expand Down Expand Up @@ -470,7 +471,7 @@ export class Vulnerabilities {
matchCurrentVersion: depVersion,
allowedVersions: fixedVersion,
isVulnerabilityAlert: true,
vulnerabilitySeverity: severityDetails.severityLevel?.toUpperCase(),
vulnerabilitySeverity: severityDetails.severityLevel,
prBodyNotes: this.generatePrBodyNotes(vulnerability, affected),
force: {
...packageFileConfig.vulnerabilityAlerts,
Expand All @@ -481,9 +482,7 @@ export class Vulnerabilities {
private evaluateCvssVector(vector: string): [string, string] {
try {
const parsedCvss: CvssScore = parseCvssVector(vector);
const severityLevel =
parsedCvss.cvss3OverallSeverityText.charAt(0).toUpperCase() +
parsedCvss.cvss3OverallSeverityText.slice(1);
const severityLevel = parsedCvss.cvss3OverallSeverityText;

return [parsedCvss.baseScore.toFixed(1), severityLevel];
} catch (err) {
Expand Down Expand Up @@ -532,10 +531,8 @@ export class Vulnerabilities {
if (severityDetails.cvssVector) {
content += `- CVSS Score: ${severityDetails.score}\n`;
content += `- Vector String: \`${severityDetails.cvssVector}\`\n`;
} else if (severityDetails.severityLevel) {
content += `${severityDetails.severityLevel}\n`;
} else {
content += 'Unknown severity.\n';
content += `${titleCase(severityDetails.severityLevel)}\n`;
}

content += `\n#### References\n${
Expand Down Expand Up @@ -566,7 +563,7 @@ export class Vulnerabilities {
vulnerability: Osv.Vulnerability,
affected: Osv.Affected
): SeverityDetails {
let severityLevel: string | undefined;
let severityLevel = 'UNKNOWN';
let score = 'Unknown';

const cvssVector =
Expand All @@ -576,15 +573,16 @@ export class Vulnerabilities {

if (cvssVector) {
const [baseScore, severity] = this.evaluateCvssVector(cvssVector);
severityLevel = severity;
score = baseScore ? `${baseScore} / 10 (${severityLevel})` : 'Unknown';
severityLevel = severity.toUpperCase();
score = baseScore
? `${baseScore} / 10 (${titleCase(severityLevel)})`
: 'Unknown';
} else if (
vulnerability.id.startsWith('GHSA-') &&
vulnerability.database_specific?.severity
) {
const severity = vulnerability.database_specific.severity as string;
severityLevel =
severity.charAt(0).toUpperCase() + severity.slice(1).toLowerCase();
severityLevel = severity.toUpperCase();
}

return {
Expand Down

0 comments on commit 1c82218

Please sign in to comment.