From bcbdff0b2e6d070e20a9cd633ff3812ed42e9d1c Mon Sep 17 00:00:00 2001 From: Holger Benl Date: Wed, 5 Aug 2026 09:04:01 +0200 Subject: [PATCH 1/3] test(bidi): unskip new websocket header tests (#42130) --- tests/library/browsercontext-locale.spec.ts | 4 ++-- tests/library/web-socket.spec.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/library/browsercontext-locale.spec.ts b/tests/library/browsercontext-locale.spec.ts index c6b5b391826af..b9780fe43eead 100644 --- a/tests/library/browsercontext-locale.spec.ts +++ b/tests/library/browsercontext-locale.spec.ts @@ -241,8 +241,8 @@ it('should send Accept-Language header on WebSocket handshake', { it('should send Accept-Language header on WebSocket handshake from a worker', { annotation: [{ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/13919' }], -}, async ({ browser, server, browserName, browserMajorVersion }) => { - it.fixme(browserName === 'firefox', 'Firefox does not associate a WebSocket opened inside a worker with its browsing context'); +}, async ({ browser, server, browserName, browserMajorVersion, isBidi }) => { + it.fixme(browserName === 'firefox' && !isBidi, 'Firefox/Juggler does not associate a WebSocket opened inside a worker with its browsing context'); it.fixme(browserName === 'chromium' && browserMajorVersion < 151, 'Chromium before 151 sends the browser Accept-Language instead of the emulated locale on WebSocket handshake'); const context = await browser.newContext({ locale: 'en-GB' }); diff --git a/tests/library/web-socket.spec.ts b/tests/library/web-socket.spec.ts index 79fd8f9608c08..ddc6bca903fff 100644 --- a/tests/library/web-socket.spec.ts +++ b/tests/library/web-socket.spec.ts @@ -259,9 +259,9 @@ it('should send extra HTTP headers on WebSocket handshake', { it('should send extra HTTP headers on WebSocket handshake from a worker', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28948' }, -}, async ({ page, server, browserName, browserMajorVersion }) => { +}, async ({ page, server, browserName, browserMajorVersion, isBidi }) => { it.fixme(browserName === 'chromium' && browserMajorVersion < 151, 'Chromium before 151 does not send extra HTTP headers on WebSocket handshake'); - it.fixme(browserName === 'firefox', 'Firefox does not associate a WebSocket opened inside a worker with its browsing context'); + it.fixme(browserName === 'firefox' && !isBidi, 'Firefox/Juggler does not associate a WebSocket opened inside a worker with its browsing context'); await page.setExtraHTTPHeaders({ foo: 'bar' }); await page.goto(server.EMPTY_PAGE); From 93ba7b68e646cd97ced406a682d249a5dcaeaa7a Mon Sep 17 00:00:00 2001 From: Microsoft Open Source Security Bot Date: Wed, 5 Aug 2026 02:43:53 -0700 Subject: [PATCH 2/3] Pin GitHub Actions to full-length commit SHAs (#42107) --- .github/actions/download-artifact/action.yml | 2 +- .github/actions/run-test/action.yml | 4 ++-- .github/actions/upload-blob-report/action.yml | 2 +- .../actions/upload-parquet-report/action.yml | 2 +- .github/dependabot.yml | 11 ++++++++++ .github/workflows/copilot-setup-steps.yml | 4 ++-- .github/workflows/create_test_report.yml | 10 ++++----- .github/workflows/fix-flakes.yml | 18 +++++++-------- .github/workflows/infra.yml | 14 ++++++------ .github/workflows/pr-ci-triage.yml | 12 +++++----- .github/workflows/publish_extension.yml | 4 ++-- .github/workflows/publish_release.yml | 10 ++++----- .github/workflows/roll_nodejs.yml | 8 +++---- .github/workflows/roll_stable_test_runner.yml | 8 +++---- .github/workflows/tests_bidi.yml | 12 +++++----- .github/workflows/tests_components.yml | 4 ++-- .github/workflows/tests_docker.yml | 8 +++---- .github/workflows/tests_extension.yml | 4 ++-- .github/workflows/tests_mcp.yml | 2 +- .github/workflows/tests_primary.yml | 14 ++++++------ .github/workflows/tests_secondary.yml | 22 +++++++++---------- .github/workflows/tests_webview_simulator.yml | 8 +++---- .github/workflows/triage.yml | 8 +++---- .github/workflows/update_test_results_db.yml | 6 ++--- 24 files changed, 104 insertions(+), 93 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/actions/download-artifact/action.yml b/.github/actions/download-artifact/action.yml index 641f72083d4bb..d8a5b92b6c5e2 100644 --- a/.github/actions/download-artifact/action.yml +++ b/.github/actions/download-artifact/action.yml @@ -16,7 +16,7 @@ runs: shell: bash run: mkdir -p '${{ inputs.path }}/artifacts' - name: Download artifacts - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | console.log(`downloading artifacts for workflow_run: ${context.payload.workflow_run.id}`); diff --git a/.github/actions/run-test/action.yml b/.github/actions/run-test/action.yml index bc985f15efff0..4edcfee8a880c 100644 --- a/.github/actions/run-test/action.yml +++ b/.github/actions/run-test/action.yml @@ -39,7 +39,7 @@ inputs: runs: using: composite steps: - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: ${{ inputs.node-version }} - run: | @@ -81,7 +81,7 @@ runs: env: PW_TAG: "@${{ inputs.bot-name }}" - name: Azure Login - uses: azure/login@v2 + uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0 if: ${{ !cancelled() && env.PLAYWRIGHT_SETUP_COMPLETE == 'true' && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} with: client-id: ${{ inputs.flakiness-client-id }} diff --git a/.github/actions/upload-blob-report/action.yml b/.github/actions/upload-blob-report/action.yml index 658145fcf0e9d..e623366d2e136 100644 --- a/.github/actions/upload-blob-report/action.yml +++ b/.github/actions/upload-blob-report/action.yml @@ -20,7 +20,7 @@ runs: echo "::endgroup::" - name: Upload blob report to GitHub if: ${{ !cancelled() }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: blob-report-${{ inputs.job_name }} path: ${{ inputs.report_dir }}/** diff --git a/.github/actions/upload-parquet-report/action.yml b/.github/actions/upload-parquet-report/action.yml index af8ae5567a995..2c7911a5b719b 100644 --- a/.github/actions/upload-parquet-report/action.yml +++ b/.github/actions/upload-parquet-report/action.yml @@ -13,7 +13,7 @@ runs: steps: - name: Upload parquet report to GitHub if: ${{ hashFiles(inputs.report_file) != '' }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: parquet-report-${{ inputs.job_name }} path: ${{ inputs.report_file }} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..2c48305b7ebfa --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + groups: + github-actions: + patterns: ["*"] + schedule: + interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index e0bc98790d21e..37076d9b2f919 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -8,8 +8,8 @@ jobs: contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: npm ci diff --git a/.github/workflows/create_test_report.yml b/.github/workflows/create_test_report.yml index f6aed35520254..59dde654cd1c8 100644 --- a/.github/workflows/create_test_report.yml +++ b/.github/workflows/create_test_report.yml @@ -23,8 +23,8 @@ jobs: env: MARKDOWN_OUTPUT_FILE: ${{ github.workspace }}/report.md steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: npm ci @@ -54,7 +54,7 @@ jobs: - name: Upload HTML report id: upload-report - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: path: playwright-report/index.html archive: false # Upload as a single, browser-openable file (no zip) @@ -83,7 +83,7 @@ jobs: - name: Post report comment to PR if: ${{ steps.pr.outputs.number }} - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: HTML_REPORT_URL: ${{ steps.upload-report.outputs.artifact-url }} PR_NUMBER: ${{ steps.pr.outputs.number }} @@ -101,7 +101,7 @@ jobs: }); - name: Publish Report URL as Commit Status - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | await github.rest.repos.createCommitStatus({ diff --git a/.github/workflows/fix-flakes.yml b/.github/workflows/fix-flakes.yml index c2fcb65e2d8fc..fe48371e050c8 100644 --- a/.github/workflows/fix-flakes.yml +++ b/.github/workflows/fix-flakes.yml @@ -26,10 +26,10 @@ jobs: cancel-in-progress: false steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* @@ -132,13 +132,13 @@ jobs: copilot-requests: write steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: ref: ${{ github.sha }} fetch-depth: 0 - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* @@ -226,7 +226,7 @@ jobs: - name: Upload handoff (fix patch) if: steps.export.outputs.has_fix == 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: fix-flakes-handoff-${{ needs.triage.outputs.runner }} path: handoff/ @@ -244,7 +244,7 @@ jobs: - name: Upload session transcript if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: fix-flakes-session-${{ needs.triage.outputs.runner }} path: output/copilot-session.md @@ -259,18 +259,18 @@ jobs: pull-requests: write steps: - name: Checkout base commit - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: ref: ${{ github.sha }} fetch-depth: 0 - name: Download handoff - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: fix-flakes-handoff-${{ needs.triage.outputs.runner }} path: handoff - - uses: actions/create-github-app-token@v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 id: app-token with: client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml index fe5ef6cfbf7d6..2abf95a61d5a9 100644 --- a/.github/workflows/infra.yml +++ b/.github/workflows/infra.yml @@ -15,8 +15,8 @@ jobs: name: "docs & lint" runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: npm ci @@ -37,17 +37,17 @@ jobs: name: "Lint snippets" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - - uses: actions/setup-python@v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.11' - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: 8.0.x - - uses: actions/setup-java@v5 + - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: 'zulu' java-version: '21' diff --git a/.github/workflows/pr-ci-triage.yml b/.github/workflows/pr-ci-triage.yml index 07c9c7b32a180..452ccb6861de8 100644 --- a/.github/workflows/pr-ci-triage.yml +++ b/.github/workflows/pr-ci-triage.yml @@ -29,13 +29,13 @@ jobs: GH_TOKEN: ${{ github.token }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: microsoft/playwright ref: main - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: '24' @@ -84,7 +84,7 @@ jobs: - name: Upload triage draft if: ${{ always() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ci-triage-${{ inputs.pr_number }} path: output/triage.md @@ -104,19 +104,19 @@ jobs: REPORT_NAME: ${{ github.event.workflow_run.name || github.workflow }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: microsoft/playwright ref: main - name: Download triage draft - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: ci-triage-${{ inputs.pr_number }} path: output - name: Post triage comment - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/publish_extension.yml b/.github/workflows/publish_extension.yml index a681e52c9dee3..23a2bb5d353e6 100644 --- a/.github/workflows/publish_extension.yml +++ b/.github/workflows/publish_extension.yml @@ -7,8 +7,8 @@ jobs: runs-on: ubuntu-latest environment: allow-publishing-extension-to-cws steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* cache: 'npm' diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 18c678511d196..28d8eb42e89fb 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -19,8 +19,8 @@ jobs: id-token: write # This is required for OIDC login (NPM publish) to succeed contents: read # This is required for actions/checkout to succeed steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* registry-url: 'https://registry.npmjs.org' @@ -51,11 +51,11 @@ jobs: runs-on: ubuntu-24.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - - uses: actions/create-github-app-token@v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 id: app-token with: client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} diff --git a/.github/workflows/roll_nodejs.yml b/.github/workflows/roll_nodejs.yml index 1287bbe7c9c0a..f666398a80bb3 100644 --- a/.github/workflows/roll_nodejs.yml +++ b/.github/workflows/roll_nodejs.yml @@ -12,8 +12,8 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: node utils/build/update-playwright-node.mjs @@ -33,14 +33,14 @@ jobs: git add . git commit -m "chore: roll driver/Dockerfile to recent Node.js LTS version" git push origin $BRANCH_NAME - - uses: actions/create-github-app-token@v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 id: app-token with: client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - name: Create Pull Request if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.app-token.outputs.token }} script: | diff --git a/.github/workflows/roll_stable_test_runner.yml b/.github/workflows/roll_stable_test_runner.yml index 0e262839a61a0..7daab8be18d03 100644 --- a/.github/workflows/roll_stable_test_runner.yml +++ b/.github/workflows/roll_stable_test_runner.yml @@ -12,8 +12,8 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: | @@ -38,14 +38,14 @@ jobs: git add . git commit -m "test: roll stable-test-runner to ${{ steps.bump.outputs.VERSION }}" git push origin $BRANCH_NAME - - uses: actions/create-github-app-token@v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 id: app-token with: client-id: ${{ vars.PLAYWRIGHT_APP_CLIENT_ID }} private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - name: Create Pull Request if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.app-token.outputs.token }} script: | diff --git a/.github/workflows/tests_bidi.yml b/.github/workflows/tests_bidi.yml index b11400d438fb4..340a363aec712 100644 --- a/.github/workflows/tests_bidi.yml +++ b/.github/workflows/tests_bidi.yml @@ -39,13 +39,13 @@ jobs: - isPullRequest: true channel: bidi-chromium steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 if: github.event_name != 'workflow_dispatch' - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 if: github.event_name == 'workflow_dispatch' with: ref: ${{ github.event.inputs.ref }} - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 20 - run: npm ci @@ -64,7 +64,7 @@ jobs: PWTEST_USE_BIDI_EXPECTATIONS: ${{ matrix.isPullRequest && '1' || '' }} - name: Upload csv report to GitHub if: ${{ !cancelled() }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: csv-report-${{ matrix.channel }} path: test-results/report.csv @@ -72,7 +72,7 @@ jobs: - name: Upload json report to GitHub if: ${{ !cancelled() }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: json-report-${{ matrix.channel }} path: test-results/report.json @@ -86,7 +86,7 @@ jobs: - name: Azure Login if: ${{ !cancelled() && github.ref == 'refs/heads/main' }} - uses: azure/login@v3 + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 with: client-id: ${{ secrets.AZURE_BLOB_REPORTS_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_BLOB_REPORTS_TENANT_ID }} diff --git a/.github/workflows/tests_components.yml b/.github/workflows/tests_components.yml index e525ea0de3bec..aa17779559dcc 100644 --- a/.github/workflows/tests_components.yml +++ b/.github/workflows/tests_components.yml @@ -37,8 +37,8 @@ jobs: node-version: 24 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.github/workflows/tests_docker.yml b/.github/workflows/tests_docker.yml index 2fd7dc34cb7a8..f5745e4417f0c 100644 --- a/.github/workflows/tests_docker.yml +++ b/.github/workflows/tests_docker.yml @@ -39,8 +39,8 @@ jobs: steps: - name: Create ~/.azure directory run: mkdir -p ~/.azure - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 22 env: @@ -51,7 +51,7 @@ jobs: # main repo, where the secrets are present; forks fall back to Docker Hub. - name: Azure Login if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - uses: azure/login@v3 + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 with: client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} @@ -114,7 +114,7 @@ jobs: - name: Azure Login if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} - uses: azure/login@v3 + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 with: client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} diff --git a/.github/workflows/tests_extension.yml b/.github/workflows/tests_extension.yml index 38a413f319c95..beaa51b6c08ca 100644 --- a/.github/workflows/tests_extension.yml +++ b/.github/workflows/tests_extension.yml @@ -41,8 +41,8 @@ jobs: os: [macos-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 22 - run: npm ci diff --git a/.github/workflows/tests_mcp.yml b/.github/workflows/tests_mcp.yml index 8a5d04390435b..e33f04c0eb6bf 100644 --- a/.github/workflows/tests_mcp.yml +++ b/.github/workflows/tests_mcp.yml @@ -54,7 +54,7 @@ jobs: id-token: write # This is required for OIDC login (azure/login) to succeed contents: read # This is required for actions/checkout to succeed steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: "22" diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index a4da6a0e7f061..1496970453d49 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -54,7 +54,7 @@ jobs: id-token: write # This is required for OIDC login (azure/login) to succeed contents: read # This is required for actions/checkout to succeed steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: ${{ matrix.node-version }} @@ -127,7 +127,7 @@ jobs: id-token: write # This is required for OIDC login (azure/login) to succeed contents: read # This is required for actions/checkout to succeed steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: ${{matrix.node-version}} @@ -152,7 +152,7 @@ jobs: package: [html-reporter, web] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: 20 @@ -167,8 +167,8 @@ jobs: name: VSCode Extension runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 20 - run: npm ci @@ -215,7 +215,7 @@ jobs: id-token: write # This is required for OIDC login (azure/login) to succeed contents: read # This is required for actions/checkout to succeed steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - run: npm install -g yarn@1 - run: npm install -g pnpm@8 - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed @@ -247,7 +247,7 @@ jobs: clock: [frozen, realtime] runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: 22 diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml index 7e04617c61066..d90a1f7e8f0cf 100644 --- a/.github/workflows/tests_secondary.yml +++ b/.github/workflows/tests_secondary.yml @@ -36,7 +36,7 @@ jobs: browser: chromium runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: browsers-to-install: ${{ matrix.browser }} chromium @@ -56,7 +56,7 @@ jobs: browser: [chromium, firefox, webkit] runs-on: windows-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: browsers-to-install: ${{ matrix.browser }} chromium @@ -83,7 +83,7 @@ jobs: node_version: 26 timeout-minutes: 30 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - run: npm install -g yarn@1 - run: npm install -g pnpm@8 - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed @@ -109,7 +109,7 @@ jobs: fail-fast: false runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: browsers-to-install: chromium @@ -137,7 +137,7 @@ jobs: runs-on: ubuntu-24.04 runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: browsers-to-install: ${{ matrix.browser }} chromium @@ -170,7 +170,7 @@ jobs: - channel: msedge-dev runs-on: windows-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: browsers-to-install: ${{ matrix.channel }} @@ -187,8 +187,8 @@ jobs: environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} runs-on: playwright-x64-ubuntu24-64-core steps: - - uses: actions/checkout@v6 - - uses: actions/setup-java@v5 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: 'temurin' java-version: '21' @@ -197,7 +197,7 @@ jobs: echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 22 - name: Create Android Emulator @@ -225,7 +225,7 @@ jobs: matrix: clock: [frozen, realtime] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: ./.github/actions/run-test with: node-version: 22 @@ -249,7 +249,7 @@ jobs: contents: read # This is required for actions/checkout to succeed runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed if: ${{ runner.os == 'Linux' }} run: | diff --git a/.github/workflows/tests_webview_simulator.yml b/.github/workflows/tests_webview_simulator.yml index 0a8c1cea2ba9e..9701dd37daa6b 100644 --- a/.github/workflows/tests_webview_simulator.yml +++ b/.github/workflows/tests_webview_simulator.yml @@ -25,8 +25,8 @@ jobs: matrix: shard: [1, 2, 3, 4] steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 20 @@ -81,7 +81,7 @@ jobs: echo "::endgroup::" - name: Boot iOS Simulator - uses: futureware-tech/simulator-action@v5 + uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # v5 with: # Per wiki/Devices-macos-15.md only iPhone 16/17 series ship pre-installed; iPhone 15 isn't. model: 'iPhone 16' @@ -152,7 +152,7 @@ jobs: - name: Upload artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: webview-simulator-logs-${{ matrix.shard }} path: | diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 7e3a766fef6c4..7ed4715708c21 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -27,10 +27,10 @@ jobs: ISSUE: ${{ github.event.issue.number || inputs.issue }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* @@ -79,7 +79,7 @@ jobs: - name: Upload output if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: triage-${{ github.event.issue.number || inputs.issue }} path: output/triage.md @@ -97,7 +97,7 @@ jobs: WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} steps: - name: Download triage output - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: triage-${{ github.event.issue.number || inputs.issue }} path: output diff --git a/.github/workflows/update_test_results_db.yml b/.github/workflows/update_test_results_db.yml index 067516b2f5bc4..2a01229a861a4 100644 --- a/.github/workflows/update_test_results_db.yml +++ b/.github/workflows/update_test_results_db.yml @@ -18,8 +18,8 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: lts/* - run: npm ci @@ -38,7 +38,7 @@ jobs: run: node utils/test-results-db/cli.ts truncate --max-runs 2000 - name: Upload database if: steps.ingest.outputs.imported != '0' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-results-db path: utils/test-results-db/test-results.duckdb From d5b12171ef7fe77a5b4c849e0796571629af195b Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 5 Aug 2026 12:54:19 +0200 Subject: [PATCH 3/3] fix(fetch): do not crash on late EPIPE after refused body (#42116) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e --- packages/playwright-core/src/server/fetch.ts | 20 +++++++++++- tests/library/global-fetch.spec.ts | 32 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index b3f2f520a9c00..d49f1619e6a68 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -356,10 +356,20 @@ export abstract class APIRequestContext extends SdkObject { let serverPort: number | undefined; let securityDetails: har.SecurityDetails | undefined; + let responseReceived = false; const listeners: RegisteredListener[] = []; + const handleRequestError = (error: Error) => { + // Write errors after we received a response are swallowed, following undici behaviour: + // https://github.com/nodejs/undici/blob/01a912e49a50c48009ed2639d2a457a6ec26752a/lib/dispatcher/client-h1.js#L735 + if (responseReceived && isNetworkConnectionError(error)) + return; + reject(error); + }; + const request = requestConstructor(url, requestOptions as any, async response => { + responseReceived = true; const responseAt = monotonicTime(); const notifyRequestFinished = (body?: Buffer) => { @@ -559,7 +569,7 @@ export abstract class APIRequestContext extends SdkObject { body.on('data', chunk => chunks.push(chunk)); body.on('end', notifyBodyFinished); }); - request.on('error', reject); + request.on('error', handleRequestError); destroyRequest = () => request.destroy(); listeners.push( @@ -589,6 +599,14 @@ export abstract class APIRequestContext extends SdkObject { serverIPAddress = socket.remoteAddress; serverPort = socket.remotePort; + socket.on('error', handleRequestError); + // Drop on keep-alive reuse so listeners do not accumulate. Keep if destroyed: + // a late write EPIPE may still fire after a refused-body reset. + request.once('close', () => { + if (!socket.destroyed) + socket.off('error', handleRequestError); + }); + if (request.reusedSocket) { reusedSocketAt = monotonicTime(); captureSecurityDetails(socket); diff --git a/tests/library/global-fetch.spec.ts b/tests/library/global-fetch.spec.ts index 8a92169fab4f0..5a00c0b0c8c3d 100644 --- a/tests/library/global-fetch.spec.ts +++ b/tests/library/global-fetch.spec.ts @@ -707,6 +707,38 @@ it('should retry ECONNRESET', { await request.dispose(); }); +it('should not crash when server refuses body before reading it', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/42074' } +}, async ({ playwright, server }) => { + // Respond without reading the body, then reset. Node emits a late write + // EPIPE/ECONNRESET on the request socket; without a listener that becomes an + // unhandled 'error' and kills the process. + server.setRoute('/refuse', (req, res) => { + req.pause(); + setTimeout(() => { + res.writeHead(413, { 'content-type': 'application/json' }); + res.end(JSON.stringify({ error: 'too large' })); + req.socket.destroy(); + }, 50); + }); + + const request = await playwright.request.newContext(); + // Large body so the client is still writing when the reset lands. + // Prefer CROSS_PROCESS_PREFIX (127.0.0.1) over PREFIX (localhost/::1) for a stable race. + const result = await request.post(server.CROSS_PROCESS_PREFIX + '/refuse', { + data: Buffer.alloc(20 * 1024 * 1024, 0x78), + headers: { 'content-type': 'text/plain' }, + maxRetries: 0, + }).catch(e => e); + if (result instanceof Error) { + expect(result.message).toMatch(/apiRequestContext\.post|ECONNRESET|EPIPE|ECONNABORTED|socket/i); + } else { + expect(result.status()).toBe(413); + expect(await result.text()).toBe(JSON.stringify({ error: 'too large' })); + } + await request.dispose(); +}); + it('should throw when failOnStatusCode is set to true inside APIRequest context options', async ({ playwright, server }) => { it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34204' }); const request = await playwright.request.newContext({ failOnStatusCode: true });