@node-core/utils 5.3.0 → 5.4.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/components/git/security.js +1 -1
- package/lib/pr_checker.js +4 -3
- package/lib/prepare_release.js +2 -2
- package/lib/prepare_security.js +8 -18
- package/lib/security-announcement.js +2 -2
- package/lib/security_blog.js +20 -35
- package/lib/update-v8/applyNodeChanges.js +2 -4
- package/lib/update-v8/backport.js +6 -7
- package/lib/update-v8/majorUpdate.js +2 -4
- package/lib/update-v8/minorUpdate.js +2 -4
- package/lib/update-v8/updateV8Clone.js +2 -4
- package/lib/update-v8/updateVersionNumbers.js +2 -4
- package/package.json +10 -10
@@ -79,7 +79,7 @@ export function builder(yargs) {
|
|
79
79
|
'Request CVEs for a security release of Node.js based on' +
|
80
80
|
' the next-security-release/vulnerabilities.json'
|
81
81
|
).example(
|
82
|
-
'git node security --post-release'
|
82
|
+
'git node security --post-release',
|
83
83
|
'Create the post-release announcement on the Nodejs.org repo'
|
84
84
|
);
|
85
85
|
}
|
package/lib/pr_checker.js
CHANGED
@@ -29,6 +29,7 @@ const GITHUB_SUCCESS_CONCLUSIONS = ['SUCCESS', 'NEUTRAL', 'SKIPPED'];
|
|
29
29
|
const FAST_TRACK_RE = /^Fast-track has been requested by @(.+?)\. Please 👍 to approve\.$/;
|
30
30
|
const FAST_TRACK_MIN_APPROVALS = 2;
|
31
31
|
const GIT_CONFIG_GUIDE_URL = 'https://github.com/nodejs/node/blob/99b1ada/doc/guides/contributing/pull-requests.md#step-1-fork';
|
32
|
+
const IGNORED_CHECK_SLUGS = ['dependabot', 'codecov'];
|
32
33
|
|
33
34
|
// eslint-disable-next-line no-extend-native
|
34
35
|
Array.prototype.findLastIndex ??= function findLastIndex(fn) {
|
@@ -373,9 +374,9 @@ export default class PRChecker {
|
|
373
374
|
|
374
375
|
// GitHub new Check API
|
375
376
|
for (const { status, conclusion, app } of checkSuites.nodes) {
|
376
|
-
if (app && app.slug
|
377
|
-
// Ignore Dependabot check suites.
|
378
|
-
// sometimes and never complete.
|
377
|
+
if (app && IGNORED_CHECK_SLUGS.includes(app.slug)) {
|
378
|
+
// Ignore Dependabot and Codecov check suites.
|
379
|
+
// They are expected to show up sometimes and never complete.
|
379
380
|
continue;
|
380
381
|
}
|
381
382
|
|
package/lib/prepare_release.js
CHANGED
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
2
2
|
import { promises as fs } from 'node:fs';
|
3
3
|
|
4
4
|
import semver from 'semver';
|
5
|
-
import
|
5
|
+
import { replaceInFile } from 'replace-in-file';
|
6
6
|
|
7
7
|
import { getMergedConfig } from './config.js';
|
8
8
|
import { runAsync, runSync } from './run.js';
|
@@ -427,7 +427,7 @@ export default class ReleasePreparation {
|
|
427
427
|
async updateREPLACEMEs() {
|
428
428
|
const { newVersion } = this;
|
429
429
|
|
430
|
-
await
|
430
|
+
await replaceInFile({
|
431
431
|
files: 'doc/api/*.md',
|
432
432
|
from: /REPLACEME/g,
|
433
433
|
to: `v${newVersion}`
|
package/lib/prepare_security.js
CHANGED
@@ -6,7 +6,6 @@ import {
|
|
6
6
|
NEXT_SECURITY_RELEASE_BRANCH,
|
7
7
|
NEXT_SECURITY_RELEASE_FOLDER,
|
8
8
|
NEXT_SECURITY_RELEASE_REPOSITORY,
|
9
|
-
PLACEHOLDERS,
|
10
9
|
checkoutOnSecurityReleaseBranch,
|
11
10
|
commitAndPushVulnerabilitiesJSON,
|
12
11
|
validateDate,
|
@@ -37,22 +36,15 @@ export default class PrepareSecurityRelease {
|
|
37
36
|
const createVulnerabilitiesJSON = await this.promptVulnerabilitiesJSON();
|
38
37
|
|
39
38
|
let securityReleasePRUrl;
|
39
|
+
const content = await this.buildDescription(releaseDate, securityReleasePRUrl);
|
40
40
|
if (createVulnerabilitiesJSON) {
|
41
|
-
securityReleasePRUrl = await this.startVulnerabilitiesJSONCreation(releaseDate);
|
41
|
+
securityReleasePRUrl = await this.startVulnerabilitiesJSONCreation(releaseDate, content);
|
42
42
|
}
|
43
43
|
|
44
|
-
const createIssue = await this.promptCreateRelaseIssue();
|
45
|
-
|
46
|
-
if (createIssue) {
|
47
|
-
const content = await this.buildIssue(releaseDate, securityReleasePRUrl);
|
48
|
-
await createIssue(
|
49
|
-
this.title, content, this.repository, { cli: this.cli, repository: this.repository });
|
50
|
-
};
|
51
|
-
|
52
44
|
this.cli.ok('Done!');
|
53
45
|
}
|
54
46
|
|
55
|
-
async startVulnerabilitiesJSONCreation(releaseDate) {
|
47
|
+
async startVulnerabilitiesJSONCreation(releaseDate, content) {
|
56
48
|
// checkout on the next-security-release branch
|
57
49
|
checkoutOnSecurityReleaseBranch(this.cli, this.repository);
|
58
50
|
|
@@ -87,7 +79,7 @@ export default class PrepareSecurityRelease {
|
|
87
79
|
if (!createPr) return;
|
88
80
|
|
89
81
|
// create pr on the security-release repo
|
90
|
-
return this.createPullRequest();
|
82
|
+
return this.createPullRequest(content);
|
91
83
|
}
|
92
84
|
|
93
85
|
promptCreatePR() {
|
@@ -143,11 +135,9 @@ export default class PrepareSecurityRelease {
|
|
143
135
|
{ defaultAnswer: true });
|
144
136
|
}
|
145
137
|
|
146
|
-
async
|
138
|
+
async buildDescription() {
|
147
139
|
const template = await this.getSecurityIssueTemplate();
|
148
|
-
|
149
|
-
.replace(PLACEHOLDERS.vulnerabilitiesPRURL, securityReleasePRUrl);
|
150
|
-
return content;
|
140
|
+
return template;
|
151
141
|
}
|
152
142
|
|
153
143
|
async chooseReports() {
|
@@ -185,11 +175,11 @@ export default class PrepareSecurityRelease {
|
|
185
175
|
return fullPath;
|
186
176
|
}
|
187
177
|
|
188
|
-
async createPullRequest() {
|
178
|
+
async createPullRequest(content) {
|
189
179
|
const { owner, repo } = this.repository;
|
190
180
|
const response = await this.req.createPullRequest(
|
191
181
|
this.title,
|
192
|
-
'List of vulnerabilities to be included in the next security release',
|
182
|
+
content ?? 'List of vulnerabilities to be included in the next security release',
|
193
183
|
{
|
194
184
|
owner,
|
195
185
|
repo,
|
@@ -53,7 +53,7 @@ export default class SecurityAnnouncement {
|
|
53
53
|
};
|
54
54
|
|
55
55
|
const { title, content } = this.createPreleaseAnnouncementIssue(releaseDate, 'build');
|
56
|
-
await
|
56
|
+
await createIssue(title, content, repository, { cli: this.cli, req: this.req });
|
57
57
|
}
|
58
58
|
|
59
59
|
createPreleaseAnnouncementIssue(releaseDate, team) {
|
@@ -71,6 +71,6 @@ export default class SecurityAnnouncement {
|
|
71
71
|
};
|
72
72
|
|
73
73
|
const { title, content } = this.createPreleaseAnnouncementIssue(releaseDate, 'docker');
|
74
|
-
await createIssue(title, content, repository, { cli: this.cli,
|
74
|
+
await createIssue(title, content, repository, { cli: this.cli, req: this.req });
|
75
75
|
}
|
76
76
|
}
|
package/lib/security_blog.js
CHANGED
@@ -8,7 +8,6 @@ import {
|
|
8
8
|
checkoutOnSecurityReleaseBranch,
|
9
9
|
NEXT_SECURITY_RELEASE_REPOSITORY,
|
10
10
|
validateDate,
|
11
|
-
getSummary,
|
12
11
|
commitAndPushVulnerabilitiesJSON,
|
13
12
|
NEXT_SECURITY_RELEASE_FOLDER
|
14
13
|
} from './security-release/security-release.js';
|
@@ -84,6 +83,7 @@ export default class SecurityBlog {
|
|
84
83
|
const releaseDate = new Date(content.releaseDate);
|
85
84
|
const template = this.getSecurityPostReleaseTemplate();
|
86
85
|
const data = {
|
86
|
+
// TODO: read from pre-sec-release
|
87
87
|
annoucementDate: await this.getAnnouncementDate(cli),
|
88
88
|
releaseDate: this.formatReleaseDate(releaseDate),
|
89
89
|
affectedVersions: this.getAffectedVersions(content),
|
@@ -205,46 +205,25 @@ export default class SecurityBlog {
|
|
205
205
|
const reports = content.reports;
|
206
206
|
let template = '';
|
207
207
|
for (const report of reports) {
|
208
|
-
|
208
|
+
const cveId = report.cveIds?.join(', ');
|
209
209
|
if (!cveId) {
|
210
|
-
|
211
|
-
|
212
|
-
cveId = await this.cli.prompt(`What is the CVE ID for vulnerability https://hackerone.com/reports/${report.id} ${report.title}?`, {
|
213
|
-
questionType: 'input',
|
214
|
-
defaultAnswer: 'TBD'
|
215
|
-
});
|
216
|
-
report.cve_ids = [cveId];
|
217
|
-
content[kChanged] = true;
|
210
|
+
this.cli.error(`CVE ID for vulnerability ${report.link} ${report.title} not found`);
|
211
|
+
process.exit(1);
|
218
212
|
}
|
219
213
|
template += `## ${report.title} (${cveId}) - (${report.severity.rating})\n\n`;
|
220
214
|
if (!report.summary) {
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
defaultAnswer: true
|
225
|
-
});
|
226
|
-
|
227
|
-
if (fetchIt) {
|
228
|
-
report.summary = await getSummary(report.id, this.req);
|
229
|
-
content[kChanged] = true;
|
230
|
-
}
|
231
|
-
|
232
|
-
if (!report.summary) {
|
233
|
-
this.cli.error(`Summary missing for vulnerability https://hackerone.com/reports/${report.id} ${report.title}. Please create it before continuing.`);
|
234
|
-
process.exit(1);
|
235
|
-
}
|
215
|
+
this.cli.error(`Summary missing for vulnerability ${report.link} ` +
|
216
|
+
`${report.title}. Please create it before continuing.`);
|
217
|
+
process.exit(1);
|
236
218
|
}
|
219
|
+
|
237
220
|
template += `${report.summary}\n\n`;
|
238
221
|
const releaseLines = report.affectedVersions.join(', ');
|
239
222
|
template += `Impact:\n\n- This vulnerability affects all users\
|
240
223
|
in active release lines: ${releaseLines}\n\n`;
|
241
224
|
if (!report.patchAuthors) {
|
242
|
-
|
243
|
-
|
244
|
-
defaultAnswer: 'TBD'
|
245
|
-
});
|
246
|
-
report.patchAuthors = author.split('&').map((p) => p.trim());
|
247
|
-
content[kChanged] = true;
|
225
|
+
this.cli.error(`Missing patch author for vulnerability ${report.link} ${report.title}`);
|
226
|
+
process.exit(1);
|
248
227
|
}
|
249
228
|
template += `Thank you, to ${report.reporter} for reporting this vulnerability\
|
250
229
|
and thank you ${report.patchAuthors.join(' and ')} for fixing it.\n\n`;
|
@@ -253,9 +232,10 @@ export default class SecurityBlog {
|
|
253
232
|
}
|
254
233
|
|
255
234
|
getDependencyUpdatesTemplate(dependencyUpdates) {
|
256
|
-
if (
|
257
|
-
|
258
|
-
|
235
|
+
if (typeof dependencyUpdates !== 'object') return '';
|
236
|
+
if (Object.keys(dependencyUpdates).length === 0) return '';
|
237
|
+
let template = '\nThis security release includes the following dependency' +
|
238
|
+
' updates to address public vulnerabilities:\n';
|
259
239
|
for (const dependencyUpdate of Object.values(dependencyUpdates)) {
|
260
240
|
for (const dependency of dependencyUpdate) {
|
261
241
|
const title = dependency.title.substring(dependency.title.indexOf(':') + ':'.length).trim();
|
@@ -351,7 +331,12 @@ export default class SecurityBlog {
|
|
351
331
|
affectedVersions.add(affectedVersion);
|
352
332
|
}
|
353
333
|
}
|
354
|
-
|
334
|
+
const parseToNumber = str => +(str.match(/[\d.]+/g)[0]);
|
335
|
+
return Array.from(affectedVersions)
|
336
|
+
.sort((a, b) => {
|
337
|
+
return parseToNumber(a) > parseToNumber(b) ? -1 : 1;
|
338
|
+
})
|
339
|
+
.join(', ');
|
355
340
|
}
|
356
341
|
|
357
342
|
getSecurityPreReleaseTemplate() {
|
@@ -1,7 +1,5 @@
|
|
1
1
|
import path from 'node:path';
|
2
2
|
|
3
|
-
import { Listr } from 'listr2';
|
4
|
-
|
5
3
|
import {
|
6
4
|
getNodeV8Version,
|
7
5
|
filterForVersion,
|
@@ -19,10 +17,10 @@ const nodeChanges = [
|
|
19
17
|
export default function applyNodeChanges() {
|
20
18
|
return {
|
21
19
|
title: 'Apply Node-specific changes',
|
22
|
-
task: async(ctx) => {
|
20
|
+
task: async(ctx, task) => {
|
23
21
|
const v8Version = await getNodeV8Version(ctx.nodeDir);
|
24
22
|
const list = filterForVersion(nodeChanges, v8Version);
|
25
|
-
return
|
23
|
+
return task.newListr(list.map((change) => change.task()));
|
26
24
|
}
|
27
25
|
};
|
28
26
|
}
|
@@ -4,7 +4,6 @@ import {
|
|
4
4
|
} from 'node:fs';
|
5
5
|
|
6
6
|
import inquirer from 'inquirer';
|
7
|
-
import { Listr } from 'listr2';
|
8
7
|
import { ListrEnquirerPromptAdapter } from '@listr2/prompt-adapter-enquirer';
|
9
8
|
|
10
9
|
import { shortSha } from '../utils.js';
|
@@ -50,8 +49,8 @@ export function doBackport(options) {
|
|
50
49
|
|
51
50
|
return {
|
52
51
|
title: 'V8 commit backport',
|
53
|
-
task: () => {
|
54
|
-
return
|
52
|
+
task: (ctx, task) => {
|
53
|
+
return task.newListr(todo);
|
55
54
|
}
|
56
55
|
};
|
57
56
|
};
|
@@ -164,8 +163,8 @@ function applyPatches() {
|
|
164
163
|
function applyAndCommitPatches() {
|
165
164
|
return {
|
166
165
|
title: 'Apply and commit patches to deps/v8',
|
167
|
-
task: (ctx) => {
|
168
|
-
return
|
166
|
+
task: (ctx, task) => {
|
167
|
+
return task.newListr(ctx.patches.map(applyPatchTask));
|
169
168
|
}
|
170
169
|
};
|
171
170
|
}
|
@@ -173,7 +172,7 @@ function applyAndCommitPatches() {
|
|
173
172
|
function applyPatchTask(patch) {
|
174
173
|
return {
|
175
174
|
title: `Commit ${shortSha(patch.sha)}`,
|
176
|
-
task: (ctx) => {
|
175
|
+
task: (ctx, task) => {
|
177
176
|
const todo = [
|
178
177
|
{
|
179
178
|
title: 'Apply patch',
|
@@ -188,7 +187,7 @@ function applyPatchTask(patch) {
|
|
188
187
|
}
|
189
188
|
}
|
190
189
|
todo.push(commitPatch(patch));
|
191
|
-
return
|
190
|
+
return task.newListr(todo);
|
192
191
|
}
|
193
192
|
};
|
194
193
|
}
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import path from 'node:path';
|
2
2
|
import { promises as fs } from 'node:fs';
|
3
3
|
|
4
|
-
import { Listr } from 'listr2';
|
5
|
-
|
6
4
|
import { getCurrentV8Version } from './common.js';
|
7
5
|
import {
|
8
6
|
getNodeV8Version,
|
@@ -19,8 +17,8 @@ import { forceRunAsync } from '../run.js';
|
|
19
17
|
export default function majorUpdate() {
|
20
18
|
return {
|
21
19
|
title: 'Major V8 update',
|
22
|
-
task: () => {
|
23
|
-
return
|
20
|
+
task: (ctx, task) => {
|
21
|
+
return task.newListr([
|
24
22
|
getCurrentV8Version(),
|
25
23
|
checkoutBranch(),
|
26
24
|
removeDepsV8(),
|
@@ -2,8 +2,6 @@ import { spawn } from 'node:child_process';
|
|
2
2
|
import path from 'node:path';
|
3
3
|
import { promises as fs } from 'node:fs';
|
4
4
|
|
5
|
-
import { Listr } from 'listr2';
|
6
|
-
|
7
5
|
import { getCurrentV8Version } from './common.js';
|
8
6
|
import { isVersionString } from './util.js';
|
9
7
|
import { forceRunAsync } from '../run.js';
|
@@ -11,8 +9,8 @@ import { forceRunAsync } from '../run.js';
|
|
11
9
|
export default function minorUpdate() {
|
12
10
|
return {
|
13
11
|
title: 'Minor V8 update',
|
14
|
-
task: () => {
|
15
|
-
return
|
12
|
+
task: (ctx, task) => {
|
13
|
+
return task.newListr([
|
16
14
|
getCurrentV8Version(),
|
17
15
|
getLatestV8Version(),
|
18
16
|
doMinorUpdate()
|
@@ -1,15 +1,13 @@
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
2
2
|
|
3
|
-
import { Listr } from 'listr2';
|
4
|
-
|
5
3
|
import { v8Git } from './constants.js';
|
6
4
|
import { forceRunAsync } from '../run.js';
|
7
5
|
|
8
6
|
export default function updateV8Clone() {
|
9
7
|
return {
|
10
8
|
title: 'Update local V8 clone',
|
11
|
-
task: () => {
|
12
|
-
return
|
9
|
+
task: (ctx, task) => {
|
10
|
+
return task.newListr([fetchOrigin(), createClone()]);
|
13
11
|
}
|
14
12
|
};
|
15
13
|
};
|
@@ -1,15 +1,13 @@
|
|
1
1
|
import path from 'node:path';
|
2
2
|
import { promises as fs } from 'node:fs';
|
3
3
|
|
4
|
-
import { Listr } from 'listr2';
|
5
|
-
|
6
4
|
import { getNodeV8Version } from './util.js';
|
7
5
|
|
8
6
|
export default function updateVersionNumbers() {
|
9
7
|
return {
|
10
8
|
title: 'Update version numbers',
|
11
|
-
task: () => {
|
12
|
-
return
|
9
|
+
task: (ctx, task) => {
|
10
|
+
return task.newListr([resetEmbedderString(), bumpNodeModule()]);
|
13
11
|
}
|
14
12
|
};
|
15
13
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@node-core/utils",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.4.0",
|
4
4
|
"description": "Utilities for Node.js core collaborators",
|
5
5
|
"type": "module",
|
6
6
|
"engines": {
|
@@ -34,8 +34,8 @@
|
|
34
34
|
],
|
35
35
|
"license": "MIT",
|
36
36
|
"dependencies": {
|
37
|
-
"@listr2/prompt-adapter-enquirer": "^2.0.
|
38
|
-
"@node-core/caritat": "^1.
|
37
|
+
"@listr2/prompt-adapter-enquirer": "^2.0.10",
|
38
|
+
"@node-core/caritat": "^1.6.0",
|
39
39
|
"@pkgjs/nv": "^0.2.2",
|
40
40
|
"branch-diff": "^3.0.4",
|
41
41
|
"chalk": "^5.3.0",
|
@@ -44,26 +44,26 @@
|
|
44
44
|
"clipboardy": "^4.0.0",
|
45
45
|
"core-validate-commit": "^4.0.0",
|
46
46
|
"figures": "^6.1.0",
|
47
|
-
"ghauth": "^6.0.
|
48
|
-
"inquirer": "^9.2
|
47
|
+
"ghauth": "^6.0.5",
|
48
|
+
"inquirer": "^9.3.2",
|
49
49
|
"js-yaml": "^4.1.0",
|
50
|
-
"listr2": "^8.2.
|
50
|
+
"listr2": "^8.2.3",
|
51
51
|
"lodash": "^4.17.21",
|
52
52
|
"log-symbols": "^6.0.0",
|
53
53
|
"ora": "^8.0.1",
|
54
|
-
"replace-in-file": "^
|
55
|
-
"undici": "^6.
|
54
|
+
"replace-in-file": "^8.0.2",
|
55
|
+
"undici": "^6.19.2",
|
56
56
|
"which": "^4.0.0",
|
57
57
|
"yargs": "^17.7.2"
|
58
58
|
},
|
59
59
|
"devDependencies": {
|
60
60
|
"@reporters/github": "^1.7.0",
|
61
|
-
"c8": "^
|
61
|
+
"c8": "^10.1.2",
|
62
62
|
"eslint": "^8.57.0",
|
63
63
|
"eslint-config-standard": "^17.1.0",
|
64
64
|
"eslint-plugin-import": "^2.29.1",
|
65
65
|
"eslint-plugin-n": "^16.6.2",
|
66
|
-
"eslint-plugin-promise": "^6.
|
66
|
+
"eslint-plugin-promise": "^6.4.0",
|
67
67
|
"sinon": "^18.0.0"
|
68
68
|
}
|
69
69
|
}
|