Skip to content

Commit cc7645f

Browse files
authored
fix: improve --request-cve (#1037)
1 parent 7520eb9 commit cc7645f

File tree

1 file changed

+62
-35
lines changed

1 file changed

+62
-35
lines changed

lib/update_security_release.js

Lines changed: 62 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -141,46 +141,55 @@ export default class UpdateSecurityRelease extends SecurityRelease {
141141
const vulnerabilitiesJSONPath = this.getVulnerabilitiesJSONPath();
142142
const content = this.readVulnerabilitiesJSON(vulnerabilitiesJSONPath);
143143
const { reports } = content;
144+
this.validateReportsForCVE(reports);
144145
const req = new Request(credentials);
145146
const programId = await this.getNodeProgramId(req);
146-
const cves = await this.promptCVECreation(req, reports, programId);
147-
this.assignCVEtoReport(cves, reports);
148-
this.updateVulnerabilitiesJSON(content);
149-
this.updateHackonerReportCve(req, reports);
147+
await this.promptCVECreation(req, reports, programId, content);
150148
}
151149

152-
assignCVEtoReport(cves, reports) {
153-
for (const cve of cves) {
154-
const report = reports.find(report => report.id === cve.reportId);
155-
report.cveIds = [cve.cve_identifier];
156-
report.patchedVersions = cve.patchedVersions;
150+
validateReportsForCVE(reports) {
151+
const invalid = [];
152+
for (const report of reports) {
153+
if (report.cveIds?.length) continue;
154+
const missing = [];
155+
if (!report.summary) missing.push('description');
156+
if (!report.severity?.weakness_id) missing.push('weakness_id');
157+
if (!report.severity?.cvss_vector_string) missing.push('cvss_vector_string');
158+
if (missing.length) {
159+
invalid.push({ id: report.id, missing });
160+
}
161+
}
162+
if (invalid.length) {
163+
for (const { id, missing } of invalid) {
164+
this.cli.error(`Report ${id} is missing: ${missing.join(', ')}`);
165+
}
166+
throw new Error('Some reports are missing required fields for CVE request. ' +
167+
'Run `git node security --sync` to update them.');
157168
}
158169
}
159170

160-
async updateHackonerReportCve(req, reports) {
161-
for (const report of reports) {
162-
const { id, cveIds } = report;
163-
this.cli.startSpinner(`Updating report ${id} with CVEs ${cveIds}..`);
164-
const body = {
165-
data: {
166-
type: 'report-cves',
167-
attributes: {
168-
cve_ids: cveIds
169-
}
171+
async updateHackonerReportCve(req, report) {
172+
const { id, cveIds } = report;
173+
this.cli.startSpinner(`Updating report ${id} with CVEs ${cveIds}..`);
174+
const body = {
175+
data: {
176+
type: 'report-cves',
177+
attributes: {
178+
cve_ids: cveIds
170179
}
171-
};
172-
const response = await req.updateReportCVE(id, body);
173-
if (response.errors) {
174-
this.cli.error(`Error updating report ${id}`);
175-
this.cli.error(JSON.stringify(response.errors, null, 2));
176180
}
177-
this.cli.stopSpinner(`Done updating report ${id} with CVEs ${cveIds}..`);
181+
};
182+
const response = await req.updateReportCVE(id, body);
183+
if (response.errors) {
184+
this.cli.error(`Error updating report ${id}`);
185+
this.cli.error(JSON.stringify(response.errors, null, 2));
178186
}
187+
this.cli.stopSpinner(`Done updating report ${id} with CVEs ${cveIds}..`);
179188
}
180189

181-
async promptCVECreation(req, reports, programId) {
190+
async promptCVECreation(req, reports, programId, content) {
182191
const supportedVersions = (await nv('supported'));
183-
const cves = [];
192+
const eolVersions = (await nv('eol'));
184193
for (const report of reports) {
185194
const { id, summary, title, affectedVersions, cveIds, link } = report;
186195
// skip if already has a CVE
@@ -222,7 +231,7 @@ Summary: ${summary}\n`,
222231
if (!create) continue;
223232

224233
const { h1AffectedVersions, patchedVersions } =
225-
await this.calculateVersions(affectedVersions, supportedVersions);
234+
await this.calculateVersions(affectedVersions, supportedVersions, eolVersions);
226235
const body = {
227236
data: {
228237
type: 'cve-request',
@@ -243,16 +252,18 @@ Summary: ${summary}\n`,
243252
}
244253
}
245254
};
246-
const { data } = await req.requestCVE(programId, body);
247-
if (data.errors) {
255+
const response = await req.requestCVE(programId, body);
256+
if (response.errors) {
248257
this.cli.error(`Error requesting CVE for report ${id}`);
249-
this.cli.error(JSON.stringify(data.errors, null, 2));
258+
this.cli.error(JSON.stringify(response.errors, null, 2));
250259
continue;
251260
}
252-
const { cve_identifier } = data.attributes;
253-
cves.push({ cve_identifier, reportId: id, patchedVersions });
261+
const { cve_identifier } = response.data.attributes;
262+
report.cveIds = [cve_identifier];
263+
report.patchedVersions = patchedVersions;
264+
this.updateVulnerabilitiesJSON(content);
265+
await this.updateHackonerReportCve(req, report);
254266
}
255-
return cves;
256267
}
257268

258269
async getNodeProgramId(req) {
@@ -266,7 +277,7 @@ Summary: ${summary}\n`,
266277
}
267278
}
268279

269-
async calculateVersions(affectedVersions, supportedVersions) {
280+
async calculateVersions(affectedVersions, supportedVersions, eolVersions) {
270281
const h1AffectedVersions = [];
271282
const patchedVersions = [];
272283
let isPatchRelease = true;
@@ -300,6 +311,22 @@ Summary: ${summary}\n`,
300311
affected: true
301312
});
302313
}
314+
315+
// All EOL versions are affected since they no longer receive security patches
316+
for (const eolVersion of eolVersions) {
317+
const version = semver.valid(eolVersion.version);
318+
if (version) {
319+
h1AffectedVersions.push({
320+
vendor: 'nodejs',
321+
product: 'node',
322+
func: '<=',
323+
version,
324+
versionType: 'semver',
325+
affected: true
326+
});
327+
}
328+
}
329+
303330
return { h1AffectedVersions, patchedVersions };
304331
}
305332
}

0 commit comments

Comments
 (0)