Skip to content
Merged
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
97 changes: 62 additions & 35 deletions lib/update_security_release.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,46 +141,55 @@ export default class UpdateSecurityRelease extends SecurityRelease {
const vulnerabilitiesJSONPath = this.getVulnerabilitiesJSONPath();
const content = this.readVulnerabilitiesJSON(vulnerabilitiesJSONPath);
const { reports } = content;
this.validateReportsForCVE(reports);
const req = new Request(credentials);
const programId = await this.getNodeProgramId(req);
const cves = await this.promptCVECreation(req, reports, programId);
this.assignCVEtoReport(cves, reports);
this.updateVulnerabilitiesJSON(content);
this.updateHackonerReportCve(req, reports);
await this.promptCVECreation(req, reports, programId, content);
}

assignCVEtoReport(cves, reports) {
for (const cve of cves) {
const report = reports.find(report => report.id === cve.reportId);
report.cveIds = [cve.cve_identifier];
report.patchedVersions = cve.patchedVersions;
validateReportsForCVE(reports) {
const invalid = [];
for (const report of reports) {
if (report.cveIds?.length) continue;
const missing = [];
if (!report.summary) missing.push('description');
if (!report.severity?.weakness_id) missing.push('weakness_id');
if (!report.severity?.cvss_vector_string) missing.push('cvss_vector_string');
if (missing.length) {
invalid.push({ id: report.id, missing });
}
}
if (invalid.length) {
for (const { id, missing } of invalid) {
this.cli.error(`Report ${id} is missing: ${missing.join(', ')}`);
}
throw new Error('Some reports are missing required fields for CVE request. ' +
'Run `git node security --sync` to update them.');
}
}

async updateHackonerReportCve(req, reports) {
for (const report of reports) {
const { id, cveIds } = report;
this.cli.startSpinner(`Updating report ${id} with CVEs ${cveIds}..`);
const body = {
data: {
type: 'report-cves',
attributes: {
cve_ids: cveIds
}
async updateHackonerReportCve(req, report) {
const { id, cveIds } = report;
this.cli.startSpinner(`Updating report ${id} with CVEs ${cveIds}..`);
const body = {
data: {
type: 'report-cves',
attributes: {
cve_ids: cveIds
}
};
const response = await req.updateReportCVE(id, body);
if (response.errors) {
this.cli.error(`Error updating report ${id}`);
this.cli.error(JSON.stringify(response.errors, null, 2));
}
this.cli.stopSpinner(`Done updating report ${id} with CVEs ${cveIds}..`);
};
const response = await req.updateReportCVE(id, body);
if (response.errors) {
this.cli.error(`Error updating report ${id}`);
this.cli.error(JSON.stringify(response.errors, null, 2));
}
this.cli.stopSpinner(`Done updating report ${id} with CVEs ${cveIds}..`);
}

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

const { h1AffectedVersions, patchedVersions } =
await this.calculateVersions(affectedVersions, supportedVersions);
await this.calculateVersions(affectedVersions, supportedVersions, eolVersions);
const body = {
data: {
type: 'cve-request',
Expand All @@ -243,16 +252,18 @@ Summary: ${summary}\n`,
}
}
};
const { data } = await req.requestCVE(programId, body);
if (data.errors) {
const response = await req.requestCVE(programId, body);
if (response.errors) {
this.cli.error(`Error requesting CVE for report ${id}`);
this.cli.error(JSON.stringify(data.errors, null, 2));
this.cli.error(JSON.stringify(response.errors, null, 2));
continue;
}
const { cve_identifier } = data.attributes;
cves.push({ cve_identifier, reportId: id, patchedVersions });
const { cve_identifier } = response.data.attributes;
report.cveIds = [cve_identifier];
report.patchedVersions = patchedVersions;
this.updateVulnerabilitiesJSON(content);
await this.updateHackonerReportCve(req, report);
}
return cves;
}

async getNodeProgramId(req) {
Expand All @@ -266,7 +277,7 @@ Summary: ${summary}\n`,
}
}

async calculateVersions(affectedVersions, supportedVersions) {
async calculateVersions(affectedVersions, supportedVersions, eolVersions) {
const h1AffectedVersions = [];
const patchedVersions = [];
let isPatchRelease = true;
Expand Down Expand Up @@ -300,6 +311,22 @@ Summary: ${summary}\n`,
affected: true
});
}

// All EOL versions are affected since they no longer receive security patches
for (const eolVersion of eolVersions) {
const version = semver.valid(eolVersion.version);
if (version) {
h1AffectedVersions.push({
vendor: 'nodejs',
product: 'node',
func: '<=',
version,
versionType: 'semver',
affected: true
});
}
}

return { h1AffectedVersions, patchedVersions };
}
}
Loading