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
18 changes: 18 additions & 0 deletions components/git/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const securityOptions = {
describe: 'Start security release process',
type: 'boolean'
},
sync: {
describe: 'Synchronize an ongoing security release with HackerOne',
type: 'boolean'
},
'update-date': {
describe: 'Updates the target date of the security release',
type: 'string'
Expand Down Expand Up @@ -46,6 +50,10 @@ export function builder(yargs) {
.example(
'git node security --start',
'Prepare a security release of Node.js')
.example(
'git node security --sync',
'Synchronize an ongoing security release with HackerOne'
)
.example(
'git node security --update-date=YYYY/MM/DD',
'Updates the target date of the security release'
Expand Down Expand Up @@ -76,6 +84,9 @@ export function handler(argv) {
if (argv.start) {
return startSecurityRelease(argv);
}
if (argv.sync) {
return syncSecurityRelease(argv);
}
if (argv['update-date']) {
return updateReleaseDate(argv);
}
Expand Down Expand Up @@ -142,6 +153,13 @@ async function startSecurityRelease(argv) {
return release.start();
}

async function syncSecurityRelease(argv) {
const logStream = process.stdout.isTTY ? process.stdout : process.stderr;
const cli = new CLI(logStream);
const release = new UpdateSecurityRelease(cli);
return release.sync();
}

async function notifyPreRelease() {
const logStream = process.stdout.isTTY ? process.stdout : process.stderr;
const cli = new CLI(logStream);
Expand Down
22 changes: 15 additions & 7 deletions lib/security-release/security-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ export async function getSupportedVersions() {
return supportedVersions;
}

export async function getSummary(reportId, req) {
const { data } = await req.getReport(reportId);
export function getSummary(report) {
const { data } = report;
const summaryList = data?.relationships?.summaries?.data;
if (!summaryList?.length) return;
const summaries = summaryList.filter((summary) => summary?.attributes?.category === 'team');
Expand Down Expand Up @@ -139,17 +139,25 @@ export async function createIssue(title, content, repository, { cli, req }) {
}
}

export async function pickReport(report, { cli, req }) {
export function getReportSeverity(report) {
const {
id, attributes: { title, cve_ids },
relationships: { severity, weakness, reporter, custom_field_values }
relationships: { severity, weakness }
} = report;
const link = `https://hackerone.com/reports/${id}`;
const reportSeverity = {
rating: severity?.data?.attributes?.rating || '',
cvss_vector_string: severity?.data?.attributes?.cvss_vector_string || '',
weakness_id: weakness?.data?.id || ''
};
return reportSeverity;
}

export async function pickReport(report, { cli, req }) {
const {
id, attributes: { title, cve_ids },
relationships: { reporter, custom_field_values }
} = report;
const link = `https://hackerone.com/reports/${id}`;
const reportSeverity = getReportSeverity(report);

cli.separator();
cli.info(`Report: ${link} - ${title} (${reportSeverity?.rating})`);
Expand Down Expand Up @@ -185,7 +193,7 @@ export async function pickReport(report, { cli, req }) {
}
}

const summaryContent = await getSummary(id, req);
const summaryContent = getSummary(report);

return {
id,
Expand Down
40 changes: 39 additions & 1 deletion lib/update_security_release.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import {
NEXT_SECURITY_RELEASE_FOLDER,
NEXT_SECURITY_RELEASE_REPOSITORY,
checkoutOnSecurityReleaseBranch,
checkRemote,
commitAndPushVulnerabilitiesJSON,
validateDate,
pickReport
pickReport,
getReportSeverity,
getSummary
} from './security-release/security-release.js';
import fs from 'node:fs';
import path from 'node:path';
Expand All @@ -18,6 +21,41 @@ export default class UpdateSecurityRelease {
this.cli = cli;
}

async sync() {
checkRemote(this.cli, this.repository);

const vulnerabilitiesJSONPath = this.getVulnerabilitiesJSONPath();
const content = this.readVulnerabilitiesJSON(vulnerabilitiesJSONPath);
const credentials = await auth({
github: true,
h1: true
});
const req = new Request(credentials);
for (let i = 0; i < content.reports.length; ++i) {
let report = content.reports[i];
const { data } = await req.getReport(report.id);
const reportSeverity = getReportSeverity(data);
const summaryContent = getSummary(data);
const link = `https://hackerone.com/reports/${report.id}`;
let prURL = report.prURL;
if (data.relationships.custom_field_values.data.length) {
prURL = data.relationships.custom_field_values.data[0].attributes.value;
}

report = {
...report,
title: data.attributes.title,
cveIds: data.attributes.cve_ids,
severity: reportSeverity,
summary: summaryContent ?? report.summary,
link,
prURL
};
}
fs.writeFileSync(vulnerabilitiesJSONPath, JSON.stringify(content, null, 2));
this.cli.ok('Synced vulnerabilities.json with HackerOne');
}

async updateReleaseDate(releaseDate) {
const { cli } = this;

Expand Down