Skip to content

Commit 2d6065c

Browse files
Merge branch 'main' into pkcs12
2 parents 44b14a4 + 452c8c5 commit 2d6065c

627 files changed

Lines changed: 12514 additions & 4133 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/auto-start-ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
# optimistic, it can take longer to run.
1010
# To understand why `schedule` is used instead of other events, refer to
1111
# ./doc/contributing/commit-queue.md
12-
- cron: '*/5 * * * *'
12+
- cron: 3/5 * * * *
1313

1414
concurrency: ${{ github.workflow }}
1515

‎.github/workflows/commit-queue.yml‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111
# be read-only, and the Action won't have access to any other repository
1212
# secrets, which it needs to access Jenkins API.
1313
schedule:
14-
- cron: '*/5 * * * *'
14+
- cron: 3/5 * * * *
1515

1616
concurrency: ${{ github.workflow }}
1717

@@ -28,6 +28,7 @@ jobs:
2828
if: github.repository == 'nodejs/node'
2929
runs-on: ubuntu-slim
3030
outputs:
31+
aged_prs: ${{ steps.get_candidate_prs.outputs.aged_prs }}
3132
candidates: ${{ steps.get_candidate_prs.outputs.candidates }}
3233
steps:
3334
- name: Get Pull Request Candidates
@@ -50,6 +51,7 @@ jobs:
5051
--search "-label:blocked")
5152
candidates=$(printf '%s %s\n' "$fast_track_prs" "$aged_prs" |
5253
jq -r -s 'reduce .[] as $pr ([]; if index($pr) then . else . + [$pr] end) | join(" ")')
54+
echo "aged_prs=$aged_prs" >> "$GITHUB_OUTPUT"
5355
echo "candidates=$candidates" >> "$GITHUB_OUTPUT"
5456
env:
5557
GH_TOKEN: ${{ github.token }}
@@ -93,6 +95,7 @@ jobs:
9395
curl -fsSLo "$readme" "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/README.md"
9496
9597
numbers=
98+
lacks_second_approval_prs=
9699
# shellcheck disable=SC2086
97100
for pr in $CANDIDATES; do
98101
metadata="${RUNNER_TEMP}/metadata-${pr}.json"
@@ -139,6 +142,14 @@ jobs:
139142
if [ "$metadata_status" -ge 20 ] && [ "$metadata_status" -le 29 ]; then
140143
echo "pr ${pr} skipped, not ready to land"
141144
echo "reason codes: ${metadata_reason_codes}"
145+
if jq -e '
146+
(.reasonCodes | index("wait-time")) and
147+
(.pullRequest.labels | index("lacks-second-approval") | not)
148+
' "$metadata" > /dev/null; then
149+
case " $AGED_PRS " in
150+
*" $pr "*) lacks_second_approval_prs="$lacks_second_approval_prs $pr" ;;
151+
esac
152+
fi
142153
continue
143154
fi
144155
@@ -148,11 +159,27 @@ jobs:
148159
done
149160
150161
numbers=$(echo "$numbers" | xargs)
162+
lacks_second_approval_prs=$(echo "$lacks_second_approval_prs" | xargs)
151163
echo "numbers=$numbers" >> "$GITHUB_OUTPUT"
164+
echo "lacks_second_approval_prs=$lacks_second_approval_prs" >> "$GITHUB_OUTPUT"
152165
env:
166+
AGED_PRS: ${{ needs.get_candidate_prs.outputs.aged_prs }}
153167
CANDIDATES: ${{ needs.get_candidate_prs.outputs.candidates }}
154168
GH_TOKEN: ${{ github.token }}
155169

170+
- name: Label Pull Requests Lacking a Second Approval
171+
if: steps.get_mergeable_prs.outputs.lacks_second_approval_prs != ''
172+
run: |
173+
# shellcheck disable=SC2086
174+
for pr in $PULL_REQUESTS; do
175+
if ! gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label 'lacks-second-approval'; then
176+
echo "::warning::Failed to add lacks-second-approval to PR ${pr}"
177+
fi
178+
done
179+
env:
180+
GH_TOKEN: ${{ secrets.GH_USER_TOKEN }}
181+
PULL_REQUESTS: ${{ steps.get_mergeable_prs.outputs.lacks_second_approval_prs }}
182+
156183
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
157184
if: steps.get_mergeable_prs.outputs.numbers != ''
158185
with:
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Welcome first-time contributors
2+
3+
on:
4+
pull_request_target:
5+
types: [opened]
6+
7+
permissions: {}
8+
9+
jobs:
10+
agentscan:
11+
if: >-
12+
github.run_attempt == 1 &&
13+
github.repository == 'nodejs/node' &&
14+
(github.event.pull_request.author_association == 'FIRST_TIMER' ||
15+
github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR')
16+
runs-on: ubuntu-slim
17+
permissions:
18+
contents: read
19+
outputs:
20+
scan_outcome: ${{ steps.agentscan.outcome }}
21+
classification: ${{ steps.agentscan.outputs.classification }}
22+
community_flagged: ${{ steps.agentscan.outputs['community-flagged'] }}
23+
steps:
24+
- name: Scan contributor activity
25+
id: agentscan
26+
# The welcome should still be posted if this advisory scan fails.
27+
continue-on-error: true
28+
uses: MatteoGabriele/agentscan-action@98202262c925c508d4c1424b1dfbe17ee35b0c02 # v2.4.0
29+
with:
30+
github-token: ${{ github.token }}
31+
mode: silent
32+
scan-pull-requests: true
33+
scan-issues: false
34+
auto-close: false
35+
honeypot: false
36+
37+
comment:
38+
needs: agentscan
39+
runs-on: ubuntu-slim
40+
permissions:
41+
pull-requests: write
42+
steps:
43+
- name: Welcome first-time contributor
44+
env:
45+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
NUMBER: ${{ github.event.pull_request.number }}
47+
AGENTSCAN_OUTCOME: ${{ needs.agentscan.outputs.scan_outcome }}
48+
AGENTSCAN_CLASSIFICATION: ${{ needs.agentscan.outputs.classification }}
49+
AGENTSCAN_COMMUNITY_FLAGGED: ${{ needs.agentscan.outputs.community_flagged }}
50+
WELCOME_MESSAGE: >2-
51+
Welcome to Node.js, and thank you for your first contribution!
52+
53+
Before review, please take a moment to read:
54+
55+
* the [guide for first-time contributors](https://github.com/nodejs/node/blob/HEAD/doc/contributing/first-contributions.md)
56+
* the [contribution and automation policies](https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md)
57+
* the [pull request guide](https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md)
58+
* the [AI use policy](https://github.com/nodejs/node/blob/HEAD/doc/contributing/ai-guidelines.md)
59+
* the [Code of Conduct](https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md)
60+
61+
Please make sure every commit is
62+
[signed off](https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#step-4-commit).
63+
For a first pull request, GitHub Actions require collaborator
64+
approval and Jenkins CI must be started by a collaborator or triager,
65+
so an initial wait is normal.
66+
CAUTION_MESSAGE: >-
67+
> [!CAUTION]
68+
69+
> AgentScan found account activity patterns that may be consistent with
70+
automation. This is a heuristic, not proof that this pull request was
71+
opened by an agent or violates policy. AI-assisted contributions are
72+
permitted, but automated tooling must not open pull requests without
73+
advance approval, and contributors must personally understand, test,
74+
verify, and take responsibility for every submitted change. See the
75+
[AgentScan analysis](https://agentscan.tools/user/${{ github.event.pull_request.user.login }}),
76+
[AI use policy](https://github.com/nodejs/node/blob/HEAD/doc/contributing/ai-guidelines.md),
77+
and
78+
[automation policy](https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md#automation-and-bots)
79+
for additional context.
80+
run: |
81+
add_caution=false
82+
if [[ "$AGENTSCAN_OUTCOME" == "success" ]]; then
83+
case "$AGENTSCAN_CLASSIFICATION" in
84+
mixed|automation)
85+
add_caution=true
86+
;;
87+
esac
88+
if [[ "$AGENTSCAN_COMMUNITY_FLAGGED" == "true" ]]; then
89+
add_caution=true
90+
fi
91+
fi
92+
93+
if [[ "$add_caution" == "true" ]]; then
94+
printf '%s\n\n%s\n' "$WELCOME_MESSAGE" "$CAUTION_MESSAGE"
95+
else
96+
printf '%s\n' "$WELCOME_MESSAGE"
97+
fi | gh pr comment "$NUMBER" --repo "$GITHUB_REPOSITORY" --body-file -

‎CHANGELOG.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ release.
4141
</tr>
4242
<tr>
4343
<td valign="top">
44-
<b><a href="doc/changelogs/CHANGELOG_V26.md#26.8.0">26.8.0</a></b><br/>
44+
<b><a href="doc/changelogs/CHANGELOG_V26.md#26.8.1">26.8.1</a></b><br/>
45+
<a href="doc/changelogs/CHANGELOG_V26.md#26.8.0">26.8.0</a><br/>
4546
<a href="doc/changelogs/CHANGELOG_V26.md#26.7.0">26.7.0</a><br/>
4647
<a href="doc/changelogs/CHANGELOG_V26.md#26.6.0">26.6.0</a><br/>
4748
<a href="doc/changelogs/CHANGELOG_V26.md#26.5.1">26.5.1</a><br/>

‎Makefile‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,7 +1528,8 @@ format-md: tools/lint-md/node_modules/remark-parse/package.json ## Format the ma
15281528
LINT_JS_TARGETS = eslint.config.mjs benchmark doc lib test tools
15291529

15301530
run-lint-js = tools/eslint/node_modules/eslint/bin/eslint.js --cache \
1531-
--max-warnings=0 --report-unused-disable-directives $(LINT_JS_TARGETS)
1531+
--max-warnings=0 --report-unused-disable-directives \
1532+
--concurrency auto $(LINT_JS_TARGETS)
15321533
run-lint-js-fix = $(run-lint-js) --fix
15331534

15341535
tools/eslint/node_modules/eslint/bin/eslint.js: tools/eslint/package-lock.json
@@ -1555,7 +1556,7 @@ jslint: lint-js
15551556

15561557
run-lint-js-ci = tools/eslint/node_modules/eslint/bin/eslint.js \
15571558
--max-warnings=0 --report-unused-disable-directives -f tap \
1558-
-o test-eslint.tap $(LINT_JS_TARGETS)
1559+
--concurrency auto -o test-eslint.tap $(LINT_JS_TARGETS)
15591560

15601561
.PHONY: lint-js-ci
15611562
# On the CI the output is emitted in the TAP format.

‎SECURITY.md‎

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,43 @@ This policy recognizes that experimental platforms may not compile, may not
124124
pass the test suite, and do not have the same level of testing and support
125125
infrastructure as Tier 1 and Tier 2 platforms.
126126

127-
### Experimental features behind compile-time flags and V8 flags
127+
### Experimental features behind compile-time flags, experimental runtime flags, and V8 flags
128128

129129
Node.js includes certain experimental features that are only available when
130-
Node.js is compiled with specific flags. These features are intended for
131-
development, debugging, or testing purposes and are not enabled in official
132-
releases.
130+
Node.js is compiled with specific flags or that are only enabled with experimental
131+
runtime flags. These features are intended for development, debugging, or testing
132+
purposes and are not enabled or supported in official releases.
133133

134134
Node.js may also expose V8 features that are controlled by V8 command-line flags
135135
(e.g., `--js-staging`, `--max_old_space_size`). These flags
136136
enable or modify V8-level JavaScript engine behavior that is not part of the
137137
ECMAScript specification that Node.js implements and is not part of the
138138
Node.js documented API surface.
139139

140+
#### Runtime gated experimental features
141+
142+
Experimental features behind runtime flags can fall into one of three
143+
[categories](https://github.com/nodejs/node/blob/main/doc/api/documentation.md?rgh-link-date=2026-08-21T20%3A28%3A33.000Z#stability-index):
144+
145+
* 1.0 - Early development.
146+
* 1.1 - Active development.
147+
* 1.2 - Release candidate.
148+
149+
Security vulnerabilities that only affect experimental features in either the
150+
1.0 or 1.1 stages, and that are gated with an `--experimental-*` runtime flag
151+
requiring explicit opt-in by the user to enable, will **not** be accepted as
152+
valid security issues unless the vulnerability can be exploited in a way that
153+
impacts the security of a stable feature when the associated `--experimental-*`
154+
flag is **not enabled**.
155+
156+
Security vulnerabilities that affect experimental features in the 1.2 stage are
157+
acceptable as valid security issues.
158+
159+
#### Compile-time gated experimental features and V8 flags
160+
140161
* Security vulnerabilities that only affect features behind compile-time flags
141-
or V8 flags will **not** be accepted as valid security issues.
162+
or V8 flags _that are not enabled by default_ will **not** be accepted as valid
163+
security issues.
142164
* Any issues with these features will be treated as normal bugs.
143165
* No CVEs will be issued for issues that only affect compile-time flag or V8 flag features.
144166
* Bug bounty rewards are not available for compile-time flag or V8 flag feature issues.
@@ -524,6 +546,15 @@ The following are **not** vulnerabilities in Node.js:
524546
vulnerability. Applications that rely on the Permission Model must not grant
525547
`--allow-worker` to code they do not trust.
526548

549+
#### QUIC and HTTP/3
550+
551+
The experimental QUIC and HTTP/3 implementation in Node.js is a complex new
552+
protocol stack and API that is still under active development and should not be
553+
used for production workloads. Reports that only affect QUIC or HTTP/3 are not
554+
considered Node.js vulnerabilities at this time. It is expected that the QUIC
555+
and HTTP/3 implementation will continue to evolve, and security issues will be
556+
addressed as the implementation matures.
557+
527558
#### Virtual File System (`node:vfs`)
528559

529560
The experimental [Virtual File System](https://nodejs.org/api/vfs.html)
@@ -560,12 +591,6 @@ vulnerability. Node.js validates the structure of Early Hints per the HTTP spec
560591
but does not sanitize free-form application data passed to it; that is the
561592
application's responsibility.
562593

563-
## Assessing experimental features reports
564-
565-
Experimental features are eligible for security reports just like any other
566-
stable feature of Node.js. They may also receive the same severity score that a
567-
stable feature would.
568-
569594
## Receiving security updates
570595

571596
Security notifications will be distributed via the following methods.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const assert = require('node:assert');
5+
const crypto = require('node:crypto');
6+
const fs = require('node:fs');
7+
const path = require('node:path');
8+
9+
const fixtureDir = path.resolve(__dirname, '../../test/fixtures/keys');
10+
const certificate = fs.readFileSync(path.join(fixtureDir, 'agent1-cert.pem'));
11+
const dhPrime = crypto.getDiffieHellman('modp14').getPrime();
12+
const key = Buffer.alloc(32, 0x01);
13+
const keyObject = crypto.createSecretKey(key);
14+
const hmacAlgorithm = { name: 'HMAC', hash: 'SHA-256' };
15+
const keyUsages = ['sign'];
16+
const iv = Buffer.alloc(16, 0x02);
17+
18+
const iterations = {
19+
Certificate: 1e7,
20+
Cipheriv: 1e5,
21+
Decipheriv: 1e5,
22+
DiffieHellman: 10,
23+
DiffieHellmanGroup: 2e5,
24+
ECDH: 2e5,
25+
Hash: 1e5,
26+
Hmac: 5e4,
27+
KeyObject: 1e5,
28+
Sign: 1e5,
29+
Verify: 1e5,
30+
CryptoKey: 5e4,
31+
X509Certificate: 5e3,
32+
};
33+
34+
const bench = common.createBenchmark(main, {
35+
type: Object.keys(iterations),
36+
n: [...new Set(Object.values(iterations))],
37+
}, {
38+
combinationFilter({ type, n }) {
39+
// Benchmark test mode reduces numeric options to 1.
40+
return n === 1 || iterations[type] === n;
41+
},
42+
});
43+
44+
function construct(type) {
45+
switch (type) {
46+
case 'Certificate':
47+
return new crypto.Certificate();
48+
case 'Cipheriv':
49+
return crypto.createCipheriv('aes-256-ctr', key, iv);
50+
case 'Decipheriv':
51+
return crypto.createDecipheriv('aes-256-ctr', key, iv);
52+
case 'DiffieHellman':
53+
return crypto.createDiffieHellman(dhPrime);
54+
case 'DiffieHellmanGroup':
55+
return crypto.getDiffieHellman('modp14');
56+
case 'ECDH':
57+
return crypto.createECDH('prime256v1');
58+
case 'Hash':
59+
return crypto.createHash('sha256');
60+
case 'Hmac':
61+
return crypto.createHmac('sha256', key);
62+
case 'KeyObject':
63+
return crypto.createSecretKey(key);
64+
case 'Sign':
65+
return crypto.createSign('sha256');
66+
case 'Verify':
67+
return crypto.createVerify('sha256');
68+
case 'CryptoKey':
69+
return keyObject.toCryptoKey(hmacAlgorithm, true, keyUsages);
70+
case 'X509Certificate':
71+
return new crypto.X509Certificate(certificate);
72+
default:
73+
throw new Error(`Unsupported class: ${type}`);
74+
}
75+
}
76+
77+
function main({ type, n }) {
78+
const instances = new Array(n);
79+
80+
bench.start();
81+
for (let i = 0; i < n; ++i)
82+
instances[i] = construct(type);
83+
bench.end(n);
84+
85+
assert.strictEqual(typeof instances[n - 1], 'object');
86+
}

0 commit comments

Comments
 (0)