From f52179315be36040266736907cd76275c4db031d Mon Sep 17 00:00:00 2001 From: Marco Ippolito Date: Tue, 16 Apr 2024 17:48:04 +0200 Subject: [PATCH] feat: prompt dependency updates url in vulnerabilities.json creation (#788) * feat: prompt dependency updates url in vulnerabilities.json creation * feat: get pr from github * fix: improve usability --- lib/prepare_security.js | 64 ++++++++++++++++++++++-- lib/request.js | 12 +++++ lib/security-release/security-release.js | 7 +++ 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/lib/prepare_security.js b/lib/prepare_security.js index cfadbcdf..278f7974 100644 --- a/lib/prepare_security.js +++ b/lib/prepare_security.js @@ -11,8 +11,11 @@ import { checkoutOnSecurityReleaseBranch, commitAndPushVulnerabilitiesJSON, getSummary, - validateDate + validateDate, + promptDependencies, + getSupportedVersions } from './security-release/security-release.js'; +import _ from 'lodash'; export default class SecurityReleaseSteward { repository = NEXT_SECURITY_RELEASE_REPOSITORY; @@ -54,9 +57,11 @@ export default class SecurityReleaseSteward { // choose the reports to include in the security release const reports = await release.chooseReports(cli); + const depUpdates = await release.getDependencyUpdates({ cli }); + const deps = _.groupBy(depUpdates, 'name'); // create the vulnerabilities.json file in the security-release repo - const filePath = await release.createVulnerabilitiesJSON(reports, { cli }); + const filePath = await release.createVulnerabilitiesJSON(reports, deps, { cli }); // review the vulnerabilities.json file const review = await release.promptReviewVulnerabilitiesJSON(cli); @@ -212,10 +217,11 @@ class PrepareSecurityRelease { return selectedReports; } - async createVulnerabilitiesJSON(reports, { cli }) { + async createVulnerabilitiesJSON(reports, dependencies, { cli }) { cli.separator('Creating vulnerabilities.json...'); const file = JSON.stringify({ - reports + reports, + dependencies }, null, 2); const folderPath = path.join(process.cwd(), NEXT_SECURITY_RELEASE_FOLDER); @@ -259,4 +265,54 @@ class PrepareSecurityRelease { } process.exit(1); } + + async getDependencyUpdates({ cli }) { + const deps = []; + cli.log('\n'); + cli.separator('Dependency Updates'); + const updates = await cli.prompt('Are there dependency updates in this security release?', { + defaultAnswer: true, + questionType: 'confirm' + }); + + if (!updates) return deps; + + const supportedVersions = await getSupportedVersions(); + + let asking = true; + while (asking) { + const dep = await promptDependencies(cli); + if (!dep) { + asking = false; + break; + } + + const name = await cli.prompt('What is the name of the dependency that has been updated?', { + defaultAnswer: '', + questionType: 'input' + }); + + const versions = await cli.prompt('Which release line does this dependency update affect?', { + defaultAnswer: supportedVersions, + questionType: 'input' + }); + + try { + const prUrl = dep.replace('https://github.com/', 'https://api.github.com/repos/').replace('pull', 'pulls'); + const res = await this.req.getPullRequest(prUrl); + const { html_url, title } = res; + deps.push({ + name, + url: html_url, + title, + affectedVersions: versions.split(',').map((v) => v.replace('v', '').trim()) + }); + cli.separator(); + } catch (error) { + this.cli.error('Invalid PR url. Please provide a valid PR url.'); + this.cli.error(error); + } + } + return deps; + } } diff --git a/lib/request.js b/lib/request.js index 4e8c830d..f4723fb6 100644 --- a/lib/request.js +++ b/lib/request.js @@ -77,6 +77,18 @@ export default class Request { return this.json(url, options); } + async getPullRequest(url) { + const options = { + method: 'GET', + headers: { + Authorization: `Basic ${this.credentials.github}`, + 'User-Agent': 'node-core-utils', + Accept: 'application/vnd.github+json' + } + }; + return this.json(url, options); + } + async createPullRequest(title, body, { owner, repo, head, base }) { const url = `https://api.github.com/repos/${owner}/${repo}/pulls`; const options = { diff --git a/lib/security-release/security-release.js b/lib/security-release/security-release.js index 81ff6f7f..00e6ddc3 100644 --- a/lib/security-release/security-release.js +++ b/lib/security-release/security-release.js @@ -107,3 +107,10 @@ export function formatDateToYYYYMMDD(date) { // Concatenate year, month, and day with slashes return `${year}/${month}/${day}`; } + +export function promptDependencies(cli) { + return cli.prompt('Enter the link to the dependency update PR (leave empty to exit): ', { + defaultAnswer: '', + questionType: 'input' + }); +}