From cd736a1eebe8cee1593fd6e231bd1af70ba9395d Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 1 Jun 2026 16:38:29 +0200 Subject: [PATCH] chore: replace `process.exit` calls with actual error thrown --- lib/security_blog.js | 27 ++++++---------- test/unit/security_release.test.js | 52 ++++++------------------------ 2 files changed, 18 insertions(+), 61 deletions(-) diff --git a/lib/security_blog.js b/lib/security_blog.js index 194e4d06..b424a5bc 100644 --- a/lib/security_blog.js +++ b/lib/security_blog.js @@ -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); @@ -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); @@ -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); @@ -247,14 +244,12 @@ 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`; @@ -262,8 +257,7 @@ export default class SecurityBlog extends SecurityRelease { 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`; @@ -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) { @@ -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; @@ -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}.`); } } diff --git a/test/unit/security_release.test.js b/test/unit/security_release.test.js index 80541024..8058e8be 100644 --- a/test/unit/security_release.test.js +++ b/test/unit/security_release.test.js @@ -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, @@ -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'), @@ -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']), @@ -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', @@ -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: [ { @@ -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'), @@ -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: [ { @@ -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/); }); });