From c6f70a52f7aa6e008676a10f67f119b823e2a077 Mon Sep 17 00:00:00 2001 From: Khafra Date: Sun, 12 May 2024 12:19:56 -0400 Subject: [PATCH 1/9] fix error message in websocket --- lib/web/websocket/websocket.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/web/websocket/websocket.js b/lib/web/websocket/websocket.js index 32ec97e68db..7b62dde43c6 100644 --- a/lib/web/websocket/websocket.js +++ b/lib/web/websocket/websocket.js @@ -26,7 +26,7 @@ const { ByteParser } = require('./receiver') const { kEnumerableProperty, isBlobLike } = require('../../core/util') const { getGlobalDispatcher } = require('../../global') const { types } = require('node:util') -const { ErrorEvent } = require('./events') +const { ErrorEvent, CloseEvent } = require('./events') let experimentalWarned = false @@ -594,9 +594,19 @@ function onParserDrain () { } function onParserError (err) { - fireEvent('error', this, () => new ErrorEvent('error', { error: err, message: err.reason })) + let message + let code + + if (err instanceof CloseEvent) { + message = err.reason + code = err.code + } else { + message = err.message + } + + fireEvent('error', this, () => new ErrorEvent('error', { error: err, message })) - closeWebSocketConnection(this, err.code) + closeWebSocketConnection(this, code) } module.exports = { From a239a51dfcd3568d1062efbddc4a885a69164e71 Mon Sep 17 00:00:00 2001 From: Khafra Date: Sun, 12 May 2024 15:45:34 -0400 Subject: [PATCH 2/9] add autobahn suite --- test/autobahn/client.js | 42 +++++++++++++++++++++++++ test/autobahn/config/fuzzingserver.json | 7 +++++ test/autobahn/run.sh | 6 ++++ 3 files changed, 55 insertions(+) create mode 100644 test/autobahn/client.js create mode 100644 test/autobahn/config/fuzzingserver.json create mode 100644 test/autobahn/run.sh diff --git a/test/autobahn/client.js b/test/autobahn/client.js new file mode 100644 index 00000000000..a75e05daeef --- /dev/null +++ b/test/autobahn/client.js @@ -0,0 +1,42 @@ +// @ts-check +const { WebSocket } = require('../..') + +let currentTest = 1 +let testCount + +function nextTest () { + let ws + + if (currentTest > testCount) { + ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws') + return + } + + console.log(`Running test case ${currentTest}/${testCount}`) + + ws = new WebSocket( + `ws://localhost:9001/runCase?case=${currentTest}&agent=ws` + ) + ws.addEventListener('message', (data) => { + ws.send(data.data) + }) + ws.addEventListener('close', () => { + currentTest++ + process.nextTick(nextTest) + }) + ws.addEventListener('error', (e) => { + console.error(e.error) + currentTest++ + process.nextTick(nextTest) + }) +} + +const ws = new WebSocket('ws://localhost:9001/getCaseCount') +ws.addEventListener('message', (data) => { + testCount = parseInt(data.data) +}) +ws.addEventListener('close', () => { + if (testCount > 0) { + nextTest() + } +}) diff --git a/test/autobahn/config/fuzzingserver.json b/test/autobahn/config/fuzzingserver.json new file mode 100644 index 00000000000..e21b420ffa5 --- /dev/null +++ b/test/autobahn/config/fuzzingserver.json @@ -0,0 +1,7 @@ +{ + "url": "ws://127.0.0.1:9001", + "outdir": "./reports/clients", + "cases": ["*"], + "exclude-cases": [], + "exclude-agent-cases": {} +} diff --git a/test/autobahn/run.sh b/test/autobahn/run.sh new file mode 100644 index 00000000000..907ff71778b --- /dev/null +++ b/test/autobahn/run.sh @@ -0,0 +1,6 @@ +docker run -it --rm \ + -v "${PWD}/config:/config" \ + -v "${PWD}/reports:/reports" \ + -p 9001:9001 \ + --name fuzzingserver \ + crossbario/autobahn-testsuite From f4c0b0f5a6dbf4fc785f54f12889e2314caa59ed Mon Sep 17 00:00:00 2001 From: Khafra Date: Sun, 12 May 2024 15:56:44 -0400 Subject: [PATCH 3/9] fix opcode tests --- lib/web/websocket/connection.js | 8 ++------ lib/web/websocket/receiver.js | 15 ++++++++++++++- lib/web/websocket/util.js | 12 +++++++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/web/websocket/connection.js b/lib/web/websocket/connection.js index 5058fc58095..85b471e6e0b 100644 --- a/lib/web/websocket/connection.js +++ b/lib/web/websocket/connection.js @@ -261,13 +261,9 @@ function closeWebSocketConnection (ws, code, reason, reasonByteLength) { /** @type {import('stream').Duplex} */ const socket = ws[kResponse].socket - socket.write(frame.createFrame(opcodes.CLOSE), (err) => { - if (!err) { - ws[kSentClose] = sentCloseFrameState.SENT - } - }) + socket.write(frame.createFrame(opcodes.CLOSE)) - ws[kSentClose] = sentCloseFrameState.PROCESSING + ws[kSentClose] = sentCloseFrameState.SENT // Upon either sending or receiving a Close control frame, it is said // that _The WebSocket Closing Handshake is Started_ and that the diff --git a/lib/web/websocket/receiver.js b/lib/web/websocket/receiver.js index 087b962a3ce..20ced08b951 100644 --- a/lib/web/websocket/receiver.js +++ b/lib/web/websocket/receiver.js @@ -5,7 +5,15 @@ const assert = require('node:assert') const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants') const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols') const { channels } = require('../../core/diagnostics') -const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived, utf8Decode, isControlFrame, isContinuationFrame } = require('./util') +const { + isValidStatusCode, + isValidOpcode, + failWebsocketConnection, + websocketMessageReceived, + utf8Decode, + isControlFrame, + isContinuationFrame +} = require('./util') const { WebsocketFrameSend } = require('./frame') const { CloseEvent } = require('./events') @@ -58,6 +66,11 @@ class ByteParser extends Writable { const opcode = buffer[0] & 0x0F const masked = (buffer[1] & 0x80) === 0x80 + if (!isValidOpcode(opcode)) { + failWebsocketConnection(this.ws, 'Invalid opcode received') + return callback() + } + if (masked) { failWebsocketConnection(this.ws, 'Frame cannot be masked') return callback() diff --git a/lib/web/websocket/util.js b/lib/web/websocket/util.js index 35d67d17eb5..ea5b29d3549 100644 --- a/lib/web/websocket/util.js +++ b/lib/web/websocket/util.js @@ -226,6 +226,14 @@ function isContinuationFrame (opcode) { return opcode === opcodes.CONTINUATION } +function isTextBinaryFrame (opcode) { + return opcode === opcodes.TEXT || opcode === opcodes.BINARY +} + +function isValidOpcode (opcode) { + return isTextBinaryFrame(opcode) || isContinuationFrame(opcode) || isControlFrame(opcode) +} + // https://nodejs.org/api/intl.html#detecting-internationalization-support const hasIntl = typeof process.versions.icu === 'string' const fatalDecoder = hasIntl ? new TextDecoder('utf-8', { fatal: true }) : undefined @@ -255,5 +263,7 @@ module.exports = { websocketMessageReceived, utf8Decode, isControlFrame, - isContinuationFrame + isContinuationFrame, + isTextBinaryFrame, + isValidOpcode } From 871705da5bc00f9aa47f67a8701fe35b34d4a014 Mon Sep 17 00:00:00 2001 From: Khafra Date: Sun, 12 May 2024 20:32:02 -0400 Subject: [PATCH 4/9] fix: rsv bits must be clear --- lib/web/websocket/receiver.js | 18 ++++++++++++++++-- test/autobahn/client.js | 2 -- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/web/websocket/receiver.js b/lib/web/websocket/receiver.js index 20ced08b951..16026952c7f 100644 --- a/lib/web/websocket/receiver.js +++ b/lib/web/websocket/receiver.js @@ -76,6 +76,20 @@ class ByteParser extends Writable { return callback() } + const rsv1 = (buffer[0] & 0x40) !== 0 + const rsv2 = (buffer[0] & 0x20) !== 0 + const rsv3 = (buffer[0] & 0x10) !== 0 + + // MUST be 0 unless an extension is negotiated that defines meanings + // for non-zero values. If a nonzero value is received and none of + // the negotiated extensions defines the meaning of such a nonzero + // value, the receiving endpoint MUST _Fail the WebSocket + // Connection_. + if (rsv1 || rsv2 || rsv3) { + failWebsocketConnection(this.ws, 'RSV1, RSV2, RSV3 must be clear') + return + } + const fragmented = !fin && opcode !== opcodes.CONTINUATION if (fragmented && opcode !== opcodes.BINARY && opcode !== opcodes.TEXT) { @@ -282,7 +296,7 @@ class ByteParser extends Writable { if (info.payloadLength > 125) { // Control frames can have a payload length of 125 bytes MAX - callback(new Error('Payload length for control frame exceeded 125 bytes.')) + failWebsocketConnection(this.ws, 'Payload length for control frame exceeded 125 bytes.') return false } else if (this.#byteOffset < info.payloadLength) { callback() @@ -388,7 +402,7 @@ class ByteParser extends Writable { parseContinuationFrame (callback, info) { // If we received a continuation frame before we started parsing another frame. if (this.#info.opcode === undefined) { - callback(new Error('Received unexpected continuation frame.')) + failWebsocketConnection(this.ws, 'Received unexpected continuation frame.') return false } else if (this.#byteOffset < info.payloadLength) { callback() diff --git a/test/autobahn/client.js b/test/autobahn/client.js index a75e05daeef..64b0c9c3c9b 100644 --- a/test/autobahn/client.js +++ b/test/autobahn/client.js @@ -26,8 +26,6 @@ function nextTest () { }) ws.addEventListener('error', (e) => { console.error(e.error) - currentTest++ - process.nextTick(nextTest) }) } From 01a09b3fd1087dcaf283a2a5265d777f2e668b39 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 13 May 2024 02:44:47 +0200 Subject: [PATCH 5/9] add autobahn workflow --- .github/workflows/autobahn.yml | 45 ++++++++++++++++++++++++++++++++++ package.json | 2 ++ test/autobahn/.gitignore | 1 + test/autobahn/client.js | 15 +++++++++--- test/autobahn/report.js | 23 +++++++++++++++++ test/autobahn/run.sh | 0 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/autobahn.yml create mode 100644 test/autobahn/.gitignore create mode 100644 test/autobahn/report.js mode change 100644 => 100755 test/autobahn/run.sh diff --git a/.github/workflows/autobahn.yml b/.github/workflows/autobahn.yml new file mode 100644 index 00000000000..a70c9b9dc81 --- /dev/null +++ b/.github/workflows/autobahn.yml @@ -0,0 +1,45 @@ +name: Autobahn +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + autobahn: + name: Autobahn Test Suite + runs-on: ubuntu-latest + container: node:22 + services: + fuzzingserver: + image: crossbario/autobahn-testsuite:latest + ports: + - '9001:9001' + options: --name fuzzingserver + volumes: + - ${{ github.workspace }}/test/autobahn/config:/config + - ${{ github.workspace }}/test/autobahn/reports:/reports + steps: + - name: Checkout Code + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + persist-credentials: false + clean: false + + - name: Restart Autobahn Server + # Restart service after volumes have been checked out + uses: docker://docker + with: + args: docker restart --time 0 --signal=SIGKILL fuzzingserver + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: lts/* + + - name: Run Autobahn Test Suite + run: npm run test:websocket:autobahn + env: + FUZZING_SERVER_URL: ws://fuzzingserver:9001 + - name: Report + run: npm run test:websocket:autobahn:report diff --git a/package.json b/package.json index bf594948491..95cf7b38b94 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,8 @@ "test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts", "test:webidl": "borp -p \"test/webidl/*.js\"", "test:websocket": "borp -p \"test/websocket/*.js\"", + "test:websocket:autobahn": "node test/autobahn/client.js", + "test:websocket:autobahn:report": "node test/autobahn/report.js", "test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs", "test:wpt:withoutintl": "node test/wpt/start-fetch.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs", "coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report", diff --git a/test/autobahn/.gitignore b/test/autobahn/.gitignore new file mode 100644 index 00000000000..f073a2d3495 --- /dev/null +++ b/test/autobahn/.gitignore @@ -0,0 +1 @@ +reports/clients diff --git a/test/autobahn/client.js b/test/autobahn/client.js index 64b0c9c3c9b..41bf1d61063 100644 --- a/test/autobahn/client.js +++ b/test/autobahn/client.js @@ -1,21 +1,24 @@ -// @ts-check +'use strict' + const { WebSocket } = require('../..') let currentTest = 1 let testCount +const autobahnFuzzingserverUrl = process.env.FUZZING_SERVER_URL || 'ws://localhost:9001' + function nextTest () { let ws if (currentTest > testCount) { - ws = new WebSocket('ws://localhost:9001/updateReports?agent=ws') + ws = new WebSocket(`${autobahnFuzzingserverUrl}/updateReports?agent=undici`) return } console.log(`Running test case ${currentTest}/${testCount}`) ws = new WebSocket( - `ws://localhost:9001/runCase?case=${currentTest}&agent=ws` + `${autobahnFuzzingserverUrl}/runCase?case=${currentTest}&agent=undici` ) ws.addEventListener('message', (data) => { ws.send(data.data) @@ -29,7 +32,7 @@ function nextTest () { }) } -const ws = new WebSocket('ws://localhost:9001/getCaseCount') +const ws = new WebSocket(`${autobahnFuzzingserverUrl}/getCaseCount`) ws.addEventListener('message', (data) => { testCount = parseInt(data.data) }) @@ -38,3 +41,7 @@ ws.addEventListener('close', () => { nextTest() } }) +ws.addEventListener('error', (e) => { + console.error(e.error) + process.exit(1) +}) diff --git a/test/autobahn/report.js b/test/autobahn/report.js new file mode 100644 index 00000000000..3c4f53fb167 --- /dev/null +++ b/test/autobahn/report.js @@ -0,0 +1,23 @@ +'use strict' + +const result = require('./reports/clients/index.json').undici + +function testCaseIdToWeight (testCaseId) { + const [major, minor, sub] = testCaseId.split('.') + return sub + ? parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 + parseInt(sub, 10) + : parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 +} + +const keys = Object.keys(result).sort((a, b) => { + a = testCaseIdToWeight(a) + b = testCaseIdToWeight(b) + return a - b +}) + +const reorderedResult = {} +for (const key of keys) { + reorderedResult[key] = result[key] +} + +console.table(reorderedResult) diff --git a/test/autobahn/run.sh b/test/autobahn/run.sh old mode 100644 new mode 100755 From 0284933d58590780c34a432ee781063c6c8e2be4 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 13 May 2024 03:11:07 +0200 Subject: [PATCH 6/9] run autobahn on pull_request event --- .github/workflows/autobahn.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/autobahn.yml b/.github/workflows/autobahn.yml index a70c9b9dc81..e3c05dc5ea1 100644 --- a/.github/workflows/autobahn.yml +++ b/.github/workflows/autobahn.yml @@ -2,6 +2,12 @@ name: Autobahn on: workflow_dispatch: + pull_request: + paths: + - '.github/workflows/autobahn.yml' + - 'lib/web/websocket/**' + - 'test/autobahn/**' + permissions: contents: read From a083605b6b5dc9323dac491cdcf067408d6541fa Mon Sep 17 00:00:00 2001 From: Khafra Date: Sun, 12 May 2024 21:46:55 -0400 Subject: [PATCH 7/9] fix case 5.18 --- lib/web/websocket/receiver.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/web/websocket/receiver.js b/lib/web/websocket/receiver.js index 16026952c7f..66f7a3e8f64 100644 --- a/lib/web/websocket/receiver.js +++ b/lib/web/websocket/receiver.js @@ -12,7 +12,8 @@ const { websocketMessageReceived, utf8Decode, isControlFrame, - isContinuationFrame + isContinuationFrame, + isTextBinaryFrame } = require('./util') const { WebsocketFrameSend } = require('./frame') const { CloseEvent } = require('./events') @@ -92,12 +93,19 @@ class ByteParser extends Writable { const fragmented = !fin && opcode !== opcodes.CONTINUATION - if (fragmented && opcode !== opcodes.BINARY && opcode !== opcodes.TEXT) { + if (fragmented && !isTextBinaryFrame(opcode)) { // Only text and binary frames can be fragmented failWebsocketConnection(this.ws, 'Invalid frame type was fragmented.') return } + // If we are already parsing a text/binary frame and do not receive either + // a continuation frame or close frame, fail the connection. + if (isTextBinaryFrame(opcode) && this.#info.opcode !== undefined) { + failWebsocketConnection(this.ws, 'Expected continuation frame') + return + } + const payloadLength = buffer[1] & 0x7F if (isControlFrame(opcode)) { From af26c19f064b764f1dcdad7ff378baa09f05c13c Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 13 May 2024 05:24:37 +0200 Subject: [PATCH 8/9] add commenting of status into PR --- .github/workflows/autobahn.yml | 21 +++++- test/autobahn/report.js | 121 ++++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 2 deletions(-) diff --git a/.github/workflows/autobahn.yml b/.github/workflows/autobahn.yml index e3c05dc5ea1..9117497c574 100644 --- a/.github/workflows/autobahn.yml +++ b/.github/workflows/autobahn.yml @@ -47,5 +47,24 @@ jobs: run: npm run test:websocket:autobahn env: FUZZING_SERVER_URL: ws://fuzzingserver:9001 - - name: Report + + - name: Report into CI + id: report-ci run: npm run test:websocket:autobahn:report + + - name: Generate Report for PR Comment + if: github.event_name == 'pull_request' + id: report-markdown + run: | + echo "comment<> $GITHUB_OUTPUT + node test/autobahn/report.js >> $GITHUB_OUTPUT + echo "nEOFn" >> $GITHUB_OUTPUT + env: + REPORTER: markdown + + - name: Comment PR + if: github.event_name == 'pull_request' + uses: thollander/actions-comment-pull-request@v2 + with: + message: ${{ steps.report-markdown.outputs.comment }} + comment_tag: autobahn diff --git a/test/autobahn/report.js b/test/autobahn/report.js index 3c4f53fb167..105eb4f1496 100644 --- a/test/autobahn/report.js +++ b/test/autobahn/report.js @@ -2,6 +2,21 @@ const result = require('./reports/clients/index.json').undici +const failOnError = process.env.FAIL_ON_ERROR === 'true' +const reporter = process.env.REPORTER || 'table' +let runFailed = false + +let okTests = 0 +let failedTests = 0 +let nonStrictTests = 0 +let wrongCodeTests = 0 +let uncleanTests = 0 +let failedByClientTests = 0 +let informationalTests = 0 +let unimplementedTests = 0 + +let totalTests = 0 + function testCaseIdToWeight (testCaseId) { const [major, minor, sub] = testCaseId.split('.') return sub @@ -9,6 +24,19 @@ function testCaseIdToWeight (testCaseId) { : parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 } +function isFailedTestCase (testCase) { + return ( + testCase.behavior === 'FAILED' || + testCase.behavior === 'WRONG CODE' || + testCase.behavior === 'UNCLEAN' || + testCase.behavior === 'FAILED BY CLIENT' || + testCase.behaviorClose === 'FAILED' || + testCase.behaviorClose === 'WRONG CODE' || + testCase.behaviorClose === 'UNCLEAN' || + testCase.behaviorClose === 'FAILED BY CLIENT' + ) +} + const keys = Object.keys(result).sort((a, b) => { a = testCaseIdToWeight(a) b = testCaseIdToWeight(b) @@ -18,6 +46,97 @@ const keys = Object.keys(result).sort((a, b) => { const reorderedResult = {} for (const key of keys) { reorderedResult[key] = result[key] + delete reorderedResult[key].reportfile + + totalTests++ + + if ( + failOnError && + !runFailed && + isFailedTestCase(result[key]) + ) { + runFailed = true + } + + switch (result[key].behavior) { + case 'OK': + okTests++ + break + case 'FAILED': + failedTests++ + break + case 'NON-STRICT': + nonStrictTests++ + break + case 'WRONG CODE': + wrongCodeTests++ + break + case 'UNCLEAN': + uncleanTests++ + break + case 'FAILED BY CLIENT': + failedByClientTests++ + break + case 'INFORMATIONAL': + informationalTests++ + break + case 'UNIMPLEMENTED': + unimplementedTests++ + break + } +} + +if ( + reporter === 'table' +) { + console.log('Autobahn Test Report\n\nSummary:') + + console.table({ + OK: okTests, + Failed: failedTests, + 'Non-Strict': nonStrictTests, + 'Wrong Code': wrongCodeTests, + Unclean: uncleanTests, + 'Failed By Client': failedByClientTests, + Informational: informationalTests, + Unimplemented: unimplementedTests, + 'Total Tests': totalTests + }) + + console.log('Details:') + + console.table(reorderedResult) +} + +if (reporter === 'markdown') { + console.log(`## Autobahn Test Report + +### Summary + +| Type | Count | +|---|---| +| OK | ${okTests} | +| Failed | ${failedTests} | +| Non-Strict | ${nonStrictTests} | +| Wrong Code | ${wrongCodeTests} | +| Unclean | ${uncleanTests} | +| Failed By Client | ${failedByClientTests} | +| Informational | ${informationalTests} | +| Unimplemented | ${unimplementedTests} | +| Total Tests | ${totalTests} | + +
+Details + +| Test Case | Behavior | Close Behavior | Duration | Remote Close Code | +|---|---|---|---|---| +${keys.map(key => { + const testCase = reorderedResult[key] + return `| ${key} | ${testCase.behavior} | ${testCase.behaviorClose} | ${testCase.duration} | ${testCase.remoteCloseCode} |` +}).join('\n')} + +
+`) } -console.table(reorderedResult) +process.exit(runFailed ? 1 : 0) From 0c224ed4f63c9c3bfb87edc6c049828b1a34f987 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 13 May 2024 05:40:01 +0200 Subject: [PATCH 9/9] add permission --- .github/workflows/autobahn.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/autobahn.yml b/.github/workflows/autobahn.yml index 9117497c574..27e0c67f25f 100644 --- a/.github/workflows/autobahn.yml +++ b/.github/workflows/autobahn.yml @@ -10,6 +10,7 @@ on: permissions: contents: read + pull-requests: write jobs: autobahn: @@ -37,11 +38,11 @@ jobs: uses: docker://docker with: args: docker restart --time 0 --signal=SIGKILL fuzzingserver - + - name: Setup Node uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: - node-version: lts/* + node-version: 22 - name: Run Autobahn Test Suite run: npm run test:websocket:autobahn