@node-core/utils 4.3.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ncu-ci.js +6 -1
- package/components/git/security.js +120 -5
- package/lib/ci/run_ci.js +12 -2
- package/lib/github/templates/security-pre-release.md +30 -0
- package/lib/pr_checker.js +1 -0
- package/lib/prepare_security.js +157 -172
- package/lib/request.js +55 -0
- package/lib/security-announcement.js +76 -0
- package/lib/security-release/security-release.js +193 -0
- package/lib/security_blog.js +182 -0
- package/lib/update_security_release.js +274 -0
- package/package.json +1 -1
- package/lib/github/templates/next-security-release.md +0 -98
package/lib/prepare_security.js
CHANGED
@@ -1,244 +1,177 @@
|
|
1
|
-
import nv from '@pkgjs/nv';
|
2
|
-
import auth from './auth.js';
|
3
|
-
import Request from './request.js';
|
4
1
|
import fs from 'node:fs';
|
5
|
-
import { runSync } from './run.js';
|
6
2
|
import path from 'node:path';
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
3
|
+
import auth from './auth.js';
|
4
|
+
import Request from './request.js';
|
5
|
+
import {
|
6
|
+
NEXT_SECURITY_RELEASE_BRANCH,
|
7
|
+
NEXT_SECURITY_RELEASE_FOLDER,
|
8
|
+
NEXT_SECURITY_RELEASE_REPOSITORY,
|
9
|
+
PLACEHOLDERS,
|
10
|
+
checkoutOnSecurityReleaseBranch,
|
11
|
+
commitAndPushVulnerabilitiesJSON,
|
12
|
+
validateDate,
|
13
|
+
promptDependencies,
|
14
|
+
getSupportedVersions,
|
15
|
+
pickReport
|
16
|
+
} from './security-release/security-release.js';
|
17
|
+
import _ from 'lodash';
|
18
|
+
|
19
|
+
export default class PrepareSecurityRelease {
|
20
|
+
repository = NEXT_SECURITY_RELEASE_REPOSITORY;
|
21
|
+
title = 'Next Security Release';
|
17
22
|
constructor(cli) {
|
18
23
|
this.cli = cli;
|
19
24
|
}
|
20
25
|
|
21
26
|
async start() {
|
22
|
-
const { cli } = this;
|
23
27
|
const credentials = await auth({
|
24
28
|
github: true,
|
25
29
|
h1: true
|
26
30
|
});
|
27
31
|
|
28
|
-
|
29
|
-
const
|
30
|
-
|
31
|
-
|
32
|
+
this.req = new Request(credentials);
|
33
|
+
const releaseDate = await this.promptReleaseDate();
|
34
|
+
if (releaseDate !== 'TBD') {
|
35
|
+
validateDate(releaseDate);
|
36
|
+
}
|
37
|
+
const createVulnerabilitiesJSON = await this.promptVulnerabilitiesJSON();
|
32
38
|
|
33
|
-
|
39
|
+
let securityReleasePRUrl;
|
34
40
|
if (createVulnerabilitiesJSON) {
|
35
|
-
securityReleasePRUrl = await this.
|
41
|
+
securityReleasePRUrl = await this.startVulnerabilitiesJSONCreation(releaseDate);
|
36
42
|
}
|
37
43
|
|
38
|
-
const createIssue = await
|
44
|
+
const createIssue = await this.promptCreateRelaseIssue();
|
39
45
|
|
40
46
|
if (createIssue) {
|
41
|
-
const
|
42
|
-
await
|
47
|
+
const content = await this.buildIssue(releaseDate, securityReleasePRUrl);
|
48
|
+
await createIssue(
|
49
|
+
this.title, content, this.repository, { cli: this.cli, repository: this.repository });
|
43
50
|
};
|
44
51
|
|
45
|
-
cli.ok('Done!');
|
52
|
+
this.cli.ok('Done!');
|
46
53
|
}
|
47
54
|
|
48
|
-
async
|
55
|
+
async startVulnerabilitiesJSONCreation(releaseDate) {
|
49
56
|
// checkout on the next-security-release branch
|
50
|
-
|
57
|
+
checkoutOnSecurityReleaseBranch(this.cli, this.repository);
|
51
58
|
|
52
59
|
// choose the reports to include in the security release
|
53
|
-
const reports = await
|
60
|
+
const reports = await this.chooseReports();
|
61
|
+
const depUpdates = await this.getDependencyUpdates();
|
62
|
+
const deps = _.groupBy(depUpdates, 'name');
|
54
63
|
|
55
64
|
// create the vulnerabilities.json file in the security-release repo
|
56
|
-
const filePath = await
|
65
|
+
const filePath = await this.createVulnerabilitiesJSON(reports, deps, releaseDate);
|
57
66
|
|
58
67
|
// review the vulnerabilities.json file
|
59
|
-
const review = await
|
68
|
+
const review = await this.promptReviewVulnerabilitiesJSON();
|
60
69
|
|
61
70
|
if (!review) {
|
62
|
-
cli.info(`To push the vulnerabilities.json file run:
|
71
|
+
this.cli.info(`To push the vulnerabilities.json file run:
|
63
72
|
- git add ${filePath}
|
64
73
|
- git commit -m "chore: create vulnerabilities.json for next security release"
|
65
|
-
- git push -u origin
|
66
|
-
- open a PR on ${
|
74
|
+
- git push -u origin ${NEXT_SECURITY_RELEASE_BRANCH}
|
75
|
+
- open a PR on ${this.repository.owner}/${this.repository.repo}`);
|
67
76
|
return;
|
68
77
|
};
|
69
78
|
|
70
79
|
// commit and push the vulnerabilities.json file
|
71
|
-
|
80
|
+
const commitMessage = 'chore: create vulnerabilities.json for next security release';
|
81
|
+
commitAndPushVulnerabilitiesJSON(filePath,
|
82
|
+
commitMessage,
|
83
|
+
{ cli: this.cli, repository: this.repository });
|
72
84
|
|
73
|
-
const createPr = await
|
85
|
+
const createPr = await this.promptCreatePR();
|
74
86
|
|
75
87
|
if (!createPr) return;
|
76
88
|
|
77
89
|
// create pr on the security-release repo
|
78
|
-
return
|
90
|
+
return this.createPullRequest();
|
79
91
|
}
|
80
|
-
}
|
81
92
|
|
82
|
-
|
83
|
-
|
84
|
-
owner: 'nodejs-private',
|
85
|
-
repo: 'security-release'
|
86
|
-
};
|
87
|
-
|
88
|
-
title = 'Next Security Release';
|
89
|
-
nextSecurityReleaseBranch = 'next-security-release';
|
90
|
-
|
91
|
-
constructor(req, repository) {
|
92
|
-
this.req = req;
|
93
|
-
if (repository) {
|
94
|
-
this.repository = repository;
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
98
|
-
promptCreatePR(cli) {
|
99
|
-
return cli.prompt(
|
93
|
+
promptCreatePR() {
|
94
|
+
return this.cli.prompt(
|
100
95
|
'Create the Next Security Release PR?',
|
101
96
|
{ defaultAnswer: true });
|
102
97
|
}
|
103
98
|
|
104
|
-
|
105
|
-
const
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
99
|
+
async getSecurityIssueTemplate() {
|
100
|
+
const url = 'https://raw.githubusercontent.com/nodejs/node/main/doc/contributing/security-release-process.md';
|
101
|
+
try {
|
102
|
+
// fetch document from nodejs/node main so we dont need to keep a copy
|
103
|
+
const response = await fetch(url);
|
104
|
+
const body = await response.text();
|
105
|
+
// remove everything before the Planning section
|
106
|
+
const index = body.indexOf('## Planning');
|
107
|
+
if (index !== -1) {
|
108
|
+
return body.substring(index);
|
109
|
+
}
|
110
|
+
return body;
|
111
|
+
} catch (error) {
|
112
|
+
this.cli.error(`Could not retrieve the security issue template from ${url}`);
|
112
113
|
}
|
113
114
|
}
|
114
115
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
const
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
getSecurityIssueTemplate() {
|
126
|
-
return fs.readFileSync(
|
127
|
-
new URL(
|
128
|
-
'./github/templates/next-security-release.md',
|
129
|
-
import.meta.url
|
130
|
-
),
|
131
|
-
'utf-8'
|
132
|
-
);
|
133
|
-
}
|
134
|
-
|
135
|
-
async promptReleaseDate(cli) {
|
136
|
-
return cli.prompt('Enter target release date in YYYY-MM-DD format:', {
|
137
|
-
questionType: 'input',
|
138
|
-
defaultAnswer: 'TBD'
|
139
|
-
});
|
116
|
+
async promptReleaseDate() {
|
117
|
+
const nextWeekDate = new Date();
|
118
|
+
nextWeekDate.setDate(nextWeekDate.getDate() + 7);
|
119
|
+
// Format the date as YYYY/MM/DD
|
120
|
+
const formattedDate = nextWeekDate.toISOString().slice(0, 10).replace(/-/g, '/');
|
121
|
+
return this.cli.prompt(
|
122
|
+
'Enter target release date in YYYY/MM/DD format (TBD if not defined yet):', {
|
123
|
+
questionType: 'input',
|
124
|
+
defaultAnswer: formattedDate
|
125
|
+
});
|
140
126
|
}
|
141
127
|
|
142
|
-
async promptVulnerabilitiesJSON(
|
143
|
-
return cli.prompt(
|
128
|
+
async promptVulnerabilitiesJSON() {
|
129
|
+
return this.cli.prompt(
|
144
130
|
'Create the vulnerabilities.json?',
|
145
131
|
{ defaultAnswer: true });
|
146
132
|
}
|
147
133
|
|
148
|
-
async promptCreateRelaseIssue(
|
149
|
-
return cli.prompt(
|
134
|
+
async promptCreateRelaseIssue() {
|
135
|
+
return this.cli.prompt(
|
150
136
|
'Create the Next Security Release issue?',
|
151
137
|
{ defaultAnswer: true });
|
152
138
|
}
|
153
139
|
|
154
|
-
async promptReviewVulnerabilitiesJSON(
|
155
|
-
return cli.prompt(
|
140
|
+
async promptReviewVulnerabilitiesJSON() {
|
141
|
+
return this.cli.prompt(
|
156
142
|
'Please review vulnerabilities.json and press enter to proceed.',
|
157
143
|
{ defaultAnswer: true });
|
158
144
|
}
|
159
145
|
|
160
|
-
buildIssue(releaseDate, securityReleasePRUrl) {
|
161
|
-
const template = this.getSecurityIssueTemplate();
|
146
|
+
async buildIssue(releaseDate, securityReleasePRUrl = PLACEHOLDERS.vulnerabilitiesPRURL) {
|
147
|
+
const template = await this.getSecurityIssueTemplate();
|
162
148
|
const content = template.replace(PLACEHOLDERS.releaseDate, releaseDate)
|
163
149
|
.replace(PLACEHOLDERS.vulnerabilitiesPRURL, securityReleasePRUrl);
|
164
|
-
return
|
165
|
-
}
|
166
|
-
|
167
|
-
async createIssue(content, { cli }) {
|
168
|
-
const data = await this.req.createIssue(this.title, content, this.repository);
|
169
|
-
if (data.html_url) {
|
170
|
-
cli.ok('Created: ' + data.html_url);
|
171
|
-
} else {
|
172
|
-
cli.error(data);
|
173
|
-
process.exit(1);
|
174
|
-
}
|
150
|
+
return content;
|
175
151
|
}
|
176
152
|
|
177
|
-
async chooseReports(
|
178
|
-
cli.info('Getting triaged H1 reports...');
|
153
|
+
async chooseReports() {
|
154
|
+
this.cli.info('Getting triaged H1 reports...');
|
179
155
|
const reports = await this.req.getTriagedReports();
|
180
|
-
const supportedVersions = (await nv('supported'))
|
181
|
-
.map((v) => v.versionName + '.x')
|
182
|
-
.join(',');
|
183
156
|
const selectedReports = [];
|
184
157
|
|
185
158
|
for (const report of reports.data) {
|
186
|
-
const
|
187
|
-
|
188
|
-
|
189
|
-
cli.info(`Report: ${id} - ${title} (${reportLevel})`);
|
190
|
-
const include = await cli.prompt(
|
191
|
-
'Would you like to include this report to the next security release?',
|
192
|
-
{ defaultAnswer: true });
|
193
|
-
if (!include) {
|
194
|
-
continue;
|
195
|
-
}
|
196
|
-
|
197
|
-
const versions = await cli.prompt('Which active release lines this report affects?', {
|
198
|
-
questionType: 'input',
|
199
|
-
defaultAnswer: supportedVersions
|
200
|
-
});
|
201
|
-
const summaryContent = await this.getSummary(id);
|
202
|
-
|
203
|
-
selectedReports.push({
|
204
|
-
id,
|
205
|
-
title,
|
206
|
-
cve_ids,
|
207
|
-
severity: reportLevel,
|
208
|
-
summary: summaryContent ?? '',
|
209
|
-
affectedVersions: versions.split(',').map((v) => v.replace('v', '').trim())
|
210
|
-
});
|
159
|
+
const rep = await pickReport(report, { cli: this.cli, req: this.req });
|
160
|
+
if (!rep) continue;
|
161
|
+
selectedReports.push(rep);
|
211
162
|
}
|
212
163
|
return selectedReports;
|
213
164
|
}
|
214
165
|
|
215
|
-
async
|
216
|
-
|
217
|
-
const summaryList = data?.relationships?.summaries?.data;
|
218
|
-
if (!summaryList?.length) return;
|
219
|
-
const summaries = summaryList.filter((summary) => summary?.attributes?.category === 'team');
|
220
|
-
if (!summaries?.length) return;
|
221
|
-
return summaries?.[0].attributes?.content;
|
222
|
-
}
|
223
|
-
|
224
|
-
checkoutOnSecurityReleaseBranch(cli) {
|
225
|
-
this.checkRemote(cli);
|
226
|
-
const currentBranch = runSync('git', ['branch', '--show-current']).trim();
|
227
|
-
cli.info(`Current branch: ${currentBranch} `);
|
228
|
-
|
229
|
-
if (currentBranch !== this.nextSecurityReleaseBranch) {
|
230
|
-
runSync('git', ['checkout', '-B', this.nextSecurityReleaseBranch]);
|
231
|
-
cli.ok(`Checkout on branch: ${this.nextSecurityReleaseBranch} `);
|
232
|
-
};
|
233
|
-
}
|
234
|
-
|
235
|
-
async createVulnerabilitiesJSON(reports, { cli }) {
|
236
|
-
cli.separator('Creating vulnerabilities.json...');
|
166
|
+
async createVulnerabilitiesJSON(reports, dependencies, releaseDate) {
|
167
|
+
this.cli.separator('Creating vulnerabilities.json...');
|
237
168
|
const file = JSON.stringify({
|
238
|
-
|
169
|
+
releaseDate,
|
170
|
+
reports,
|
171
|
+
dependencies
|
239
172
|
}, null, 2);
|
240
173
|
|
241
|
-
const folderPath = path.join(process.cwd(),
|
174
|
+
const folderPath = path.join(process.cwd(), NEXT_SECURITY_RELEASE_FOLDER);
|
242
175
|
try {
|
243
176
|
await fs.accessSync(folderPath);
|
244
177
|
} catch (error) {
|
@@ -247,14 +180,14 @@ class PrepareSecurityRelease {
|
|
247
180
|
|
248
181
|
const fullPath = path.join(folderPath, 'vulnerabilities.json');
|
249
182
|
fs.writeFileSync(fullPath, file);
|
250
|
-
cli.ok(`Created ${fullPath} `);
|
183
|
+
this.cli.ok(`Created ${fullPath} `);
|
251
184
|
|
252
185
|
return fullPath;
|
253
186
|
}
|
254
187
|
|
255
|
-
async createPullRequest(
|
188
|
+
async createPullRequest() {
|
256
189
|
const { owner, repo } = this.repository;
|
257
|
-
const response = await req.createPullRequest(
|
190
|
+
const response = await this.req.createPullRequest(
|
258
191
|
this.title,
|
259
192
|
'List of vulnerabilities to be included in the next security release',
|
260
193
|
{
|
@@ -267,17 +200,69 @@ class PrepareSecurityRelease {
|
|
267
200
|
);
|
268
201
|
const url = response?.html_url;
|
269
202
|
if (url) {
|
270
|
-
cli.ok(
|
203
|
+
this.cli.ok(`Created: ${url}`);
|
271
204
|
return url;
|
205
|
+
}
|
206
|
+
if (response?.errors) {
|
207
|
+
for (const error of response.errors) {
|
208
|
+
this.cli.error(error.message);
|
209
|
+
}
|
272
210
|
} else {
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
211
|
+
this.cli.error(response);
|
212
|
+
}
|
213
|
+
process.exit(1);
|
214
|
+
}
|
215
|
+
|
216
|
+
async getDependencyUpdates() {
|
217
|
+
const deps = [];
|
218
|
+
this.cli.log('\n');
|
219
|
+
this.cli.separator('Dependency Updates');
|
220
|
+
const updates = await this.cli.prompt('Are there dependency updates in this security release?',
|
221
|
+
{
|
222
|
+
defaultAnswer: true,
|
223
|
+
questionType: 'confirm'
|
224
|
+
});
|
225
|
+
|
226
|
+
if (!updates) return deps;
|
227
|
+
|
228
|
+
const supportedVersions = await getSupportedVersions();
|
229
|
+
|
230
|
+
let asking = true;
|
231
|
+
while (asking) {
|
232
|
+
const dep = await promptDependencies(this.cli);
|
233
|
+
if (!dep) {
|
234
|
+
asking = false;
|
235
|
+
break;
|
236
|
+
}
|
237
|
+
|
238
|
+
const name = await this.cli.prompt(
|
239
|
+
'What is the name of the dependency that has been updated?', {
|
240
|
+
defaultAnswer: '',
|
241
|
+
questionType: 'input'
|
242
|
+
});
|
243
|
+
|
244
|
+
const versions = await this.cli.prompt(
|
245
|
+
'Which release line does this dependency update affect?', {
|
246
|
+
defaultAnswer: supportedVersions,
|
247
|
+
questionType: 'input'
|
248
|
+
});
|
249
|
+
|
250
|
+
try {
|
251
|
+
const prUrl = dep.replace('https://github.com/', 'https://api.github.com/repos/').replace('pull', 'pulls');
|
252
|
+
const res = await this.req.getPullRequest(prUrl);
|
253
|
+
const { html_url, title } = res;
|
254
|
+
deps.push({
|
255
|
+
name,
|
256
|
+
url: html_url,
|
257
|
+
title,
|
258
|
+
affectedVersions: versions.split(',').map((v) => v.replace('v', '').trim())
|
259
|
+
});
|
260
|
+
this.cli.separator();
|
261
|
+
} catch (error) {
|
262
|
+
this.cli.error('Invalid PR url. Please provide a valid PR url.');
|
263
|
+
this.cli.error(error);
|
279
264
|
}
|
280
|
-
process.exit(1);
|
281
265
|
}
|
266
|
+
return deps;
|
282
267
|
}
|
283
268
|
}
|
package/lib/request.js
CHANGED
@@ -77,6 +77,18 @@ export default class Request {
|
|
77
77
|
return this.json(url, options);
|
78
78
|
}
|
79
79
|
|
80
|
+
async getPullRequest(url) {
|
81
|
+
const options = {
|
82
|
+
method: 'GET',
|
83
|
+
headers: {
|
84
|
+
Authorization: `Basic ${this.credentials.github}`,
|
85
|
+
'User-Agent': 'node-core-utils',
|
86
|
+
Accept: 'application/vnd.github+json'
|
87
|
+
}
|
88
|
+
};
|
89
|
+
return this.json(url, options);
|
90
|
+
}
|
91
|
+
|
80
92
|
async createPullRequest(title, body, { owner, repo, head, base }) {
|
81
93
|
const url = `https://api.github.com/repos/${owner}/${repo}/pulls`;
|
82
94
|
const options = {
|
@@ -132,6 +144,49 @@ export default class Request {
|
|
132
144
|
return this.json(url, options);
|
133
145
|
}
|
134
146
|
|
147
|
+
async getPrograms() {
|
148
|
+
const url = 'https://api.hackerone.com/v1/me/programs';
|
149
|
+
const options = {
|
150
|
+
method: 'GET',
|
151
|
+
headers: {
|
152
|
+
Authorization: `Basic ${this.credentials.h1}`,
|
153
|
+
'User-Agent': 'node-core-utils',
|
154
|
+
Accept: 'application/json'
|
155
|
+
}
|
156
|
+
};
|
157
|
+
return this.json(url, options);
|
158
|
+
}
|
159
|
+
|
160
|
+
async requestCVE(programId, opts) {
|
161
|
+
const url = `https://api.hackerone.com/v1/programs/${programId}/cve_requests`;
|
162
|
+
const options = {
|
163
|
+
method: 'POST',
|
164
|
+
headers: {
|
165
|
+
Authorization: `Basic ${this.credentials.h1}`,
|
166
|
+
'User-Agent': 'node-core-utils',
|
167
|
+
'Content-Type': 'application/json',
|
168
|
+
Accept: 'application/json'
|
169
|
+
},
|
170
|
+
body: JSON.stringify(opts)
|
171
|
+
};
|
172
|
+
return this.json(url, options);
|
173
|
+
}
|
174
|
+
|
175
|
+
async updateReportCVE(reportId, opts) {
|
176
|
+
const url = `https://api.hackerone.com/v1/reports/${reportId}/cves`;
|
177
|
+
const options = {
|
178
|
+
method: 'PUT',
|
179
|
+
headers: {
|
180
|
+
Authorization: `Basic ${this.credentials.h1}`,
|
181
|
+
'User-Agent': 'node-core-utils',
|
182
|
+
Accept: 'application/json',
|
183
|
+
'Content-Type': 'application/json'
|
184
|
+
},
|
185
|
+
body: JSON.stringify(opts)
|
186
|
+
};
|
187
|
+
return this.json(url, options);
|
188
|
+
}
|
189
|
+
|
135
190
|
async getReport(reportId) {
|
136
191
|
const url = `https://api.hackerone.com/v1/reports/${reportId}`;
|
137
192
|
const options = {
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import {
|
2
|
+
NEXT_SECURITY_RELEASE_REPOSITORY,
|
3
|
+
checkoutOnSecurityReleaseBranch,
|
4
|
+
getVulnerabilitiesJSON,
|
5
|
+
validateDate,
|
6
|
+
formatDateToYYYYMMDD,
|
7
|
+
createIssue
|
8
|
+
} from './security-release/security-release.js';
|
9
|
+
import auth from './auth.js';
|
10
|
+
import Request from './request.js';
|
11
|
+
|
12
|
+
export default class SecurityAnnouncement {
|
13
|
+
repository = NEXT_SECURITY_RELEASE_REPOSITORY;
|
14
|
+
req;
|
15
|
+
constructor(cli) {
|
16
|
+
this.cli = cli;
|
17
|
+
}
|
18
|
+
|
19
|
+
async notifyPreRelease() {
|
20
|
+
const { cli } = this;
|
21
|
+
|
22
|
+
const credentials = await auth({
|
23
|
+
github: true,
|
24
|
+
h1: true
|
25
|
+
});
|
26
|
+
|
27
|
+
this.req = new Request(credentials);
|
28
|
+
|
29
|
+
// checkout on security release branch
|
30
|
+
checkoutOnSecurityReleaseBranch(cli, this.repository);
|
31
|
+
// read vulnerabilities JSON file
|
32
|
+
const content = getVulnerabilitiesJSON(cli);
|
33
|
+
// validate the release date read from vulnerabilities JSON
|
34
|
+
if (!content.releaseDate) {
|
35
|
+
cli.error('Release date is not set in vulnerabilities.json,' +
|
36
|
+
' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
|
37
|
+
process.exit(1);
|
38
|
+
}
|
39
|
+
|
40
|
+
validateDate(content.releaseDate);
|
41
|
+
const releaseDate = new Date(content.releaseDate);
|
42
|
+
|
43
|
+
await Promise.all([
|
44
|
+
this.createDockerNodeIssue(releaseDate),
|
45
|
+
this.createBuildWGIssue(releaseDate)
|
46
|
+
]);
|
47
|
+
}
|
48
|
+
|
49
|
+
async createBuildWGIssue(releaseDate) {
|
50
|
+
const repository = {
|
51
|
+
owner: 'nodejs',
|
52
|
+
repo: 'build'
|
53
|
+
};
|
54
|
+
|
55
|
+
const { title, content } = this.createPreleaseAnnouncementIssue(releaseDate, 'build');
|
56
|
+
await this.createIssue(title, content, repository);
|
57
|
+
}
|
58
|
+
|
59
|
+
createPreleaseAnnouncementIssue(releaseDate, team) {
|
60
|
+
const title = `[NEXT-SECURITY-RELEASE] Heads up on upcoming Node.js\
|
61
|
+
security release ${formatDateToYYYYMMDD(releaseDate)}`;
|
62
|
+
const content = `As per security release workflow,\
|
63
|
+
creating issue to give the ${team} team a heads up.`;
|
64
|
+
return { title, content };
|
65
|
+
}
|
66
|
+
|
67
|
+
async createDockerNodeIssue(releaseDate) {
|
68
|
+
const repository = {
|
69
|
+
owner: 'nodejs',
|
70
|
+
repo: 'docker-node'
|
71
|
+
};
|
72
|
+
|
73
|
+
const { title, content } = this.createPreleaseAnnouncementIssue(releaseDate, 'docker');
|
74
|
+
await createIssue(title, content, repository, { cli: this.cli, repository: this.repository });
|
75
|
+
}
|
76
|
+
}
|