Skip to content

Commit da25653

Browse files
committed
fix: split security release vulnerability wording
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
1 parent b12497a commit da25653

3 files changed

Lines changed: 147 additions & 11 deletions

File tree

lib/security-release/security-release.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ export const NEXT_SECURITY_RELEASE_REPOSITORY = {
1212
};
1313

1414
const SEVERITY_RANK = {
15-
critical: 0,
16-
high: 1,
17-
medium: 2,
18-
low: 3
15+
low: 0,
16+
medium: 1,
17+
high: 2,
18+
critical: 3
1919
};
2020

2121
const SEVERITY_LABEL = {
@@ -146,18 +146,19 @@ export function formatDateToYYYYMMDD(date) {
146146

147147
export function getHighestSeverity(reports) {
148148
let highestSeverity = '';
149+
let highestRank = -1;
149150

150151
for (const report of reports) {
151-
const rating = report.severity.rating.toLowerCase();
152-
const currentRank = SEVERITY_RANK[rating] ?? Number.MAX_SAFE_INTEGER;
153-
const highestRank = SEVERITY_RANK[highestSeverity] ?? Number.MAX_SAFE_INTEGER;
152+
const rating = report.severity.rating;
153+
const currentRank = SEVERITY_RANK[rating] ?? -1;
154154

155-
if (!highestSeverity || currentRank < highestRank) {
155+
if (currentRank > highestRank) {
156156
highestSeverity = rating;
157+
highestRank = currentRank;
157158
}
158159
}
159160

160-
return SEVERITY_LABEL[highestSeverity] ?? highestSeverity.toUpperCase();
161+
return SEVERITY_LABEL[highestSeverity] ?? 'NONE';
161162
}
162163

163164
export function getHighestSeverityAnnouncement(reports) {

lib/security_blog.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default class SecurityBlog extends SecurityRelease {
3939
annoucementDate: await this.getAnnouncementDate(cli),
4040
releaseDate: this.formatReleaseDate(releaseDate),
4141
affectedVersions: this.getAffectedVersions(content),
42-
vulnerabilities: this.getVulnerabilities(content),
42+
vulnerabilities: this.getPreReleaseVulnerabilities(content),
4343
slug: this.getSlug(releaseDate),
4444
impact: this.getImpact(content)
4545
};
@@ -347,12 +347,34 @@ export default class SecurityBlog extends SecurityRelease {
347347
}
348348

349349
getVulnerabilities(content) {
350+
const severityCount = new Map();
351+
350352
for (const report of content.reports) {
351353
if (!report.severity?.rating) {
352354
this.cli.error(`severity.rating not found for report ${report.id}.`);
353355
process.exit(1);
354356
}
357+
358+
const rating = report.severity.rating;
359+
severityCount.set(rating, (severityCount.get(rating) || 0) + 1);
360+
}
361+
362+
const text = [];
363+
for (const [rating, count] of severityCount) {
364+
text.push(`- ${count} ${rating} severity issues.`);
355365
}
366+
367+
return text.join('\n');
368+
}
369+
370+
getPreReleaseVulnerabilities(content) {
371+
for (const report of content.reports) {
372+
if (!report.severity?.rating) {
373+
this.cli.error(`severity.rating not found for report ${report.id}.`);
374+
process.exit(1);
375+
}
376+
}
377+
356378
return getHighestSeverityAnnouncement(content.reports);
357379
}
358380

test/unit/security_release.test.js

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ const cli = {
1111
error() {}
1212
};
1313

14+
function assertExits(fn) {
15+
const originalExit = process.exit;
16+
process.exit = () => {
17+
throw new Error('process.exit');
18+
};
19+
20+
try {
21+
assert.throws(fn, /process\.exit/);
22+
} finally {
23+
process.exit = originalExit;
24+
}
25+
}
26+
1427
function report(id, rating, affectedVersions = ['24.x']) {
1528
return {
1629
id,
@@ -46,6 +59,16 @@ describe('security_release: severity announcement', () => {
4659
'The highest severity issue fixed in this release is MEDIUM.'
4760
);
4861
});
62+
63+
it('ignores invalid severity ratings', () => {
64+
const reports = [
65+
report(1, 'low'),
66+
report(2, 'hypercritical'),
67+
report(3, 'medium')
68+
];
69+
70+
assert.strictEqual(getHighestSeverity(reports), 'MEDIUM');
71+
});
4972
});
5073

5174
describe('security_blog: pre-release severity wording', () => {
@@ -59,7 +82,7 @@ describe('security_blog: pre-release severity wording', () => {
5982
};
6083

6184
assert.strictEqual(
62-
blog.getVulnerabilities(content),
85+
blog.getPreReleaseVulnerabilities(content),
6386
'The highest severity issue fixed in this release is MEDIUM.'
6487
);
6588
});
@@ -80,4 +103,94 @@ describe('security_blog: pre-release severity wording', () => {
80103
'The highest severity issue fixed in the 20.x release line is HIGH.'
81104
);
82105
});
106+
107+
it('replaces the pre-release template placeholder with the highest severity sentence', () => {
108+
const blog = new SecurityBlog(cli);
109+
const template = blog.getSecurityPreReleaseTemplate();
110+
const preRelease = blog.buildPreRelease(template, {
111+
annoucementDate: '2026-06-01T00:00:00.000Z',
112+
releaseDate: 'Tuesday, June 2, 2026',
113+
affectedVersions: '24.x, 22.x',
114+
vulnerabilities: blog.getPreReleaseVulnerabilities({
115+
reports: [
116+
report(1, 'low'),
117+
report(2, 'high')
118+
]
119+
}),
120+
slug: 'june-2026-security-releases',
121+
impact: 'The highest severity issue fixed in the 24.x release line is HIGH.'
122+
});
123+
124+
assert.match(
125+
preRelease,
126+
/The highest severity issue fixed in this release is HIGH\./
127+
);
128+
assert.doesNotMatch(preRelease, /%VULNERABILITIES%/);
129+
});
130+
131+
it('exits when a report is missing a severity rating', () => {
132+
const errors = [];
133+
const blog = new SecurityBlog({
134+
error(message) {
135+
errors.push(message);
136+
}
137+
});
138+
const content = {
139+
reports: [
140+
{
141+
id: 1,
142+
severity: {},
143+
affectedVersions: ['24.x']
144+
}
145+
]
146+
};
147+
148+
assertExits(() => blog.getPreReleaseVulnerabilities(content));
149+
assertExits(() => blog.getImpact(content));
150+
assert.deepStrictEqual(errors, [
151+
'severity.rating not found for report 1.',
152+
'severity.rating not found for report 1.'
153+
]);
154+
});
155+
});
156+
157+
describe('security_blog: post-release severity wording', () => {
158+
it('keeps the vulnerability count list', () => {
159+
const blog = new SecurityBlog(cli);
160+
const content = {
161+
reports: [
162+
report(1, 'low'),
163+
report(2, 'medium'),
164+
report(3, 'medium')
165+
]
166+
};
167+
168+
assert.strictEqual(
169+
blog.getVulnerabilities(content),
170+
'- 1 low severity issues.\n- 2 medium severity issues.'
171+
);
172+
});
173+
174+
it('exits when a report is missing a severity rating', () => {
175+
const errors = [];
176+
const blog = new SecurityBlog({
177+
error(message) {
178+
errors.push(message);
179+
}
180+
});
181+
const content = {
182+
reports: [
183+
{
184+
id: 1,
185+
severity: {},
186+
affectedVersions: ['24.x']
187+
}
188+
]
189+
};
190+
191+
assertExits(() => blog.getVulnerabilities(content));
192+
assert.deepStrictEqual(errors, [
193+
'severity.rating not found for report 1.'
194+
]);
195+
});
83196
});

0 commit comments

Comments
 (0)