@node-core/utils 5.8.0 → 5.10.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/lib/prepare_release.js +19 -5
- package/lib/promote_release.js +23 -0
- package/lib/security_blog.js +31 -32
- package/lib/update-v8/constants.js +12 -0
- package/lib/update_security_release.js +4 -1
- package/package.json +14 -14
package/lib/prepare_release.js
CHANGED
@@ -363,8 +363,14 @@ export default class ReleasePreparation extends Session {
|
|
363
363
|
try {
|
364
364
|
runSync('git', ['rev-parse', tagName]);
|
365
365
|
} catch {
|
366
|
-
this.cli.
|
367
|
-
|
366
|
+
this.cli.error(`Error parsing git ref ${tagName}`);
|
367
|
+
this.cli.startSpinner('Attempting fetching it as a tag\n');
|
368
|
+
try {
|
369
|
+
runSync('git', ['fetch', this.upstream, 'tag', '-n', tagName]);
|
370
|
+
} catch (e) {
|
371
|
+
this.cli.error(`${e.message}\nRun: git remote update`);
|
372
|
+
process.exit(1);
|
373
|
+
}
|
368
374
|
this.cli.stopSpinner(`Tag fetched: ${tagName}`);
|
369
375
|
}
|
370
376
|
try {
|
@@ -765,7 +771,7 @@ export default class ReleasePreparation extends Session {
|
|
765
771
|
}
|
766
772
|
|
767
773
|
async prepareLocalBranch() {
|
768
|
-
const { cli } = this;
|
774
|
+
const { cli, isSecurityRelease } = this;
|
769
775
|
if (this.newVersion) {
|
770
776
|
// If the CLI asked for a specific version:
|
771
777
|
const newVersion = semver.parse(this.newVersion);
|
@@ -789,11 +795,19 @@ export default class ReleasePreparation extends Session {
|
|
789
795
|
// Otherwise, we need to figure out what's the next version number for the
|
790
796
|
// release line of the branch that's currently checked out.
|
791
797
|
const currentBranch = this.getCurrentBranch();
|
792
|
-
const match = /^v(\d+)\.x-staging$/.exec(currentBranch);
|
793
798
|
|
799
|
+
// In security releases vN.x branch is the base
|
800
|
+
let regex = /^v(\d+)\.x-staging$/;
|
801
|
+
let targetBranch = 'vN.x-staging';
|
802
|
+
if (isSecurityRelease) {
|
803
|
+
regex = /^v(\d+)\.x$/;
|
804
|
+
targetBranch = 'vN.x';
|
805
|
+
}
|
806
|
+
|
807
|
+
const match = regex.exec(currentBranch);
|
794
808
|
if (!match) {
|
795
809
|
cli.warn(`Cannot prepare a release from ${currentBranch
|
796
|
-
|
810
|
+
}. Switch to a ${targetBranch} branch before proceeding.`);
|
797
811
|
return;
|
798
812
|
}
|
799
813
|
this.stagingBranch = currentBranch;
|
package/lib/promote_release.js
CHANGED
@@ -131,6 +131,7 @@ export default class ReleasePromotion extends Session {
|
|
131
131
|
throw new Error('Aborted');
|
132
132
|
}
|
133
133
|
await this.secureTagRelease();
|
134
|
+
await this.verifyTagSignature();
|
134
135
|
|
135
136
|
// Set up for next release.
|
136
137
|
cli.startSpinner('Setting up for next release');
|
@@ -223,6 +224,28 @@ export default class ReleasePromotion extends Session {
|
|
223
224
|
this.isLTS ? '=false' : ''} --title=${JSON.stringify(this.releaseTitle)} --notes-file -`);
|
224
225
|
}
|
225
226
|
|
227
|
+
async verifyTagSignature() {
|
228
|
+
const { cli, version } = this;
|
229
|
+
const [needle, haystack] = await Promise.all([forceRunAsync(
|
230
|
+
'git', ['--no-pager',
|
231
|
+
'log', '-1',
|
232
|
+
`refs/tags/v${version}`,
|
233
|
+
'--format=* **%an** <<%ae>>\n `%GF`'
|
234
|
+
], { captureStdout: true }), fs.readFile('README.md')]);
|
235
|
+
if (haystack.includes(needle)) {
|
236
|
+
return;
|
237
|
+
}
|
238
|
+
cli.warn('Tag was signed with an undocumented identity/key pair!');
|
239
|
+
cli.info('Expected to find the following entry in the README:');
|
240
|
+
cli.info(needle);
|
241
|
+
cli.info('If you are using a subkey, it might be OK.');
|
242
|
+
cli.info(`Otherwise consider removing the tag (git tag -d v${version
|
243
|
+
}), check your local config, and start the process over.`);
|
244
|
+
if (!await cli.prompt('Do you want to proceed anyway?', { defaultAnswer: false })) {
|
245
|
+
throw new Error('Aborted');
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
226
249
|
async verifyPRAttributes() {
|
227
250
|
const { cli, prid, owner, repo, req } = this;
|
228
251
|
|
package/lib/security_blog.js
CHANGED
@@ -47,7 +47,7 @@ export default class SecurityBlog extends SecurityRelease {
|
|
47
47
|
const fileNameExt = fileName + '.md';
|
48
48
|
const preRelease = this.buildPreRelease(template, data);
|
49
49
|
|
50
|
-
const pathToBlogPosts = 'apps/site/pages/en/blog/
|
50
|
+
const pathToBlogPosts = 'apps/site/pages/en/blog/vulnerability';
|
51
51
|
const pathToBannerJson = 'apps/site/site.json';
|
52
52
|
|
53
53
|
const file = path.resolve(process.cwd(), nodejsOrgFolder, pathToBlogPosts, fileNameExt);
|
@@ -101,7 +101,7 @@ export default class SecurityBlog extends SecurityRelease {
|
|
101
101
|
dependencyUpdates: content.dependencies
|
102
102
|
};
|
103
103
|
|
104
|
-
const pathToBlogPosts = path.resolve(nodejsOrgFolder, 'apps/site/pages/en/blog/
|
104
|
+
const pathToBlogPosts = path.resolve(nodejsOrgFolder, 'apps/site/pages/en/blog/vulnerability');
|
105
105
|
const pathToBannerJson = path.resolve(nodejsOrgFolder, 'apps/site/site.json');
|
106
106
|
|
107
107
|
const preReleasePath = path.resolve(pathToBlogPosts, data.slug + '.md');
|
@@ -161,7 +161,7 @@ export default class SecurityBlog extends SecurityRelease {
|
|
161
161
|
link: content.link ?? currentValue.link,
|
162
162
|
type: content.type ?? currentValue.type
|
163
163
|
};
|
164
|
-
fs.writeFileSync(siteJsonPath, JSON.stringify(siteJson, null, 2));
|
164
|
+
fs.writeFileSync(siteJsonPath, JSON.stringify(siteJson, null, 2) + '\n');
|
165
165
|
}
|
166
166
|
|
167
167
|
formatReleaseDate(releaseDate) {
|
@@ -250,12 +250,8 @@ export default class SecurityBlog extends SecurityRelease {
|
|
250
250
|
if (Object.keys(dependencyUpdates).length === 0) return '';
|
251
251
|
let template = '\nThis security release includes the following dependency' +
|
252
252
|
' updates to address public vulnerabilities:\n';
|
253
|
-
for (const
|
254
|
-
|
255
|
-
const title = dependency.title.substring(dependency.title.indexOf(':') + ':'.length).trim();
|
256
|
-
template += `- ${title}\
|
257
|
-
on ${dependency.affectedVersions.join(', ')}\n`;
|
258
|
-
}
|
253
|
+
for (const [dependency, { versions, affectedVersions }] of Object.entries(dependencyUpdates)) {
|
254
|
+
template += `- ${dependency} (${versions.join(', ')}) on ${affectedVersions.join(', ')}\n`;
|
259
255
|
}
|
260
256
|
return template;
|
261
257
|
}
|
@@ -299,34 +295,37 @@ export default class SecurityBlog extends SecurityRelease {
|
|
299
295
|
}
|
300
296
|
|
301
297
|
getImpact(content) {
|
302
|
-
const impact =
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
acc[affectedVersion] = [report];
|
308
|
-
}
|
298
|
+
const impact = new Map();
|
299
|
+
for (const report of content.reports) {
|
300
|
+
for (const version of report.affectedVersions) {
|
301
|
+
if (!impact.has(version)) impact.set(version, []);
|
302
|
+
impact.get(version).push(report);
|
309
303
|
}
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
304
|
+
}
|
305
|
+
|
306
|
+
const result = Array.from(impact.entries())
|
307
|
+
.sort(([a], [b]) => b.localeCompare(a)) // DESC
|
308
|
+
.map(([version, reports]) => {
|
309
|
+
const severityCount = new Map();
|
310
|
+
|
311
|
+
for (const report of reports) {
|
312
|
+
const rating = report.severity.rating?.toLowerCase();
|
313
|
+
if (!rating) {
|
314
|
+
this.cli.error(`severity.rating not found for report ${report.id}.`);
|
320
315
|
process.exit(1);
|
321
316
|
}
|
322
|
-
|
323
|
-
|
324
|
-
}).join(', ');
|
317
|
+
severityCount.set(rating, (severityCount.get(rating) || 0) + 1);
|
318
|
+
}
|
325
319
|
|
326
|
-
|
327
|
-
|
320
|
+
const groupedByRating = Array.from(severityCount.entries())
|
321
|
+
.map(([rating, count]) => `${count} ${rating} severity issues`)
|
322
|
+
.join(', ');
|
323
|
+
|
324
|
+
return `The ${version} release line of Node.js is vulnerable to ${groupedByRating}.`;
|
325
|
+
})
|
326
|
+
.join('\n');
|
328
327
|
|
329
|
-
return
|
328
|
+
return result;
|
330
329
|
}
|
331
330
|
|
332
331
|
getVulnerabilities(content) {
|
@@ -41,6 +41,9 @@ const fp16Ignore = `!/third_party/fp16
|
|
41
41
|
const fastFloatReplace = `/third_party/fast_float/src/*
|
42
42
|
!/third_party/fast_float/src/include`;
|
43
43
|
|
44
|
+
const highwayIgnore = `/third_party/highway/src/*
|
45
|
+
!/third_party/highway/src/hwy`;
|
46
|
+
|
44
47
|
export const v8Deps = [
|
45
48
|
{
|
46
49
|
name: 'trace_event',
|
@@ -115,5 +118,14 @@ export const v8Deps = [
|
|
115
118
|
replace: fastFloatReplace
|
116
119
|
},
|
117
120
|
since: 130
|
121
|
+
},
|
122
|
+
{
|
123
|
+
name: 'highway',
|
124
|
+
repo: 'third_party/highway/src',
|
125
|
+
gitignore: {
|
126
|
+
match: '/third_party/highway/src',
|
127
|
+
replace: highwayIgnore
|
128
|
+
},
|
129
|
+
since: 134
|
118
130
|
}
|
119
131
|
];
|
@@ -226,8 +226,11 @@ Summary: ${summary}\n`,
|
|
226
226
|
vectorString: cvss_vector_string
|
227
227
|
}
|
228
228
|
],
|
229
|
+
auto_submit_on_publicly_disclosing_report: true,
|
230
|
+
references: ['https://nodejs.org/en/blog/vulnerability'],
|
231
|
+
report_id: report.id,
|
229
232
|
weakness_id: Number(weakness_id),
|
230
|
-
description:
|
233
|
+
description: report.summary,
|
231
234
|
vulnerability_discovered_at: new Date().toISOString()
|
232
235
|
}
|
233
236
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@node-core/utils",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.10.0",
|
4
4
|
"description": "Utilities for Node.js core collaborators",
|
5
5
|
"type": "module",
|
6
6
|
"engines": {
|
@@ -34,35 +34,35 @@
|
|
34
34
|
],
|
35
35
|
"license": "MIT",
|
36
36
|
"dependencies": {
|
37
|
-
"@inquirer/prompts": "^
|
38
|
-
"@listr2/prompt-adapter-enquirer": "^2.0.
|
37
|
+
"@inquirer/prompts": "^7.2.3",
|
38
|
+
"@listr2/prompt-adapter-enquirer": "^2.0.12",
|
39
39
|
"@node-core/caritat": "^1.6.0",
|
40
40
|
"@pkgjs/nv": "^0.2.2",
|
41
41
|
"branch-diff": "^3.1.1",
|
42
|
-
"chalk": "^5.
|
43
|
-
"changelog-maker": "^4.
|
42
|
+
"chalk": "^5.4.1",
|
43
|
+
"changelog-maker": "^4.3.1",
|
44
44
|
"cheerio": "^1.0.0",
|
45
45
|
"clipboardy": "^4.0.0",
|
46
46
|
"core-validate-commit": "^4.1.0",
|
47
47
|
"figures": "^6.1.0",
|
48
|
-
"ghauth": "^6.0.
|
48
|
+
"ghauth": "^6.0.10",
|
49
49
|
"git-secure-tag": "^2.3.1",
|
50
50
|
"js-yaml": "^4.1.0",
|
51
|
-
"listr2": "^8.2.
|
51
|
+
"listr2": "^8.2.5",
|
52
52
|
"lodash": "^4.17.21",
|
53
53
|
"log-symbols": "^7.0.0",
|
54
|
-
"ora": "^8.1.
|
55
|
-
"replace-in-file": "^8.
|
56
|
-
"undici": "^
|
57
|
-
"which": "^
|
54
|
+
"ora": "^8.1.1",
|
55
|
+
"replace-in-file": "^8.3.0",
|
56
|
+
"undici": "^7.2.2",
|
57
|
+
"which": "^5.0.0",
|
58
58
|
"yargs": "^17.7.2"
|
59
59
|
},
|
60
60
|
"devDependencies": {
|
61
|
-
"@reporters/github": "^1.7.
|
62
|
-
"c8": "^10.1.
|
61
|
+
"@reporters/github": "^1.7.2",
|
62
|
+
"c8": "^10.1.3",
|
63
63
|
"eslint": "^8.57.1",
|
64
64
|
"eslint-config-standard": "^17.1.0",
|
65
|
-
"eslint-plugin-import": "^2.
|
65
|
+
"eslint-plugin-import": "^2.31.0",
|
66
66
|
"eslint-plugin-n": "^16.6.2",
|
67
67
|
"eslint-plugin-promise": "^6.6.0",
|
68
68
|
"sinon": "^19.0.2"
|