Skip to content

Commit f580644

Browse files
RafaelGSSaduh95
authored andcommitted
fix: split security release vulnerability wording
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
1 parent 966089e commit f580644

2 files changed

Lines changed: 144 additions & 2 deletions

File tree

lib/security_blog.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default class SecurityBlog extends SecurityRelease {
3838
annoucementDate: await this.getAnnouncementDate(cli),
3939
releaseDate: this.formatReleaseDate(releaseDate),
4040
affectedVersions: this.getAffectedVersions(content),
41-
vulnerabilities: this.getVulnerabilities(content),
41+
vulnerabilities: this.getPreReleaseVulnerabilities(content),
4242
slug: this.getSlug(releaseDate),
4343
impact: this.getImpact(content)
4444
};
@@ -344,12 +344,34 @@ export default class SecurityBlog extends SecurityRelease {
344344
}
345345

346346
getVulnerabilities(content) {
347+
const severityCount = new Map();
348+
347349
for (const report of content.reports) {
348350
if (!report.severity?.rating) {
349351
this.cli.error(`severity.rating not found for report ${report.id}.`);
350352
process.exit(1);
351353
}
354+
355+
const rating = report.severity.rating;
356+
severityCount.set(rating, (severityCount.get(rating) || 0) + 1);
357+
}
358+
359+
const text = [];
360+
for (const [rating, count] of severityCount) {
361+
text.push(`- ${count} ${rating} severity issues.`);
352362
}
363+
364+
return text.join('\n');
365+
}
366+
367+
getPreReleaseVulnerabilities(content) {
368+
for (const report of content.reports) {
369+
if (!report.severity?.rating) {
370+
this.cli.error(`severity.rating not found for report ${report.id}.`);
371+
process.exit(1);
372+
}
373+
}
374+
353375
return getHighestSeverityAnnouncement(content.reports);
354376
}
355377

test/unit/security_release.test.js

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

13+
function assertExits(fn) {
14+
const originalExit = process.exit;
15+
process.exit = () => {
16+
throw new Error('process.exit');
17+
};
18+
19+
try {
20+
assert.throws(fn, /process\.exit/);
21+
} finally {
22+
process.exit = originalExit;
23+
}
24+
}
25+
1326
function report(id, rating, affectedVersions = ['24.x']) {
1427
return {
1528
id,
@@ -80,6 +93,19 @@ describe('security_release: severity announcement', () => {
8093
'The highest severity issue fixed in this release is MEDIUM.'
8194
);
8295
});
96+
97+
it('ignores invalid severity ratings', () => {
98+
const reports = [
99+
report(1, 'low'),
100+
report(2, 'hypercritical'),
101+
report(3, 'medium')
102+
];
103+
104+
assert.strictEqual(
105+
getHighestSeverityAnnouncement(reports),
106+
'The highest severity issue fixed in this release is MEDIUM.'
107+
);
108+
});
83109
});
84110

85111
describe('security_blog: pre-release severity wording', () => {
@@ -93,9 +119,13 @@ describe('security_blog: pre-release severity wording', () => {
93119
};
94120

95121
assert.strictEqual(
96-
blog.getVulnerabilities(content),
122+
blog.getPreReleaseVulnerabilities(content),
97123
'The highest severity issue fixed in this release is MEDIUM.'
98124
);
125+
assert.strictEqual(
126+
blog.getVulnerabilities(content),
127+
'- 1 low severity issues.\n- 1 medium severity issues.'
128+
);
99129
});
100130

101131
it('uses the highest severity per release line in impact text', () => {
@@ -114,4 +144,94 @@ describe('security_blog: pre-release severity wording', () => {
114144
'The highest severity issue fixed in the 20.x release line is HIGH.'
115145
);
116146
});
147+
148+
it('replaces the pre-release template placeholder with the highest severity sentence', () => {
149+
const blog = new SecurityBlog(cli);
150+
const template = blog.getSecurityPreReleaseTemplate();
151+
const preRelease = blog.buildPreRelease(template, {
152+
annoucementDate: '2026-06-01T00:00:00.000Z',
153+
releaseDate: 'Tuesday, June 2, 2026',
154+
affectedVersions: '24.x, 22.x',
155+
vulnerabilities: blog.getPreReleaseVulnerabilities({
156+
reports: [
157+
report(1, 'low'),
158+
report(2, 'high')
159+
]
160+
}),
161+
slug: 'june-2026-security-releases',
162+
impact: 'The highest severity issue fixed in the 24.x release line is HIGH.'
163+
});
164+
165+
assert.match(
166+
preRelease,
167+
/The highest severity issue fixed in this release is HIGH\./
168+
);
169+
assert.doesNotMatch(preRelease, /%VULNERABILITIES%/);
170+
});
171+
172+
it('exits when a report is missing a severity rating', () => {
173+
const errors = [];
174+
const blog = new SecurityBlog({
175+
error(message) {
176+
errors.push(message);
177+
}
178+
});
179+
const content = {
180+
reports: [
181+
{
182+
id: 1,
183+
severity: {},
184+
affectedVersions: ['24.x']
185+
}
186+
]
187+
};
188+
189+
assertExits(() => blog.getPreReleaseVulnerabilities(content));
190+
assertExits(() => blog.getImpact(content));
191+
assert.deepStrictEqual(errors, [
192+
'severity.rating not found for report 1.',
193+
'severity.rating not found for report 1.'
194+
]);
195+
});
196+
});
197+
198+
describe('security_blog: post-release severity wording', () => {
199+
it('keeps the vulnerability count list', () => {
200+
const blog = new SecurityBlog(cli);
201+
const content = {
202+
reports: [
203+
report(1, 'low'),
204+
report(2, 'medium'),
205+
report(3, 'medium')
206+
]
207+
};
208+
209+
assert.strictEqual(
210+
blog.getVulnerabilities(content),
211+
'- 1 low severity issues.\n- 2 medium severity issues.'
212+
);
213+
});
214+
215+
it('exits when a report is missing a severity rating', () => {
216+
const errors = [];
217+
const blog = new SecurityBlog({
218+
error(message) {
219+
errors.push(message);
220+
}
221+
});
222+
const content = {
223+
reports: [
224+
{
225+
id: 1,
226+
severity: {},
227+
affectedVersions: ['24.x']
228+
}
229+
]
230+
};
231+
232+
assertExits(() => blog.getVulnerabilities(content));
233+
assert.deepStrictEqual(errors, [
234+
'severity.rating not found for report 1.'
235+
]);
236+
});
117237
});

0 commit comments

Comments
 (0)