Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 9 additions & 18 deletions lib/security_blog.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ export default class SecurityBlog extends SecurityRelease {
const content = this.readVulnerabilitiesJSON();
// validate the release date read from vulnerabilities JSON
if (!content.releaseDate) {
cli.error('Release date is not set in vulnerabilities.json,' +
throw new Error('Release date is not set in vulnerabilities.json,' +
' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
process.exit(1);
}

validateDate(content.releaseDate);
Expand Down Expand Up @@ -109,9 +108,8 @@ export default class SecurityBlog extends SecurityRelease {
// read vulnerabilities JSON file
const content = this.readVulnerabilitiesJSON();
if (!content.releaseDate) {
cli.error('Release date is not set in vulnerabilities.json,' +
throw new Error('Release date is not set in vulnerabilities.json,' +
' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
process.exit(1);
}

validateDate(content.releaseDate);
Expand All @@ -133,8 +131,7 @@ export default class SecurityBlog extends SecurityRelease {
const preReleasePath = path.resolve(pathToBlogPosts, data.slug + '.md');
let preReleaseContent = this.findExistingPreRelease(preReleasePath);
if (!preReleaseContent) {
cli.error(`Existing pre-release not found! Path: ${preReleasePath} `);
process.exit(1);
throw new Error(`Existing pre-release not found! Path: ${preReleasePath} `);
}

const postReleaseContent = await this.buildPostRelease(template, data, content);
Expand Down Expand Up @@ -247,23 +244,20 @@ export default class SecurityBlog extends SecurityRelease {
for (const report of reports) {
const cveId = report.cveIds?.join(', ');
if (!cveId) {
this.cli.error(`CVE ID for vulnerability ${report.link} ${report.title} not found`);
process.exit(1);
throw new Error(`CVE ID for vulnerability ${report.link} ${report.title} not found`);
}
template += `## ${report.title} (${cveId}) - (${report.severity.rating})\n\n`;
if (!report.summary) {
this.cli.error(`Summary missing for vulnerability ${report.link} ` +
throw new Error(`Summary missing for vulnerability ${report.link} ` +
`${report.title}. Please create it before continuing.`);
process.exit(1);
}

template += `${report.summary}\n\n`;
const releaseLines = report.affectedVersions.join(', ');
template += `Impact:\n\n- This vulnerability affects all users\
in active release lines: ${releaseLines}\n\n`;
if (!report.patchAuthors) {
this.cli.error(`Missing patch author for vulnerability ${report.link} ${report.title}`);
process.exit(1);
throw new Error(`Missing patch author for vulnerability ${report.link} ${report.title}`);
}
template += `Thank you, to ${report.reporter} for reporting this vulnerability\
and thank you ${report.patchAuthors.join(' and ')} for fixing it.\n\n`;
Expand Down Expand Up @@ -324,8 +318,7 @@ export default class SecurityBlog extends SecurityRelease {
const impact = new Map();
for (const report of content.reports) {
if (!report.severity?.rating) {
this.cli.error(`severity.rating not found for report ${report.id}.`);
process.exit(1);
throw new Error(`severity.rating not found for report ${report.id}.`);
}

for (const version of report.affectedVersions) {
Expand All @@ -348,8 +341,7 @@ export default class SecurityBlog extends SecurityRelease {

for (const report of content.reports) {
if (!report.severity?.rating) {
this.cli.error(`severity.rating not found for report ${report.id}.`);
process.exit(1);
throw new Error(`severity.rating not found for report ${report.id}.`);
}

const rating = report.severity.rating;
Expand All @@ -367,8 +359,7 @@ export default class SecurityBlog extends SecurityRelease {
getPreReleaseVulnerabilities(content) {
for (const report of content.reports) {
if (!report.severity?.rating) {
this.cli.error(`severity.rating not found for report ${report.id}.`);
process.exit(1);
throw new Error(`severity.rating not found for report ${report.id}.`);
}
}

Expand Down
52 changes: 9 additions & 43 deletions test/unit/security_release.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,6 @@ import {
getHighestSeverityAnnouncement
} from '../../lib/security-release/security-release.js';

const cli = {
error() {}
};

function assertExits(fn) {
const originalExit = process.exit;
process.exit = () => {
throw new Error('process.exit');
};

try {
assert.throws(fn, /process\.exit/);
} finally {
process.exit = originalExit;
}
}

function report(id, rating, affectedVersions = ['24.x']) {
return {
id,
Expand Down Expand Up @@ -110,7 +93,7 @@ describe('security_release: severity announcement', () => {

describe('security_blog: pre-release severity wording', () => {
it('does not include severity counts in the summary', () => {
const blog = new SecurityBlog(cli);
const blog = new SecurityBlog();
const content = {
reports: [
report(1, 'low'),
Expand All @@ -129,7 +112,7 @@ describe('security_blog: pre-release severity wording', () => {
});

it('uses the highest severity per release line in impact text', () => {
const blog = new SecurityBlog(cli);
const blog = new SecurityBlog();
const content = {
reports: [
report(1, 'low', ['22.x', '20.x']),
Expand All @@ -146,7 +129,7 @@ describe('security_blog: pre-release severity wording', () => {
});

it('replaces the pre-release template placeholder with the highest severity sentence', () => {
const blog = new SecurityBlog(cli);
const blog = new SecurityBlog();
const template = blog.getSecurityPreReleaseTemplate();
const preRelease = blog.buildPreRelease(template, {
annoucementDate: '2026-06-01T00:00:00.000Z',
Expand All @@ -170,12 +153,7 @@ describe('security_blog: pre-release severity wording', () => {
});

it('exits when a report is missing a severity rating', () => {
const errors = [];
const blog = new SecurityBlog({
error(message) {
errors.push(message);
}
});
const blog = new SecurityBlog();
const content = {
reports: [
{
Expand All @@ -186,18 +164,14 @@ describe('security_blog: pre-release severity wording', () => {
]
};

assertExits(() => blog.getPreReleaseVulnerabilities(content));
assertExits(() => blog.getImpact(content));
assert.deepStrictEqual(errors, [
'severity.rating not found for report 1.',
'severity.rating not found for report 1.'
]);
assert.throws(() => blog.getPreReleaseVulnerabilities(content), /severity\.rating not found for report 1/);
assert.throws(() => blog.getImpact(content), /severity\.rating not found for report 1/);
});
});

describe('security_blog: post-release severity wording', () => {
it('keeps the vulnerability count list', () => {
const blog = new SecurityBlog(cli);
const blog = new SecurityBlog();
const content = {
reports: [
report(1, 'low'),
Expand All @@ -213,12 +187,7 @@ describe('security_blog: post-release severity wording', () => {
});

it('exits when a report is missing a severity rating', () => {
const errors = [];
const blog = new SecurityBlog({
error(message) {
errors.push(message);
}
});
const blog = new SecurityBlog();
const content = {
reports: [
{
Expand All @@ -229,9 +198,6 @@ describe('security_blog: post-release severity wording', () => {
]
};

assertExits(() => blog.getVulnerabilities(content));
assert.deepStrictEqual(errors, [
'severity.rating not found for report 1.'
]);
assert.throws(() => blog.getVulnerabilities(content), /severity\.rating not found for report 1/);
});
});
Loading