From 29589c07cc57ab0760c789622417db60b7461c34 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:03:02 +0200 Subject: [PATCH 01/46] chore(ci): Use Playwright Docker images instead of install-playwright action Replace the custom `install-playwright` composite action with official Playwright Docker images for browser integration tests, and inline `npx playwright install` for other jobs. **Browser integration tests** (playwright + loader): - Use `mcr.microsoft.com/playwright:v1.56.1-noble` container image - Browsers are pre-installed, no download or caching needed **Remix, E2E, canary, flaky-test-detector**: - Replace composite action with `npx playwright install --with-deps chromium` - These jobs have complex setups (Node version matrix, pnpm, Verdaccio) where a container adds unnecessary complexity This also removes the `actions/cache@v4` usage from the composite action, eliminating another source of Node.js 20 deprecation warnings. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-playwright/action.yml | 52 ------------------- .github/workflows/build.yml | 34 +++++------- .github/workflows/canary.yml | 6 +-- .github/workflows/flaky-test-detector.yml | 4 +- 4 files changed, 16 insertions(+), 80 deletions(-) delete mode 100644 .github/actions/install-playwright/action.yml diff --git a/.github/actions/install-playwright/action.yml b/.github/actions/install-playwright/action.yml deleted file mode 100644 index ec6ae171e925..000000000000 --- a/.github/actions/install-playwright/action.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: 'Install Playwright dependencies' -description: 'Installs Playwright dependencies and caches them.' -inputs: - browsers: - description: 'What browsers to install.' - default: 'chromium webkit firefox' - cwd: - description: 'The working directory to run Playwright in.' - default: '.' - -runs: - using: 'composite' - steps: - - name: Get Playwright version - id: playwright-version - run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT - shell: bash - working-directory: ${{ inputs.cwd }} - - - name: Restore cached playwright binaries - uses: actions/cache/restore@v5 - id: playwright-cache - with: - path: | - ~/.cache/ms-playwright - # Bump the iteration when bumping runner images to use a new cache - key: playwright-${{ runner.os }}-iteration-1-${{ steps.playwright-version.outputs.version }} - - # We always install all browsers, if uncached - - name: Install Playwright dependencies (uncached) - run: npx playwright install chromium webkit firefox --with-deps - if: steps.playwright-cache.outputs.cache-hit != 'true' - shell: bash - working-directory: ${{ inputs.cwd }} - - - name: Install Playwright system dependencies only (cached) - env: - PLAYWRIGHT_BROWSERS: ${{ inputs.browsers || 'chromium webkit firefox' }} - run: npx playwright install-deps "$PLAYWRIGHT_BROWSERS" - if: steps.playwright-cache.outputs.cache-hit == 'true' - shell: bash - working-directory: ${{ inputs.cwd }} - - # Only store cache on develop branch - - name: Store cached playwright binaries - uses: actions/cache/save@v5 - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' - with: - path: | - ~/.cache/ms-playwright - # Bump the iteration when bumping runner images to use a new cache - key: playwright-${{ runner.os }}-iteration-1-${{ steps.playwright-version.outputs.version }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 544bb7900008..d6a15563ed02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -481,6 +481,8 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04-large-js + container: + image: mcr.microsoft.com/playwright:v1.56.1-noble timeout-minutes: 25 strategy: fail-fast: false @@ -538,16 +540,13 @@ jobs: uses: actions/setup-node@v6 with: node-version-file: 'package.json' + - name: Install yarn + run: npm install -g yarn@1.22.22 - name: Restore caches uses: ./.github/actions/restore-cache with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: ${{ matrix.project }} - - name: Run Playwright tests env: PW_BUNDLE: ${{ matrix.bundle }} @@ -584,6 +583,8 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 + container: + image: mcr.microsoft.com/playwright:v1.56.1-noble timeout-minutes: 15 strategy: fail-fast: false @@ -606,16 +607,13 @@ jobs: uses: actions/setup-node@v6 with: node-version-file: 'package.json' + - name: Install yarn + run: npm install -g yarn@1.22.22 - name: Restore caches uses: ./.github/actions/restore-cache with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: chromium - - name: Run Playwright Loader tests env: PW_BUNDLE: ${{ matrix.bundle }} @@ -823,9 +821,7 @@ jobs: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: chromium + run: npx playwright install --with-deps chromium - name: Run integration tests env: @@ -979,10 +975,8 @@ jobs: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: chromium - cwd: ${{ runner.temp }}/test-application + run: npx playwright install --with-deps chromium + working-directory: ${{ runner.temp }}/test-application - name: Run E2E test working-directory: ${{ runner.temp }}/test-application @@ -1087,10 +1081,8 @@ jobs: run: ${{ matrix.build-command || 'pnpm test:build' }} - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: chromium - cwd: ${{ runner.temp }}/test-application + run: npx playwright install --with-deps chromium + working-directory: ${{ runner.temp }}/test-application - name: Run E2E test working-directory: ${{ runner.temp }}/test-application diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index ac4e1df08841..9707b5369e19 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -158,10 +158,8 @@ jobs: run: yarn ${{ matrix.build-command }} - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: chromium - cwd: ${{ runner.temp }}/test-application + run: npx playwright install --with-deps chromium + working-directory: ${{ runner.temp }}/test-application - name: Run E2E test working-directory: ${{ runner.temp }}/test-application diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index c0a8f1f720b1..be4bd06de113 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -50,9 +50,7 @@ jobs: run: yarn build - name: Install Playwright - uses: ./.github/actions/install-playwright - with: - browsers: 'chromium' + run: npx playwright install --with-deps chromium - name: Determine changed tests uses: dorny/paths-filter@v4.0.1 From 6cb7c1dff83205b56ece0c09066dd272d246039a Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:20:30 +0200 Subject: [PATCH 02/46] chore(ci): Use custom GHCR Playwright image for all Playwright jobs Build a custom Docker image extending the official Playwright image with yarn pre-installed, push it to GHCR, and use it across all CI jobs that need Playwright browsers. - Add `.github/docker/playwright.Dockerfile` with yarn@1.22.22 - Add build workflow that pushes to GHCR on Dockerfile or Playwright version changes - All Playwright jobs (browser tests, loader tests, Remix, E2E, canary, flaky-test-detector) now use the GHCR container image - No more `npx playwright install` or browser caching logic anywhere When bumping @playwright/test, also update the PLAYWRIGHT_IMAGE env var in build.yml, canary.yml, and flaky-test-detector.yml. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 5 +++ .../build-playwright-docker-image.yml | 37 +++++++++++++++++ .github/workflows/build.yml | 41 +++++++++++-------- .github/workflows/canary.yml | 10 +++-- .github/workflows/flaky-test-detector.yml | 9 ++-- 5 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 .github/docker/playwright.Dockerfile create mode 100644 .github/workflows/build-playwright-docker-image.yml diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile new file mode 100644 index 000000000000..8c9d2b4ba5ea --- /dev/null +++ b/.github/docker/playwright.Dockerfile @@ -0,0 +1,5 @@ +ARG PLAYWRIGHT_VERSION=1.56.1 +FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble + +# Install yarn (v1) for the monorepo +RUN npm install -g yarn@1.22.22 diff --git a/.github/workflows/build-playwright-docker-image.yml b/.github/workflows/build-playwright-docker-image.yml new file mode 100644 index 000000000000..7177f8e122be --- /dev/null +++ b/.github/workflows/build-playwright-docker-image.yml @@ -0,0 +1,37 @@ +name: Build Playwright Docker Image +on: + push: + branches: [develop] + paths: + - '.github/docker/playwright.Dockerfile' + - 'dev-packages/browser-integration-tests/package.json' + workflow_dispatch: + +jobs: + build-image: + runs-on: ubuntu-24.04 + permissions: + packages: write + steps: + - uses: actions/checkout@v6 + + - name: Get Playwright version + id: playwright + run: echo "version=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test'].replace('~', '')")" >> $GITHUB_OUTPUT + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + file: .github/docker/playwright.Dockerfile + push: true + build-args: | + PLAYWRIGHT_VERSION=${{ steps.playwright.outputs.version }} + tags: | + ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6a15563ed02..8e106bab4185 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,7 @@ concurrency: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} + PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 # WARNING: this disables cross os caching as ~ and # github.workspace evaluate to differents paths @@ -482,7 +483,10 @@ jobs: if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04-large-js container: - image: mcr.microsoft.com/playwright:v1.56.1-noble + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 25 strategy: fail-fast: false @@ -540,8 +544,6 @@ jobs: uses: actions/setup-node@v6 with: node-version-file: 'package.json' - - name: Install yarn - run: npm install -g yarn@1.22.22 - name: Restore caches uses: ./.github/actions/restore-cache with: @@ -584,7 +586,10 @@ jobs: if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 container: - image: mcr.microsoft.com/playwright:v1.56.1-noble + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 15 strategy: fail-fast: false @@ -607,8 +612,6 @@ jobs: uses: actions/setup-node@v6 with: node-version-file: 'package.json' - - name: Install yarn - run: npm install -g yarn@1.22.22 - name: Restore caches uses: ./.github/actions/restore-cache with: @@ -801,6 +804,11 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_remix == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 + container: + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 15 strategy: fail-fast: false @@ -820,9 +828,6 @@ jobs: with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Install Playwright - run: npx playwright install --with-deps chromium - - name: Run integration tests env: NODE_VERSION: ${{ matrix.node }} @@ -900,6 +905,11 @@ jobs: always() && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix != '{"include":[]}' needs: [job_get_metadata, job_build, job_e2e_prepare] runs-on: ubuntu-24.04 + container: + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -974,10 +984,6 @@ jobs: env: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - - name: Install Playwright - run: npx playwright install --with-deps chromium - working-directory: ${{ runner.temp }}/test-application - - name: Run E2E test working-directory: ${{ runner.temp }}/test-application timeout-minutes: 10 @@ -1021,6 +1027,11 @@ jobs: github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' needs: [job_get_metadata, job_build, job_e2e_prepare] runs-on: ubuntu-24.04 + container: + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} @@ -1080,10 +1091,6 @@ jobs: timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} - - name: Install Playwright - run: npx playwright install --with-deps chromium - working-directory: ${{ runner.temp }}/test-application - - name: Run E2E test working-directory: ${{ runner.temp }}/test-application timeout-minutes: 10 diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 9707b5369e19..5bf0469ac4e7 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -11,6 +11,7 @@ on: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} + PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 CACHED_BUILD_PATHS: | ${{ github.workspace }}/packages/*/*.tgz @@ -55,6 +56,11 @@ jobs: name: E2E ${{ matrix.label }} Test needs: [job_e2e_prepare] runs-on: ubuntu-24.04 + container: + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -157,10 +163,6 @@ jobs: timeout-minutes: 7 run: yarn ${{ matrix.build-command }} - - name: Install Playwright - run: npx playwright install --with-deps chromium - working-directory: ${{ runner.temp }}/test-application - - name: Run E2E test working-directory: ${{ runner.temp }}/test-application timeout-minutes: 15 diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index be4bd06de113..2c8ee4485006 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -9,6 +9,7 @@ on: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} + PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 NX_CACHE_RESTORE_KEYS: | nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} @@ -24,6 +25,11 @@ concurrency: jobs: flaky-detector: runs-on: ubuntu-24.04 + container: + image: ${{ env.PLAYWRIGHT_IMAGE }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop @@ -49,9 +55,6 @@ jobs: - name: Build packages run: yarn build - - name: Install Playwright - run: npx playwright install --with-deps chromium - - name: Determine changed tests uses: dorny/paths-filter@v4.0.1 id: changed From 45622921630c471a993792c1c88cae6995963615 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:23:09 +0200 Subject: [PATCH 03/46] chore(ci): Run Playwright image build on PRs, verify version consistency - Trigger the build workflow on PRs that change the Dockerfile, Playwright version, or any e2e test application package.json - Add a version consistency check that verifies all packages and e2e test applications use the same @playwright/test version as the canonical source (dev-packages/browser-integration-tests) - On PRs, the image is built (to verify the Dockerfile) but not pushed - On push to develop and workflow_dispatch, the image is built and pushed Co-Authored-By: Claude Opus 4.6 (1M context) --- .../build-playwright-docker-image.yml | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-playwright-docker-image.yml b/.github/workflows/build-playwright-docker-image.yml index 7177f8e122be..993301c8a9e4 100644 --- a/.github/workflows/build-playwright-docker-image.yml +++ b/.github/workflows/build-playwright-docker-image.yml @@ -5,10 +5,70 @@ on: paths: - '.github/docker/playwright.Dockerfile' - 'dev-packages/browser-integration-tests/package.json' + pull_request: + paths: + - '.github/docker/playwright.Dockerfile' + - 'dev-packages/browser-integration-tests/package.json' + - 'dev-packages/e2e-tests/test-applications/*/package.json' + - 'dev-packages/test-utils/package.json' workflow_dispatch: jobs: + verify-playwright-versions: + name: Verify Playwright version consistency + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + + - name: Check all @playwright/test versions match + run: | + # Get the canonical version from browser-integration-tests + CANONICAL=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test']") + echo "Canonical @playwright/test version: $CANONICAL" + + MISMATCHES=0 + + # Check test-utils + for pkg in dev-packages/test-utils/package.json; do + VERSION=$(node -p " + const pkg = require('./$pkg'); + (pkg.dependencies || {})['@playwright/test'] || + (pkg.devDependencies || {})['@playwright/test'] || + (pkg.peerDependencies || {})['@playwright/test'] || + 'not found' + ") + if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then + echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" + MISMATCHES=$((MISMATCHES + 1)) + fi + done + + # Check all e2e test applications + for pkg in dev-packages/e2e-tests/test-applications/*/package.json; do + VERSION=$(node -p " + const pkg = require('./$pkg'); + (pkg.dependencies || {})['@playwright/test'] || + (pkg.devDependencies || {})['@playwright/test'] || + 'not found' + ") + if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then + echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" + MISMATCHES=$((MISMATCHES + 1)) + fi + done + + if [ "$MISMATCHES" -gt 0 ]; then + echo "" + echo "Found $MISMATCHES package(s) with mismatched @playwright/test versions." + echo "All packages must use the same version as dev-packages/browser-integration-tests ($CANONICAL)." + exit 1 + fi + + echo "All @playwright/test versions are consistent ($CANONICAL)" + build-image: + name: Build Playwright Docker Image + needs: [verify-playwright-versions] runs-on: ubuntu-24.04 permissions: packages: write @@ -30,7 +90,7 @@ jobs: uses: docker/build-push-action@v6 with: file: .github/docker/playwright.Dockerfile - push: true + push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} build-args: | PLAYWRIGHT_VERSION=${{ steps.playwright.outputs.version }} tags: | From b62134760412fd6c9108dc90434af6ed53f98114 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:26:40 +0200 Subject: [PATCH 04/46] chore(ci): Extract ensure-playwright-image composite action, remove standalone workflow Replace the standalone build-playwright-docker-image workflow with a composite action that runs as a prerequisite job in each workflow: - Verifies all @playwright/test versions are consistent across the repo - Checks if the GHCR image already exists (noop if so) - Builds and pushes only when the image is missing Each workflow (build, canary, flaky-test-detector) now has a small `job_playwright_image` prerequisite job that runs the composite action and outputs the image reference for downstream container jobs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ensure-playwright-image/action.yml | 98 +++++++++++++++++++ .../build-playwright-docker-image.yml | 97 ------------------ .github/workflows/build.yml | 46 ++++++--- .github/workflows/canary.yml | 26 ++++- .github/workflows/flaky-test-detector.yml | 25 ++++- 5 files changed, 179 insertions(+), 113 deletions(-) create mode 100644 .github/actions/ensure-playwright-image/action.yml delete mode 100644 .github/workflows/build-playwright-docker-image.yml diff --git a/.github/actions/ensure-playwright-image/action.yml b/.github/actions/ensure-playwright-image/action.yml new file mode 100644 index 000000000000..9c7531ba8259 --- /dev/null +++ b/.github/actions/ensure-playwright-image/action.yml @@ -0,0 +1,98 @@ +name: 'Ensure Playwright Docker Image' +description: 'Checks if the custom Playwright Docker image exists in GHCR. Builds and pushes it if missing.' + +inputs: + github_token: + description: 'GitHub token with packages:write permission' + required: true + +outputs: + image: + description: 'The full Docker image reference (e.g. ghcr.io/owner/repo/playwright:v1.56.0)' + value: ${{ steps.image.outputs.ref }} + +runs: + using: 'composite' + steps: + - name: Get Playwright version + id: playwright + run: echo "version=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test'].replace('~', '')")" >> $GITHUB_OUTPUT + shell: bash + + - name: Verify @playwright/test version consistency + shell: bash + run: | + CANONICAL=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test']") + MISMATCHES=0 + + for pkg in dev-packages/test-utils/package.json; do + VERSION=$(node -p " + const pkg = require('./$pkg'); + (pkg.dependencies || {})['@playwright/test'] || + (pkg.devDependencies || {})['@playwright/test'] || + (pkg.peerDependencies || {})['@playwright/test'] || + 'not found' + ") + if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then + echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" + MISMATCHES=$((MISMATCHES + 1)) + fi + done + + for pkg in dev-packages/e2e-tests/test-applications/*/package.json; do + VERSION=$(node -p " + const pkg = require('./$pkg'); + (pkg.dependencies || {})['@playwright/test'] || + (pkg.devDependencies || {})['@playwright/test'] || + 'not found' + ") + if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then + echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" + MISMATCHES=$((MISMATCHES + 1)) + fi + done + + if [ "$MISMATCHES" -gt 0 ]; then + echo "Found $MISMATCHES package(s) with mismatched @playwright/test versions." + echo "All packages must use the same version as dev-packages/browser-integration-tests ($CANONICAL)." + exit 1 + fi + echo "All @playwright/test versions are consistent ($CANONICAL)" + + - name: Set image reference + id: image + run: echo "ref=ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }}" >> $GITHUB_OUTPUT + shell: bash + + - name: Check if image already exists + id: check + shell: bash + run: | + if docker manifest inspect "${{ steps.image.outputs.ref }}" > /dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Image ${{ steps.image.outputs.ref }} already exists, skipping build." + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Image ${{ steps.image.outputs.ref }} not found, will build." + fi + env: + DOCKER_CLI_EXPERIMENTAL: enabled + + - name: Log in to GHCR + if: steps.check.outputs.exists == 'false' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ inputs.github_token }} + + - name: Build and push + if: steps.check.outputs.exists == 'false' + uses: docker/build-push-action@v6 + with: + file: .github/docker/playwright.Dockerfile + push: true + build-args: | + PLAYWRIGHT_VERSION=${{ steps.playwright.outputs.version }} + tags: | + ${{ steps.image.outputs.ref }} diff --git a/.github/workflows/build-playwright-docker-image.yml b/.github/workflows/build-playwright-docker-image.yml deleted file mode 100644 index 993301c8a9e4..000000000000 --- a/.github/workflows/build-playwright-docker-image.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Build Playwright Docker Image -on: - push: - branches: [develop] - paths: - - '.github/docker/playwright.Dockerfile' - - 'dev-packages/browser-integration-tests/package.json' - pull_request: - paths: - - '.github/docker/playwright.Dockerfile' - - 'dev-packages/browser-integration-tests/package.json' - - 'dev-packages/e2e-tests/test-applications/*/package.json' - - 'dev-packages/test-utils/package.json' - workflow_dispatch: - -jobs: - verify-playwright-versions: - name: Verify Playwright version consistency - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - - name: Check all @playwright/test versions match - run: | - # Get the canonical version from browser-integration-tests - CANONICAL=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test']") - echo "Canonical @playwright/test version: $CANONICAL" - - MISMATCHES=0 - - # Check test-utils - for pkg in dev-packages/test-utils/package.json; do - VERSION=$(node -p " - const pkg = require('./$pkg'); - (pkg.dependencies || {})['@playwright/test'] || - (pkg.devDependencies || {})['@playwright/test'] || - (pkg.peerDependencies || {})['@playwright/test'] || - 'not found' - ") - if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then - echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" - MISMATCHES=$((MISMATCHES + 1)) - fi - done - - # Check all e2e test applications - for pkg in dev-packages/e2e-tests/test-applications/*/package.json; do - VERSION=$(node -p " - const pkg = require('./$pkg'); - (pkg.dependencies || {})['@playwright/test'] || - (pkg.devDependencies || {})['@playwright/test'] || - 'not found' - ") - if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then - echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" - MISMATCHES=$((MISMATCHES + 1)) - fi - done - - if [ "$MISMATCHES" -gt 0 ]; then - echo "" - echo "Found $MISMATCHES package(s) with mismatched @playwright/test versions." - echo "All packages must use the same version as dev-packages/browser-integration-tests ($CANONICAL)." - exit 1 - fi - - echo "All @playwright/test versions are consistent ($CANONICAL)" - - build-image: - name: Build Playwright Docker Image - needs: [verify-playwright-versions] - runs-on: ubuntu-24.04 - permissions: - packages: write - steps: - - uses: actions/checkout@v6 - - - name: Get Playwright version - id: playwright - run: echo "version=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test'].replace('~', '')")" >> $GITHUB_OUTPUT - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v6 - with: - file: .github/docker/playwright.Dockerfile - push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} - build-args: | - PLAYWRIGHT_VERSION=${{ steps.playwright.outputs.version }} - tags: | - ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e106bab4185..5395379c5f91 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,6 @@ concurrency: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} - PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 # WARNING: this disables cross os caching as ~ and # github.workspace evaluate to differents paths @@ -72,6 +71,29 @@ jobs: permissions: pull-requests: read + job_playwright_image: + name: Ensure Playwright Image + runs-on: ubuntu-24.04 + permissions: + packages: write + outputs: + image: ${{ steps.ensure.outputs.image }} + steps: + - name: Check out current commit + uses: actions/checkout@v6 + with: + ref: ${{ env.HEAD_COMMIT }} + sparse-checkout: | + .github + dev-packages/browser-integration-tests/package.json + dev-packages/test-utils/package.json + dev-packages/e2e-tests/test-applications + - name: Ensure Playwright image + id: ensure + uses: ./.github/actions/ensure-playwright-image + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + job_build: name: Build needs: job_get_metadata @@ -479,11 +501,11 @@ jobs: name: Playwright ${{ matrix.bundle }}${{ matrix.project && matrix.project != 'chromium' && format(' {0}', matrix.project) || ''}}${{ matrix.shard && format(' ({0}/{1})', matrix.shard, matrix.shards) || ''}} Tests - needs: [job_get_metadata, job_build] + needs: [job_get_metadata, job_build, job_playwright_image] if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04-large-js container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -582,11 +604,11 @@ jobs: job_browser_loader_tests: name: PW ${{ matrix.bundle }} Tests - needs: [job_get_metadata, job_build] + needs: [job_get_metadata, job_build, job_playwright_image] if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -801,11 +823,11 @@ jobs: job_remix_integration_tests: name: Remix (Node ${{ matrix.node }}) Tests - needs: [job_get_metadata, job_build] + needs: [job_get_metadata, job_build, job_playwright_image] if: needs.job_build.outputs.changed_remix == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -903,10 +925,11 @@ jobs: # See: https://github.com/actions/runner/issues/2205 if: always() && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix != '{"include":[]}' - needs: [job_get_metadata, job_build, job_e2e_prepare] + && needs.job_playwright_image.result == 'success' + needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -1025,10 +1048,11 @@ jobs: always() && needs.job_get_metadata.outputs.is_release != 'true' && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix-optional != '{"include":[]}' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' - needs: [job_get_metadata, job_build, job_e2e_prepare] + && needs.job_playwright_image.result == 'success' + needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 5bf0469ac4e7..c419c88fbdf6 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -11,7 +11,6 @@ on: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} - PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 CACHED_BUILD_PATHS: | ${{ github.workspace }}/packages/*/*.tgz @@ -24,8 +23,29 @@ env: permissions: contents: read issues: write + packages: write jobs: + job_playwright_image: + name: Ensure Playwright Image + runs-on: ubuntu-24.04 + outputs: + image: ${{ steps.ensure.outputs.image }} + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ env.HEAD_COMMIT }} + sparse-checkout: | + .github + dev-packages/browser-integration-tests/package.json + dev-packages/test-utils/package.json + dev-packages/e2e-tests/test-applications + - name: Ensure Playwright image + id: ensure + uses: ./.github/actions/ensure-playwright-image + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + job_e2e_prepare: name: Prepare E2E Canary tests runs-on: ubuntu-24.04 @@ -54,10 +74,10 @@ jobs: job_e2e_tests: name: E2E ${{ matrix.label }} Test - needs: [job_e2e_prepare] + needs: [job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 2c8ee4485006..a020a8bf93fe 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -9,7 +9,6 @@ on: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} - PLAYWRIGHT_IMAGE: ghcr.io/getsentry/sentry-javascript/playwright:v1.56.1 NX_CACHE_RESTORE_KEYS: | nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} @@ -23,10 +22,32 @@ concurrency: cancel-in-progress: true jobs: + job_playwright_image: + name: Ensure Playwright Image + runs-on: ubuntu-24.04 + permissions: + packages: write + outputs: + image: ${{ steps.ensure.outputs.image }} + steps: + - uses: actions/checkout@v6 + with: + sparse-checkout: | + .github + dev-packages/browser-integration-tests/package.json + dev-packages/test-utils/package.json + dev-packages/e2e-tests/test-applications + - name: Ensure Playwright image + id: ensure + uses: ./.github/actions/ensure-playwright-image + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + flaky-detector: + needs: [job_playwright_image] runs-on: ubuntu-24.04 container: - image: ${{ env.PLAYWRIGHT_IMAGE }} + image: ${{ needs.job_playwright_image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} From c0c1a1cc0cc2df35d515e29a02499de382589be0 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:28:41 +0200 Subject: [PATCH 05/46] fix(ci): Remove hardcoded default from Playwright Dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the default value for PLAYWRIGHT_VERSION ARG so the build fails if the arg isn't passed. The ensure-playwright-image action reads the version from browser-integration-tests/package.json and passes it as a build arg — that is the single source of truth. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 8c9d2b4ba5ea..e08df49898e7 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -1,4 +1,6 @@ -ARG PLAYWRIGHT_VERSION=1.56.1 +# PLAYWRIGHT_VERSION is passed as a build arg by the ensure-playwright-image action. +# The canonical source is dev-packages/browser-integration-tests/package.json. +ARG PLAYWRIGHT_VERSION FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble # Install yarn (v1) for the monorepo From ec7c8141b639be6382527e80509836f662a3bbf8 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:29:16 +0200 Subject: [PATCH 06/46] chore(ci): Remove sparse-checkout from Playwright image jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the checkout steps — full checkout is fine here and avoids potential issues with missing files. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 5 ----- .github/workflows/canary.yml | 5 ----- .github/workflows/flaky-test-detector.yml | 6 ------ 3 files changed, 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5395379c5f91..ff9d252e0b08 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,11 +83,6 @@ jobs: uses: actions/checkout@v6 with: ref: ${{ env.HEAD_COMMIT }} - sparse-checkout: | - .github - dev-packages/browser-integration-tests/package.json - dev-packages/test-utils/package.json - dev-packages/e2e-tests/test-applications - name: Ensure Playwright image id: ensure uses: ./.github/actions/ensure-playwright-image diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index c419c88fbdf6..b7dccc8da1db 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -35,11 +35,6 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ env.HEAD_COMMIT }} - sparse-checkout: | - .github - dev-packages/browser-integration-tests/package.json - dev-packages/test-utils/package.json - dev-packages/e2e-tests/test-applications - name: Ensure Playwright image id: ensure uses: ./.github/actions/ensure-playwright-image diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index a020a8bf93fe..d50c8834f9a7 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -31,12 +31,6 @@ jobs: image: ${{ steps.ensure.outputs.image }} steps: - uses: actions/checkout@v6 - with: - sparse-checkout: | - .github - dev-packages/browser-integration-tests/package.json - dev-packages/test-utils/package.json - dev-packages/e2e-tests/test-applications - name: Ensure Playwright image id: ensure uses: ./.github/actions/ensure-playwright-image From 4551b42ce7c79b5258cbce16d596ca12f30adb58 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 10:31:52 +0200 Subject: [PATCH 07/46] fix(ci): Fix Playwright version extraction in ensure-playwright-image @playwright/test is in `dependencies` (not `devDependencies`) in browser-integration-tests/package.json. Check both fields so the version is found regardless of which section it's declared in. Also cleaned up the version consistency check to use a shared function and log the canonical version for easier debugging. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ensure-playwright-image/action.yml | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/.github/actions/ensure-playwright-image/action.yml b/.github/actions/ensure-playwright-image/action.yml index 9c7531ba8259..ce05398c599e 100644 --- a/.github/actions/ensure-playwright-image/action.yml +++ b/.github/actions/ensure-playwright-image/action.yml @@ -16,40 +16,45 @@ runs: steps: - name: Get Playwright version id: playwright - run: echo "version=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test'].replace('~', '')")" >> $GITHUB_OUTPUT + run: | + VERSION=$(node -p " + const pkg = require('./dev-packages/browser-integration-tests/package.json'); + const v = (pkg.dependencies || {})['@playwright/test'] || (pkg.devDependencies || {})['@playwright/test']; + v.replace(/[~^]/, '') + ") + echo "version=$VERSION" >> $GITHUB_OUTPUT shell: bash - name: Verify @playwright/test version consistency shell: bash run: | - CANONICAL=$(node -p "require('./dev-packages/browser-integration-tests/package.json').devDependencies['@playwright/test']") + CANONICAL=$(node -p " + const pkg = require('./dev-packages/browser-integration-tests/package.json'); + (pkg.dependencies || {})['@playwright/test'] || (pkg.devDependencies || {})['@playwright/test'] + ") + echo "Canonical @playwright/test version: $CANONICAL" MISMATCHES=0 - for pkg in dev-packages/test-utils/package.json; do - VERSION=$(node -p " - const pkg = require('./$pkg'); + check_version() { + local file="$1" + local version + version=$(node -p " + const pkg = require('./$file'); (pkg.dependencies || {})['@playwright/test'] || (pkg.devDependencies || {})['@playwright/test'] || (pkg.peerDependencies || {})['@playwright/test'] || 'not found' ") - if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then - echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" + if [ "$version" != "not found" ] && [ "$version" != "$CANONICAL" ]; then + echo "::error file=$file::@playwright/test version mismatch: $version (expected $CANONICAL)" MISMATCHES=$((MISMATCHES + 1)) fi - done + } + + check_version "dev-packages/test-utils/package.json" for pkg in dev-packages/e2e-tests/test-applications/*/package.json; do - VERSION=$(node -p " - const pkg = require('./$pkg'); - (pkg.dependencies || {})['@playwright/test'] || - (pkg.devDependencies || {})['@playwright/test'] || - 'not found' - ") - if [ "$VERSION" != "not found" ] && [ "$VERSION" != "$CANONICAL" ]; then - echo "::error file=$pkg::@playwright/test version mismatch: $VERSION (expected $CANONICAL)" - MISMATCHES=$((MISMATCHES + 1)) - fi + check_version "$pkg" done if [ "$MISMATCHES" -gt 0 ]; then From ade0a16b6db02772501b92a20c94b22fdc4c3e4e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 14:14:51 +0200 Subject: [PATCH 08/46] fix(ci): Add --ipc=host to Playwright container options Firefox fails with "Sandbox: CanCreateUserNamespace() clone() failure: EPERM" when running in a Docker container on GitHub Actions because user namespaces are restricted. Adding --ipc=host allows the browser sandbox to work correctly for all browsers (chromium, firefox, webkit). Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 9 +++++++-- .github/workflows/canary.yml | 1 + .github/workflows/flaky-test-detector.yml | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ff9d252e0b08..5e7f560f21ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -504,6 +504,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 25 strategy: fail-fast: false @@ -607,6 +608,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 15 strategy: fail-fast: false @@ -826,6 +828,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 15 strategy: fail-fast: false @@ -928,6 +931,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1042,8 +1046,8 @@ jobs: if: always() && needs.job_get_metadata.outputs.is_release != 'true' && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix-optional != '{"include":[]}' && (github.event_name != 'pull_request' || - github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' - && needs.job_playwright_image.result == 'success' + github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' && + needs.job_playwright_image.result == 'success' needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 container: @@ -1051,6 +1055,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index b7dccc8da1db..f4cf10e14c45 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -76,6 +76,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index d50c8834f9a7..c055f2a692c9 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,6 +45,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From d8edc30e3689b3f5abb452ac0ab3795cfd072fc8 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 14:15:33 +0200 Subject: [PATCH 09/46] chore: Format ensure-playwright-image action Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/ensure-playwright-image/action.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/ensure-playwright-image/action.yml b/.github/actions/ensure-playwright-image/action.yml index ce05398c599e..dfaa8ba6bcfa 100644 --- a/.github/actions/ensure-playwright-image/action.yml +++ b/.github/actions/ensure-playwright-image/action.yml @@ -66,7 +66,9 @@ runs: - name: Set image reference id: image - run: echo "ref=ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }}" >> $GITHUB_OUTPUT + run: + echo "ref=ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }}" >> + $GITHUB_OUTPUT shell: bash - name: Check if image already exists From a3f5d959f7b8e5753caef4705209e3afbbc571cb Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 14:43:53 +0200 Subject: [PATCH 10/46] fix(ci): Include Dockerfile hash in Playwright image tag The image tag was only based on the Playwright version, so changes to the Dockerfile (e.g. adding yarn, system deps) didn't trigger a rebuild. Tag is now `v-<8-char-dockerfile-hash>`, e.g. `v1.56.0-a1b2c3d4`. Any change to the Dockerfile produces a new tag, which misses the GHCR cache and triggers a fresh build. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/ensure-playwright-image/action.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/actions/ensure-playwright-image/action.yml b/.github/actions/ensure-playwright-image/action.yml index dfaa8ba6bcfa..fab5bb8b5d4c 100644 --- a/.github/actions/ensure-playwright-image/action.yml +++ b/.github/actions/ensure-playwright-image/action.yml @@ -66,10 +66,11 @@ runs: - name: Set image reference id: image - run: - echo "ref=ghcr.io/${{ github.repository }}/playwright:v${{ steps.playwright.outputs.version }}" >> - $GITHUB_OUTPUT shell: bash + run: | + DOCKERFILE_HASH=$(sha256sum .github/docker/playwright.Dockerfile | cut -c1-8) + TAG="v${{ steps.playwright.outputs.version }}-${DOCKERFILE_HASH}" + echo "ref=ghcr.io/${{ github.repository }}/playwright:${TAG}" >> $GITHUB_OUTPUT - name: Check if image already exists id: check From f50802efda9cce21e922fcf2880e6ee73d73ee3d Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Tue, 14 Apr 2026 14:44:39 +0200 Subject: [PATCH 11/46] fix(ci): Set HOME=/root for Playwright containers GitHub Actions runs containers as root but sets HOME=/github/home (owned by pwuser). Firefox refuses to launch as root in another user's home directory. Setting HOME=/root fixes this. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 10 +++++----- .github/workflows/canary.yml | 2 +- .github/workflows/flaky-test-detector.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e7f560f21ce..e417d69b56bb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -504,7 +504,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 25 strategy: fail-fast: false @@ -608,7 +608,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 15 strategy: fail-fast: false @@ -828,7 +828,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 15 strategy: fail-fast: false @@ -931,7 +931,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1055,7 +1055,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index f4cf10e14c45..a2c4099aeae9 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -76,7 +76,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index c055f2a692c9..6737ccea13b5 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,7 +45,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host -e HOME=/root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From 50f388956d238f908489426c099fa567a4ac0d7c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 09:31:29 +0200 Subject: [PATCH 12/46] fix(ci): Use container.env instead of -e flag for HOME=/root The -e flag in container options gets overridden by GitHub Actions. Use container.env which is the proper way to set environment variables inside job containers and takes precedence over the Actions default. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 20 +++++++++++++++----- .github/workflows/canary.yml | 4 +++- .github/workflows/flaky-test-detector.yml | 4 +++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e417d69b56bb..2bc1d1ca3660 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -504,7 +504,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 25 strategy: fail-fast: false @@ -608,7 +610,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 15 strategy: fail-fast: false @@ -828,7 +832,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 15 strategy: fail-fast: false @@ -931,7 +937,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1055,7 +1063,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index a2c4099aeae9..1097417f8e23 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -76,7 +76,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 6737ccea13b5..19bb79a14328 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,7 +45,9 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host -e HOME=/root + options: --ipc=host + env: + HOME: /root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From d25f3c627da9dae03a31cd588728b726e8cc1eee Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 09:37:44 +0200 Subject: [PATCH 13/46] fix(ci): Enable cross-OS cache archive for container compatibility actions/cache computes an internal version hash from the cache paths and runner environment. When a cache is saved on the host runner but restored inside a Docker container, the paths resolve differently (e.g. ~ expands to /home/runner vs /root), causing a version mismatch and cache miss. Adding `enableCrossOsArchive: true` to all cache save/restore steps makes the version hash environment-independent, allowing caches to be shared between host runners and container jobs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-dependencies/action.yml | 2 ++ .github/actions/restore-cache/action.yml | 2 ++ .github/workflows/build.yml | 6 ++++++ .github/workflows/canary.yml | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index a862cd355af2..fe3b340e19b4 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -20,6 +20,8 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 1d5126fbe952..0b9dd2ca2967 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -15,6 +15,8 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ inputs.dependency_cache_key }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Restore build artifacts uses: actions/download-artifact@v7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bc1d1ca3660..e19d8ade1d89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -908,6 +908,8 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Determine which E2E test applications should be run id: matrix @@ -990,6 +992,8 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' @@ -1103,6 +1107,8 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 1097417f8e23..259f236189a6 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -59,6 +59,8 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Install dependencies run: yarn install - name: Build packages @@ -163,6 +165,8 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + # Required: cache is saved on host but restored inside Docker containers + enableCrossOsArchive: true - name: Validate Verdaccio run: yarn test:validate From 582d1d1b64f5f2ca82cde5e03e7dce7f1d5d178e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 09:39:01 +0200 Subject: [PATCH 14/46] fix(ci): Add git safe.directory to Playwright Docker image The container runs as root but the GitHub Actions workspace is owned by a different user, causing "dubious ownership" errors when rollup (or other tools) shell out to git. Baking `safe.directory '*'` into the image fixes this for all container jobs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index e08df49898e7..3dd80fc8aab8 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -5,3 +5,8 @@ FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble # Install yarn (v1) for the monorepo RUN npm install -g yarn@1.22.22 + +# Mark GitHub Actions workspace as safe for git. +# The container runs as root but the workspace is owned by a different user, +# causing "dubious ownership" errors in git operations (e.g. rollup build). +RUN git config --global --add safe.directory '*' From 50b7f381452d7abc8f0e98457903dae4e25747f9 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 10:58:11 +0200 Subject: [PATCH 15/46] use different docker file --- .github/docker/playwright.Dockerfile | 36 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 3dd80fc8aab8..984b1a88c684 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -1,10 +1,36 @@ -# PLAYWRIGHT_VERSION is passed as a build arg by the ensure-playwright-image action. -# The canonical source is dev-packages/browser-integration-tests/package.json. +# Use the same Ubuntu version as GitHub Actions runners (ubuntu-24.04) +# instead of the official Playwright image, to avoid missing system +# packages and configuration differences. +FROM ubuntu:24.04 + ARG PLAYWRIGHT_VERSION -FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble -# Install yarn (v1) for the monorepo -RUN npm install -g yarn@1.22.22 +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + git \ + gnupg && \ + rm -rf /var/lib/apt/lists/* + +# Install Volta for Node.js/Yarn version management (matches repo setup). +# Node and Yarn versions are pinned in the repo's package.json volta config. +ENV VOLTA_HOME=/root/.volta +ENV PATH=$VOLTA_HOME/bin:$PATH +RUN curl https://get.volta.sh | bash + +# Install Node.js and Yarn via Volta at the versions pinned in the repo +RUN volta install node@20.19.2 && \ + volta install yarn@1.22.22 + +# Install Playwright browsers and their OS-level dependencies. +# `npx playwright install --with-deps` installs both browsers and +# any missing system libraries (libglib, libatk, libnss, etc.). +RUN npx playwright@${PLAYWRIGHT_VERSION} install --with-deps # Mark GitHub Actions workspace as safe for git. # The container runs as root but the workspace is owned by a different user, From e7f44fe297eabb1f54b7e72c3d045095b2b8cbc8 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 11:00:20 +0200 Subject: [PATCH 16/46] fix(ci): Use Ubuntu base with Volta for Playwright Docker image Use ubuntu:24.04 as the base image instead of the official Playwright Docker image to avoid missing system packages and config differences. Install Node/Yarn via Volta to match the repo's version management. Since the container now uses the same OS as GHA runners, remove the enableCrossOsArchive workaround from all cache steps. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-dependencies/action.yml | 2 -- .github/actions/restore-cache/action.yml | 2 -- .github/workflows/build.yml | 6 ------ .github/workflows/canary.yml | 4 ---- 4 files changed, 14 deletions(-) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index fe3b340e19b4..a862cd355af2 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -20,8 +20,6 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 0b9dd2ca2967..1d5126fbe952 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -15,8 +15,6 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ inputs.dependency_cache_key }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Restore build artifacts uses: actions/download-artifact@v7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e19d8ade1d89..2bc1d1ca3660 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -908,8 +908,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Determine which E2E test applications should be run id: matrix @@ -992,8 +990,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' @@ -1107,8 +1103,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 259f236189a6..1097417f8e23 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -59,8 +59,6 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Install dependencies run: yarn install - name: Build packages @@ -165,8 +163,6 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} - # Required: cache is saved on host but restored inside Docker containers - enableCrossOsArchive: true - name: Validate Verdaccio run: yarn test:validate From 46c89a3f26e4822beb23b3f878e891e476369684 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 11:55:41 +0200 Subject: [PATCH 17/46] no volta etc. setup --- .github/docker/playwright.Dockerfile | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 984b1a88c684..6e97db3cef9e 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -17,16 +17,6 @@ RUN apt-get update && \ gnupg && \ rm -rf /var/lib/apt/lists/* -# Install Volta for Node.js/Yarn version management (matches repo setup). -# Node and Yarn versions are pinned in the repo's package.json volta config. -ENV VOLTA_HOME=/root/.volta -ENV PATH=$VOLTA_HOME/bin:$PATH -RUN curl https://get.volta.sh | bash - -# Install Node.js and Yarn via Volta at the versions pinned in the repo -RUN volta install node@20.19.2 && \ - volta install yarn@1.22.22 - # Install Playwright browsers and their OS-level dependencies. # `npx playwright install --with-deps` installs both browsers and # any missing system libraries (libglib, libatk, libnss, etc.). From e20d61678982093f8b188436a821a99a6ce83986 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 11:59:20 +0200 Subject: [PATCH 18/46] fully install playwright --- .github/docker/playwright.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 6e97db3cef9e..b138f925e08f 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -20,7 +20,7 @@ RUN apt-get update && \ # Install Playwright browsers and their OS-level dependencies. # `npx playwright install --with-deps` installs both browsers and # any missing system libraries (libglib, libatk, libnss, etc.). -RUN npx playwright@${PLAYWRIGHT_VERSION} install --with-deps +RUN npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps # Mark GitHub Actions workspace as safe for git. # The container runs as root but the workspace is owned by a different user, From eb8c6bd6525ff63fe2799e806da50520499ca3f7 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 12:10:54 +0200 Subject: [PATCH 19/46] fix(ci): Use actions-runner base image and drop Volta from Dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend ghcr.io/actions/actions-runner:2.333.1 instead of plain ubuntu. Remove Volta — actions/setup-node in workflow steps handles Node/Yarn. Update HOME env to /home/runner to match the runner user in the image. Remove enableCrossOsArchive since the container OS matches the host. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 27 +++++++++-------------- .github/workflows/build.yml | 10 ++++----- .github/workflows/canary.yml | 2 +- .github/workflows/flaky-test-detector.yml | 2 +- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index b138f925e08f..c69f75161be8 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -1,28 +1,23 @@ -# Use the same Ubuntu version as GitHub Actions runners (ubuntu-24.04) -# instead of the official Playwright image, to avoid missing system -# packages and configuration differences. -FROM ubuntu:24.04 +# Extend the GitHub Actions runner image (Ubuntu 24.04 based) to get an +# environment close to what GHA hosted runners provide. +FROM ghcr.io/actions/actions-runner:2.333.1 ARG PLAYWRIGHT_VERSION # Prevent interactive prompts during package installation ENV DEBIAN_FRONTEND=noninteractive -# Install system dependencies -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - curl \ - ca-certificates \ - git \ - gnupg && \ - rm -rf /var/lib/apt/lists/* +# Install a temporary Node.js to bootstrap Playwright browser installation. +# At runtime, actions/setup-node handles Node/Yarn from the workflow steps. +RUN sudo curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash - && \ + sudo apt-get install -y --no-install-recommends nodejs && \ + sudo rm -rf /var/lib/apt/lists/* # Install Playwright browsers and their OS-level dependencies. -# `npx playwright install --with-deps` installs both browsers and -# any missing system libraries (libglib, libatk, libnss, etc.). -RUN npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps +# `--with-deps` installs required system libraries (libglib, libatk, libnss, etc.). +RUN sudo npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps # Mark GitHub Actions workspace as safe for git. -# The container runs as root but the workspace is owned by a different user, +# The container may run with a different workspace owner, # causing "dubious ownership" errors in git operations (e.g. rollup build). RUN git config --global --add safe.directory '*' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bc1d1ca3660..947acb77f8e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -506,7 +506,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 25 strategy: fail-fast: false @@ -612,7 +612,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 15 strategy: fail-fast: false @@ -834,7 +834,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 15 strategy: fail-fast: false @@ -939,7 +939,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1065,7 +1065,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 1097417f8e23..abb46e8df805 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -78,7 +78,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 19bb79a14328..34f136844eb6 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host env: - HOME: /root + HOME: /home/runner timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From f6b771ab43601425ac1470c4993796cf67048c81 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 12:42:10 +0200 Subject: [PATCH 20/46] fix(ci): Install Node/Yarn in Playwright image from package.json versions Read node and yarn versions from the root package.json volta config and pass them as build args to the Dockerfile. This ensures the Docker image always has Node and Yarn installed at the same versions the repo pins. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ensure-playwright-image/action.yml | 19 +++++++++++++------ .github/docker/playwright.Dockerfile | 10 ++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/actions/ensure-playwright-image/action.yml b/.github/actions/ensure-playwright-image/action.yml index fab5bb8b5d4c..647bd933e9e4 100644 --- a/.github/actions/ensure-playwright-image/action.yml +++ b/.github/actions/ensure-playwright-image/action.yml @@ -14,15 +14,20 @@ outputs: runs: using: 'composite' steps: - - name: Get Playwright version - id: playwright + - name: Get versions + id: versions run: | - VERSION=$(node -p " + PLAYWRIGHT_VERSION=$(node -p " const pkg = require('./dev-packages/browser-integration-tests/package.json'); const v = (pkg.dependencies || {})['@playwright/test'] || (pkg.devDependencies || {})['@playwright/test']; v.replace(/[~^]/, '') ") - echo "version=$VERSION" >> $GITHUB_OUTPUT + ROOT_PKG=$(node -p "JSON.stringify(require('./package.json').volta)") + NODE_VERSION=$(echo "$ROOT_PKG" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).node") + YARN_VERSION=$(echo "$ROOT_PKG" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).yarn") + echo "playwright=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT + echo "node=$NODE_VERSION" >> $GITHUB_OUTPUT + echo "yarn=$YARN_VERSION" >> $GITHUB_OUTPUT shell: bash - name: Verify @playwright/test version consistency @@ -69,7 +74,7 @@ runs: shell: bash run: | DOCKERFILE_HASH=$(sha256sum .github/docker/playwright.Dockerfile | cut -c1-8) - TAG="v${{ steps.playwright.outputs.version }}-${DOCKERFILE_HASH}" + TAG="v${{ steps.versions.outputs.playwright }}-${DOCKERFILE_HASH}" echo "ref=ghcr.io/${{ github.repository }}/playwright:${TAG}" >> $GITHUB_OUTPUT - name: Check if image already exists @@ -101,6 +106,8 @@ runs: file: .github/docker/playwright.Dockerfile push: true build-args: | - PLAYWRIGHT_VERSION=${{ steps.playwright.outputs.version }} + PLAYWRIGHT_VERSION=${{ steps.versions.outputs.playwright }} + NODE_VERSION=${{ steps.versions.outputs.node }} + YARN_VERSION=${{ steps.versions.outputs.yarn }} tags: | ${{ steps.image.outputs.ref }} diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index c69f75161be8..adf31b14a903 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -3,15 +3,17 @@ FROM ghcr.io/actions/actions-runner:2.333.1 ARG PLAYWRIGHT_VERSION +ARG NODE_VERSION +ARG YARN_VERSION # Prevent interactive prompts during package installation ENV DEBIAN_FRONTEND=noninteractive -# Install a temporary Node.js to bootstrap Playwright browser installation. -# At runtime, actions/setup-node handles Node/Yarn from the workflow steps. -RUN sudo curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash - && \ +# Install Node.js and Yarn at the versions pinned in the repo's package.json. +RUN sudo curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | sudo bash - && \ sudo apt-get install -y --no-install-recommends nodejs && \ - sudo rm -rf /var/lib/apt/lists/* + sudo rm -rf /var/lib/apt/lists/* && \ + sudo npm install -g yarn@${YARN_VERSION} # Install Playwright browsers and their OS-level dependencies. # `--with-deps` installs required system libraries (libglib, libatk, libnss, etc.). From 252c67bc51498bb2d8822c64b37825003c986d01 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 12:42:28 +0200 Subject: [PATCH 21/46] fix(ci): Install zstd in Playwright Docker image Required by actions/cache for compression. The actions-runner base image does not include it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index adf31b14a903..c6ac02ccdd14 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -9,7 +9,11 @@ ARG YARN_VERSION # Prevent interactive prompts during package installation ENV DEBIAN_FRONTEND=noninteractive -# Install Node.js and Yarn at the versions pinned in the repo's package.json. +# Install zstd (required by actions/cache for compression) and Node.js + Yarn +# at the versions pinned in the repo's package.json. +RUN sudo apt-get update && \ + sudo apt-get install -y --no-install-recommends zstd && \ + sudo rm -rf /var/lib/apt/lists/* RUN sudo curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | sudo bash - && \ sudo apt-get install -y --no-install-recommends nodejs && \ sudo rm -rf /var/lib/apt/lists/* && \ From fe7f336b4b1eddda2297fcb6000924a63f0c1b19 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 12:54:28 +0200 Subject: [PATCH 22/46] fix(ci): Re-add enableCrossOsArchive for cache steps actions/cache needs this flag when caches are saved on the host but restored inside Docker containers, even when both run the same OS. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-dependencies/action.yml | 1 + .github/actions/restore-cache/action.yml | 1 + .github/workflows/build.yml | 3 +++ .github/workflows/canary.yml | 2 ++ 4 files changed, 7 insertions(+) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index a862cd355af2..88bd96548b24 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -20,6 +20,7 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} + enableCrossOsArchive: true - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 1d5126fbe952..08fb18f94f37 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -15,6 +15,7 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ inputs.dependency_cache_key }} + enableCrossOsArchive: true - name: Restore build artifacts uses: actions/download-artifact@v7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 947acb77f8e3..3de0589d15da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -908,6 +908,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Determine which E2E test applications should be run id: matrix @@ -990,6 +991,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' @@ -1103,6 +1105,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index abb46e8df805..324137fe8fbb 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -59,6 +59,7 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + enableCrossOsArchive: true - name: Install dependencies run: yarn install - name: Build packages @@ -163,6 +164,7 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + enableCrossOsArchive: true - name: Validate Verdaccio run: yarn test:validate From 29e5e395cf05697c4ef75ccc661ffd3e7dcce5a9 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 13:06:20 +0200 Subject: [PATCH 23/46] fix(ci): Fix Playwright browser path and git config in container GHA overrides HOME=/github/home inside containers, so browsers installed under /home/runner/.cache weren't found at runtime. Fix by: - Setting PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers (fixed, HOME-independent) - Using system-wide git config for safe.directory (works with any HOME) - Removing HOME env overrides from all workflow container configs Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 14 ++++++++------ .github/workflows/build.yml | 10 ---------- .github/workflows/canary.yml | 2 -- .github/workflows/flaky-test-detector.yml | 2 -- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index c6ac02ccdd14..833bf9497e47 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -20,10 +20,12 @@ RUN sudo curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | sud sudo npm install -g yarn@${YARN_VERSION} # Install Playwright browsers and their OS-level dependencies. -# `--with-deps` installs required system libraries (libglib, libatk, libnss, etc.). -RUN sudo npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps +# Use a fixed path so browsers are found regardless of HOME at runtime +# (GHA sets HOME=/github/home inside containers, not /home/runner). +ENV PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers +RUN sudo mkdir -p /opt/pw-browsers && \ + sudo npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps -# Mark GitHub Actions workspace as safe for git. -# The container may run with a different workspace owner, -# causing "dubious ownership" errors in git operations (e.g. rollup build). -RUN git config --global --add safe.directory '*' +# Mark GitHub Actions workspace as safe for git (system-wide config so it +# works regardless of HOME, which GHA overrides to /github/home). +RUN sudo git config --system --add safe.directory '*' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3de0589d15da..7ea0c14c74e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -505,8 +505,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 25 strategy: fail-fast: false @@ -611,8 +609,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 15 strategy: fail-fast: false @@ -833,8 +829,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 15 strategy: fail-fast: false @@ -939,8 +933,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1066,8 +1058,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 324137fe8fbb..3f43d9806284 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -78,8 +78,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 34f136844eb6..c055f2a692c9 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -46,8 +46,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host - env: - HOME: /home/runner timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From 828c099b6c3df7c92ee430b8838363a551aaff54 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 13:07:16 +0200 Subject: [PATCH 24/46] fix(ci): Run Playwright containers as root for Docker socket access E2E tests need Docker-in-Docker (Verdaccio registry). The actions-runner base image runs as non-root 'runner' user which cannot access the Docker socket mounted from the host. Run as root to fix permissions. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 10 +++++----- .github/workflows/canary.yml | 2 +- .github/workflows/flaky-test-detector.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ea0c14c74e5..2116bd9479f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -504,7 +504,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 25 strategy: fail-fast: false @@ -608,7 +608,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 15 strategy: fail-fast: false @@ -828,7 +828,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 15 strategy: fail-fast: false @@ -932,7 +932,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1057,7 +1057,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 3f43d9806284..63aee55ee523 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -77,7 +77,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index c055f2a692c9..4fc2498c25a0 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,7 +45,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host + options: --ipc=host --user root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From f9ecb94b6fa63eb4bad3ffe330ac43b6398da14e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 13:22:11 +0200 Subject: [PATCH 25/46] fix(ci): Remove enableCrossOsArchive to fix cache version mismatch Both host (ubuntu-24.04) and container (actions-runner, also Ubuntu 24.04) are the same OS, so enableCrossOsArchive is not needed. Removing it fixes cache misses caused by version hash differences between caches saved without the flag and restores attempted with it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-dependencies/action.yml | 1 - .github/actions/restore-cache/action.yml | 1 - .github/workflows/build.yml | 3 --- .github/workflows/canary.yml | 2 -- 4 files changed, 7 deletions(-) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 88bd96548b24..a862cd355af2 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -20,7 +20,6 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} - enableCrossOsArchive: true - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 08fb18f94f37..1d5126fbe952 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -15,7 +15,6 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ inputs.dependency_cache_key }} - enableCrossOsArchive: true - name: Restore build artifacts uses: actions/download-artifact@v7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2116bd9479f2..fa58a1708aba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -902,7 +902,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - enableCrossOsArchive: true - name: Determine which E2E test applications should be run id: matrix @@ -983,7 +982,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' @@ -1095,7 +1093,6 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} - enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 63aee55ee523..c598ed30ec4d 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -59,7 +59,6 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} - enableCrossOsArchive: true - name: Install dependencies run: yarn install - name: Build packages @@ -162,7 +161,6 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} - enableCrossOsArchive: true - name: Validate Verdaccio run: yarn test:validate From c5b1b0d1b214fdcbca807ca151f503bb4ab0cf22 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 13:24:13 +0200 Subject: [PATCH 26/46] fix(ci): Bust dependency cache and re-add enableCrossOsArchive Add v2 prefix to dependency cache key to bust stale caches that were saved without enableCrossOsArchive. Re-add the flag to all cache steps so new caches are saved in cross-OS format from the start. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/install-dependencies/action.yml | 1 + .github/actions/restore-cache/action.yml | 1 + .github/workflows/build.yml | 3 +++ .github/workflows/canary.yml | 2 ++ scripts/dependency-hash-key.js | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index a862cd355af2..88bd96548b24 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -20,6 +20,7 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} + enableCrossOsArchive: true - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 1d5126fbe952..08fb18f94f37 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -15,6 +15,7 @@ runs: with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ inputs.dependency_cache_key }} + enableCrossOsArchive: true - name: Restore build artifacts uses: actions/download-artifact@v7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa58a1708aba..2116bd9479f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -902,6 +902,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Determine which E2E test applications should be run id: matrix @@ -982,6 +983,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' @@ -1093,6 +1095,7 @@ jobs: with: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + enableCrossOsArchive: true - name: Build tarballs if not cached if: steps.restore-tarball-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index c598ed30ec4d..63aee55ee523 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -59,6 +59,7 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + enableCrossOsArchive: true - name: Install dependencies run: yarn install - name: Build packages @@ -161,6 +162,7 @@ jobs: with: path: ${{ env.CACHED_BUILD_PATHS }} key: canary-${{ env.HEAD_COMMIT }} + enableCrossOsArchive: true - name: Validate Verdaccio run: yarn test:validate diff --git a/scripts/dependency-hash-key.js b/scripts/dependency-hash-key.js index 55e38e4a385e..b04a85083e8a 100644 --- a/scripts/dependency-hash-key.js +++ b/scripts/dependency-hash-key.js @@ -36,7 +36,7 @@ function outputDependencyCacheKey() { // We log the output in a way that the GitHub Actions can append it to the output // We prefix it with `dependencies-` so it is easier to identify in the logs // eslint-disable-next-line no-console - console.log(`hash=dependencies-${hash}`); + console.log(`hash=v2-dependencies-${hash}`); } function getNormalizedDependencies(packageJson, workspacePackageNames) { From 4a79425d770895ff011f5e36b4998729b9a1524e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 13:45:55 +0200 Subject: [PATCH 27/46] fix(ci): Pass PLAYWRIGHT_BROWSERS_PATH through sudo sudo resets environment variables by default, so the ENV set in the Dockerfile wasn't visible to the npx playwright install command. Explicitly pass the variable so browsers are installed to /opt/pw-browsers. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 833bf9497e47..c637a3d4d138 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -24,7 +24,7 @@ RUN sudo curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | sud # (GHA sets HOME=/github/home inside containers, not /home/runner). ENV PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers RUN sudo mkdir -p /opt/pw-browsers && \ - sudo npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps + sudo PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers npx playwright@${PLAYWRIGHT_VERSION} install chromium webkit firefox --with-deps # Mark GitHub Actions workspace as safe for git (system-wide config so it # works regardless of HOME, which GHA overrides to /github/home). From 7daf56f774122c1e365212c26f6358fce331535a Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 14:13:36 +0200 Subject: [PATCH 28/46] fix(ci): Set HOME=/root for containers to fix Firefox launch Firefox refuses to run as root when HOME points to a directory owned by a different user. GHA sets HOME=/github/home (owned by runner) but we run as --user root. Setting HOME=/root fixes the ownership mismatch. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 10 ++++++++++ .github/workflows/canary.yml | 2 ++ .github/workflows/flaky-test-detector.yml | 2 ++ 3 files changed, 14 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2116bd9479f2..8c7648f093ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -505,6 +505,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 25 strategy: fail-fast: false @@ -609,6 +611,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 15 strategy: fail-fast: false @@ -829,6 +833,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 15 strategy: fail-fast: false @@ -933,6 +939,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1058,6 +1066,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 63aee55ee523..38a6008a4150 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -78,6 +78,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 4fc2498c25a0..ca89f638e580 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -46,6 +46,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} options: --ipc=host --user root + env: + HOME: /root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From c6f71797be8051bf77e35713319a7f7b4a885b1e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 14:21:49 +0200 Subject: [PATCH 29/46] fix(ci): Use relative paths for cache to fix host/container mismatch github.workspace resolves to different absolute paths on the host (/home/runner/work/...) vs inside a container (/__w/...), causing cache version hash mismatches. Use relative paths instead, which actions/cache resolves from the working directory. Bust cache key to v3 since the path format changed. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 26 +++++++++++--------------- .github/workflows/canary.yml | 12 ++++++------ scripts/dependency-hash-key.js | 2 +- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8c7648f093ea..2130893e4ba0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,25 +28,21 @@ concurrency: env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} - # WARNING: this disables cross os caching as ~ and - # github.workspace evaluate to differents paths CACHED_DEPENDENCY_PATHS: | - ${{ github.workspace }}/node_modules - ${{ github.workspace }}/packages/*/node_modules - ${{ github.workspace }}/dev-packages/*/node_modules + node_modules + packages/*/node_modules + dev-packages/*/node_modules ~/.cache/mongodb-binaries/ # DEPENDENCY_CACHE_KEY: can't be set here because we don't have access to yarn.lock - # WARNING: this disables cross os caching as ~ and - # github.workspace evaluate to differents paths # packages/utils/cjs and packages/utils/esm: Symlinks to the folders inside of `build`, needed for tests CACHED_BUILD_PATHS: | - ${{ github.workspace }}/dev-packages/*/build - ${{ github.workspace }}/packages/*/build - ${{ github.workspace }}/packages/*/lib - ${{ github.workspace }}/packages/ember/*.d.ts - ${{ github.workspace }}/packages/gatsby/*.d.ts + dev-packages/*/build + packages/*/build + packages/*/lib + packages/ember/*.d.ts + packages/gatsby/*.d.ts BUILD_CACHE_TARBALL_KEY: tarball-${{ github.event.inputs.commit || github.sha }} @@ -906,7 +902,7 @@ jobs: - name: Stores tarballs in cache uses: actions/cache/save@v5 with: - path: ${{ github.workspace }}/packages/*/*.tgz + path: packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} enableCrossOsArchive: true @@ -989,7 +985,7 @@ jobs: uses: actions/cache/restore@v5 id: restore-tarball-cache with: - path: ${{ github.workspace }}/packages/*/*.tgz + path: packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} enableCrossOsArchive: true @@ -1103,7 +1099,7 @@ jobs: uses: actions/cache/restore@v5 id: restore-tarball-cache with: - path: ${{ github.workspace }}/packages/*/*.tgz + path: packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} enableCrossOsArchive: true diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 38a6008a4150..e98936ad9cf7 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -13,12 +13,12 @@ env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} CACHED_BUILD_PATHS: | - ${{ github.workspace }}/packages/*/*.tgz - ${{ github.workspace }}/node_modules - ${{ github.workspace }}/packages/*/node_modules - ${{ github.workspace }}/dev-packages/*/node_modules - ${{ github.workspace }}/dev-packages/*/build - ${{ github.workspace }}/packages/*/build + packages/*/*.tgz + node_modules + packages/*/node_modules + dev-packages/*/node_modules + dev-packages/*/build + packages/*/build permissions: contents: read diff --git a/scripts/dependency-hash-key.js b/scripts/dependency-hash-key.js index b04a85083e8a..7fddbc101003 100644 --- a/scripts/dependency-hash-key.js +++ b/scripts/dependency-hash-key.js @@ -36,7 +36,7 @@ function outputDependencyCacheKey() { // We log the output in a way that the GitHub Actions can append it to the output // We prefix it with `dependencies-` so it is easier to identify in the logs // eslint-disable-next-line no-console - console.log(`hash=v2-dependencies-${hash}`); + console.log(`hash=v3-dependencies-${hash}`); } function getNormalizedDependencies(packageJson, workspacePackageNames) { From f74a65d4ea35513b4e14cbca49a320c57cbd2760 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 14:23:39 +0200 Subject: [PATCH 30/46] add name to job --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2130893e4ba0..0be3483733c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,6 +61,7 @@ env: jobs: job_get_metadata: + name: Get Metadata uses: ./.github/workflows/ci-metadata.yml with: head_commit: ${{ github.event.inputs.commit || github.sha }} From ce7f5f2c0a19d32012d42b324917085227834fd8 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 14:35:19 +0200 Subject: [PATCH 31/46] remove unneeded comment --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0be3483733c3..85406e7b1b3f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,6 @@ env: # DEPENDENCY_CACHE_KEY: can't be set here because we don't have access to yarn.lock - # packages/utils/cjs and packages/utils/esm: Symlinks to the folders inside of `build`, needed for tests CACHED_BUILD_PATHS: | dev-packages/*/build packages/*/build From 32fcb9974a2d20d4490c2b27cc58545274ebd54c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 14:36:01 +0200 Subject: [PATCH 32/46] fix(ci): Set HOME=/root via docker -e flag to override GHA default GHA hard-codes HOME=/github/home when creating the container, which overrides our container.env setting. Using -e HOME=/root in the container options flag takes precedence over GHA's injected value. Firefox requires HOME to be owned by the current user (root). Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 20 +++++--------------- .github/workflows/canary.yml | 4 +--- .github/workflows/flaky-test-detector.yml | 4 +--- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85406e7b1b3f..2c0423f04c0b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -500,9 +500,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 25 strategy: fail-fast: false @@ -606,9 +604,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 15 strategy: fail-fast: false @@ -828,9 +824,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 15 strategy: fail-fast: false @@ -934,9 +928,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1061,9 +1053,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index e98936ad9cf7..c7a8041afba5 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -77,9 +77,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index ca89f638e580..377abd55c4bb 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,9 +45,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root - env: - HOME: /root + options: --ipc=host --user root -e HOME=/root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From 20aa5066d78abb91d5b9718f9ecb6d2b0f244fd4 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 15:01:22 +0200 Subject: [PATCH 33/46] fix(ci): Use workspace-relative path for E2E temp directory runner.temp resolves to the host path (/home/runner/work/_temp) but inside a container the equivalent path is /__w/_temp. The copy step writes to the host path which doesn't exist inside the container. Use a workspace-relative path (dev-packages/tmp-test-application) instead, which is inside the mounted workspace volume and accessible from both host and container. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 12 ++++++------ .github/workflows/canary.yml | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c0423f04c0b..12c059751e49 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -994,18 +994,18 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} env: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} env: @@ -1106,16 +1106,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index c7a8041afba5..dc5ebe8a8d13 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -173,16 +173,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: yarn ${{ matrix.build-command }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 15 run: yarn test:assert From 7235bbd572b1ad89fce71d5a5305f715df5c7a80 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 15:05:10 +0200 Subject: [PATCH 34/46] fix(ci): Set HOME=/root via GITHUB_ENV and fix E2E temp path GHA strips -e flags from container options, so HOME can't be overridden that way. Instead, add a 'Fix HOME for root user' step that writes HOME=/root to GITHUB_ENV at the start of every container job. Firefox requires HOME to be owned by the current user (root), and GHA sets HOME=/github/home (owned by runner). Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/docker/playwright.Dockerfile | 6 ++++++ .github/workflows/build.yml | 20 +++++++++++++++----- .github/workflows/canary.yml | 4 +++- .github/workflows/flaky-test-detector.yml | 4 +++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index c637a3d4d138..578c7ddec5ae 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -29,3 +29,9 @@ RUN sudo mkdir -p /opt/pw-browsers && \ # Mark GitHub Actions workspace as safe for git (system-wide config so it # works regardless of HOME, which GHA overrides to /github/home). RUN sudo git config --system --add safe.directory '*' + +# Ensure /root exists and is owned by root. When running as --user root, +# Firefox requires HOME to be owned by the current user. GHA sets +# HOME=/github/home (owned by runner), but we can't override it. +# The workflow sets HOME=/root via a step, and this ensures /root is ready. +RUN mkdir -p /root diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 12c059751e49..dab8d56c9575 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -500,7 +500,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 25 strategy: fail-fast: false @@ -550,6 +550,8 @@ jobs: project: 'chromium' steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -604,7 +606,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 15 strategy: fail-fast: false @@ -619,6 +621,8 @@ jobs: - loader_tracing_replay steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -824,13 +828,15 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 15 strategy: fail-fast: false matrix: node: [18, 20, 22, 24] steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -928,7 +934,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -943,6 +949,8 @@ jobs: fail-fast: false matrix: ${{ fromJson(needs.job_e2e_prepare.outputs.matrix) }} steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -1053,7 +1061,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} @@ -1069,6 +1077,8 @@ jobs: matrix: ${{ fromJson(needs.job_e2e_prepare.outputs.matrix-optional) }} steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index dc5ebe8a8d13..b85df89c158a 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -77,7 +77,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -145,6 +145,8 @@ jobs: label: 'nestjs-microservices (latest)' steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit uses: actions/checkout@v6 with: diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 377abd55c4bb..917f144c28ea 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,12 +45,14 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root -e HOME=/root + options: --ipc=host --user root timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop if: ${{ github.base_ref != 'master' && github.ref != 'refs/heads/master' }} steps: + - name: Fix HOME for root user + run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current branch uses: actions/checkout@v6 - name: Set up Node From befd626e067cc1b232d253b74c99bc7ddccde70d Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 15:10:01 +0200 Subject: [PATCH 35/46] fix(ci): Limit HOME=/root fix to Firefox-capable job only Only the browser Playwright tests job runs Firefox (via matrix project). All other container jobs (loader tests, Remix, E2E, canary, flaky detector) only run chromium and don't need the HOME override. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 8 -------- .github/workflows/canary.yml | 2 -- .github/workflows/flaky-test-detector.yml | 2 -- 3 files changed, 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dab8d56c9575..743c437abb9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -621,8 +621,6 @@ jobs: - loader_tracing_replay steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -835,8 +833,6 @@ jobs: matrix: node: [18, 20, 22, 24] steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -949,8 +945,6 @@ jobs: fail-fast: false matrix: ${{ fromJson(needs.job_e2e_prepare.outputs.matrix) }} steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: @@ -1077,8 +1071,6 @@ jobs: matrix: ${{ fromJson(needs.job_e2e_prepare.outputs.matrix-optional) }} steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v6 with: diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index b85df89c158a..ccf06002671f 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -145,8 +145,6 @@ jobs: label: 'nestjs-microservices (latest)' steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current commit uses: actions/checkout@v6 with: diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 917f144c28ea..4fc2498c25a0 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -51,8 +51,6 @@ jobs: # Also skip if PR is from master -> develop if: ${{ github.base_ref != 'master' && github.ref != 'refs/heads/master' }} steps: - - name: Fix HOME for root user - run: echo "HOME=/root" >> $GITHUB_ENV - name: Check out current branch uses: actions/checkout@v6 - name: Set up Node From bfb6d17cac116453b35d8b346bbac6880687e369 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 15:34:30 +0200 Subject: [PATCH 36/46] =?UTF-8?q?fix(ci):=20Remove=20container=20from=20E2?= =?UTF-8?q?E=20jobs=20=E2=80=94=20they=20need=20host=20Docker=20access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit E2E tests use Docker-in-Docker (Verdaccio registry) which doesn't work inside a GHA container due to network isolation. On develop these jobs run directly on the host. Only browser Playwright, loader, and Remix tests need the Playwright container image. Revert registrySetup.ts path conversion and temp directory changes for E2E jobs since they now run on the host again. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 32 +++++++++----------------------- .github/workflows/canary.yml | 6 +++--- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 743c437abb9e..5a463fac0361 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -922,15 +922,8 @@ jobs: # See: https://github.com/actions/runner/issues/2205 if: always() && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix != '{"include":[]}' - && needs.job_playwright_image.result == 'success' - needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] + needs: [job_get_metadata, job_build, job_e2e_prepare] runs-on: ubuntu-24.04 - container: - image: ${{ needs.job_playwright_image.outputs.image }} - credentials: - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -996,18 +989,18 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} env: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Run E2E test - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} env: @@ -1046,16 +1039,9 @@ jobs: if: always() && needs.job_get_metadata.outputs.is_release != 'true' && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix-optional != '{"include":[]}' && (github.event_name != 'pull_request' || - github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' && - needs.job_playwright_image.result == 'success' - needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] + github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' + needs: [job_get_metadata, job_build, job_e2e_prepare] runs-on: ubuntu-24.04 - container: - image: ${{ needs.job_playwright_image.outputs.image }} - credentials: - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} @@ -1108,16 +1094,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} - name: Run E2E test - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index ccf06002671f..95ff0b4be139 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -173,16 +173,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 7 run: yarn ${{ matrix.build-command }} - name: Run E2E test - working-directory: dev-packages/tmp-test-application + working-directory: ${{ runner.temp }}/test-application timeout-minutes: 15 run: yarn test:assert From 52fea71bdeab27ace24e808e1bf3663e717b6a17 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Wed, 15 Apr 2026 15:38:18 +0200 Subject: [PATCH 37/46] fix(ci): Restore container for E2E jobs after merging publish fix PR #20329 removed Docker-based package publishing, so E2E jobs can now run in the Playwright container without Docker-in-Docker issues. Re-add the container block to E2E jobs and use workspace-relative temp paths (runner.temp doesn't work inside containers). Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 38 ++++++++++++++++++++++++------------ .github/workflows/canary.yml | 6 +++--- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a463fac0361..ca3f5156b0ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -922,8 +922,15 @@ jobs: # See: https://github.com/actions/runner/issues/2205 if: always() && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix != '{"include":[]}' - needs: [job_get_metadata, job_build, job_e2e_prepare] + && needs.job_playwright_image.result == 'success' + needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 + container: + image: ${{ needs.job_playwright_image.outputs.image }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host --user root timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -989,18 +996,18 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} env: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} env: @@ -1011,7 +1018,7 @@ jobs: if: failure() with: name: playwright-traces-job_e2e_playwright_tests-${{ matrix.test-application}} - path: ${{ runner.temp }}/test-application/test-results + path: dev-packages/tmp-test-application/test-results overwrite: true retention-days: 7 @@ -1025,7 +1032,7 @@ jobs: if: failure() with: name: E2E Test Dump (${{ matrix.label || matrix.test-application }}) - path: ${{ runner.temp }}/test-application/event-dumps + path: dev-packages/tmp-test-application/event-dumps overwrite: true retention-days: 7 if-no-files-found: ignore @@ -1039,9 +1046,16 @@ jobs: if: always() && needs.job_get_metadata.outputs.is_release != 'true' && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix-optional != '{"include":[]}' && (github.event_name != 'pull_request' || - github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' - needs: [job_get_metadata, job_build, job_e2e_prepare] + github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' && + needs.job_playwright_image.result == 'success' + needs: [job_get_metadata, job_build, job_e2e_prepare, job_playwright_image] runs-on: ubuntu-24.04 + container: + image: ${{ needs.job_playwright_image.outputs.image }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + options: --ipc=host --user root timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} @@ -1094,16 +1108,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} @@ -1117,7 +1131,7 @@ jobs: if: failure() with: name: E2E Test Dump (${{ matrix.label || matrix.test-application }}) - path: ${{ runner.temp }}/test-application/event-dumps + path: dev-packages/tmp-test-application/event-dumps overwrite: true retention-days: 7 if-no-files-found: ignore diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 95ff0b4be139..ccf06002671f 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -173,16 +173,16 @@ jobs: working-directory: dev-packages/e2e-tests - name: Copy to temp - run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application + run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ../tmp-test-application working-directory: dev-packages/e2e-tests - name: Build E2E app - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 7 run: yarn ${{ matrix.build-command }} - name: Run E2E test - working-directory: ${{ runner.temp }}/test-application + working-directory: dev-packages/tmp-test-application timeout-minutes: 15 run: yarn test:assert From 18bfa031bdb928339a3488cbacae383bf305a8f7 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Thu, 16 Apr 2026 14:11:50 +0200 Subject: [PATCH 38/46] bump deps --- yarn.lock | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yarn.lock b/yarn.lock index cc45a89c5703..c0712a95bfb7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12561,6 +12561,13 @@ brace-expansion@^5.0.2, brace-expansion@^5.0.5: dependencies: balanced-match "^4.0.2" +brace-expansion@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" + integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== + dependencies: + balanced-match "^4.0.2" + braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" From 0ee7af2f9e703cd571ffdb8c0daa86664ddcc37b Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Thu, 16 Apr 2026 17:31:14 +0200 Subject: [PATCH 39/46] fix(ci): Enable IPv6 in Playwright containers for loopback networking Docker containers don't have IPv6 enabled on the loopback interface by default. Node.js fetch resolves localhost to ::1 (IPv6) first, which fails when IPv6 is disabled. This breaks E2E tests that do server-side self-referencing fetch (e.g., Astro SSR fetching its own API endpoints). Enable IPv6 via --sysctl net.ipv6.conf.all.disable_ipv6=0 on all container jobs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 10 +++++----- .github/workflows/canary.yml | 2 +- .github/workflows/flaky-test-detector.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca3f5156b0ff..f0efe9e3faf6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -500,7 +500,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 25 strategy: fail-fast: false @@ -606,7 +606,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 15 strategy: fail-fast: false @@ -826,7 +826,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 15 strategy: fail-fast: false @@ -930,7 +930,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1055,7 +1055,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index ccf06002671f..baad599692ce 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -77,7 +77,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 4fc2498c25a0..3ce7c6f29368 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -45,7 +45,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop From 6a28edaab016146f24af10401746ea58d2034922 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 09:23:11 +0200 Subject: [PATCH 40/46] dedupe deps --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index c0712a95bfb7..c7b8ed9f8eaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12554,7 +12554,7 @@ brace-expansion@^2.0.1, brace-expansion@^2.0.2: dependencies: balanced-match "^1.0.0" -brace-expansion@^5.0.2, brace-expansion@^5.0.5: +brace-expansion@^5.0.2: version "5.0.5" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== From b033bb6340233a472c6306f8c013b3b019410bd2 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 09:49:43 +0200 Subject: [PATCH 41/46] one fix --- dev-packages/e2e-tests/test-applications/node-hapi/src/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js b/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js index 8b68e8412aba..73f0b2e52db3 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js +++ b/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js @@ -14,7 +14,8 @@ const Boom = require('@hapi/boom'); const server = Hapi.server({ port: 3030, - host: 'localhost', + // Avoid IPv6-only ::1 bind for `localhost` on Linux CI (fetch uses 127.0.0.1). + host: '0.0.0.0', }); const init = async () => { From 4a4f98c7c83563a1e7c9e0b357a078caa8d066f6 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 09:53:41 +0200 Subject: [PATCH 42/46] install java --- .github/docker/playwright.Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index 578c7ddec5ae..d4adeeb234a2 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -9,10 +9,11 @@ ARG YARN_VERSION # Prevent interactive prompts during package installation ENV DEBIAN_FRONTEND=noninteractive -# Install zstd (required by actions/cache for compression) and Node.js + Yarn -# at the versions pinned in the repo's package.json. +# Install zstd (required by actions/cache for compression), a JRE for Firebase +# emulators (Firestore, etc. spawn `java -version`), and Node.js + Yarn at the +# versions pinned in the repo's package.json. RUN sudo apt-get update && \ - sudo apt-get install -y --no-install-recommends zstd && \ + sudo apt-get install -y --no-install-recommends zstd openjdk-17-jre-headless && \ sudo rm -rf /var/lib/apt/lists/* RUN sudo curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | sudo bash - && \ sudo apt-get install -y --no-install-recommends nodejs && \ From 7812f13ce71f184fe8ecab8f4bddaa41f75cb86c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 09:55:29 +0200 Subject: [PATCH 43/46] avoid playwright install on remix-integration tests --- packages/remix/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/remix/package.json b/packages/remix/package.json index 6241c3ec11d7..74dd7c774d98 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -110,7 +110,7 @@ "test:integration:ci": "run-s test:integration:clean test:integration:prepare test:integration:client:ci test:integration:server", "test:integration:prepare": "(cd test/integration && yarn install)", "test:integration:clean": "(cd test/integration && rimraf .cache node_modules build)", - "test:integration:client": "yarn playwright install-deps && yarn playwright test test/integration/test/client/ --project='chromium'", + "test:integration:client": "yarn playwright test test/integration/test/client/ --project='chromium'", "test:integration:client:ci": "yarn test:integration:client", "test:integration:server": "export NODE_OPTIONS='--stack-trace-limit=25' && vitest run", "test:unit": "vitest run --config vitest.config.unit.ts", From e7eab039f6ac02480e058b398b541210b644f2b4 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 10:01:00 +0200 Subject: [PATCH 44/46] fix some tests --- .../suites/public-api/startSpan-streamed/test.ts | 2 +- .../test-applications/nextjs-16/tests/middleware.test.ts | 3 ++- .../tracing/http-client-spans/fetch-strip-query/test.ts | 2 +- .../tracing/http-client-spans/http-strip-query/test.ts | 2 +- .../suites/tracing/httpIntegration/test.ts | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts index 090142714d5b..ed9a3d949879 100644 --- a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts @@ -221,7 +221,7 @@ it('sends a streamed span envelope with correct spans for a manually started spa }, 'http.request.header.cf_connecting_ip': { type: 'string', - value: '::1', + value: expect.stringMatching(/^(127\.0\.0\.1|::1)$/), }, 'http.request.header.host': { type: 'string', diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/middleware.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/middleware.test.ts index 0bb957bbc466..aae461371773 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/middleware.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/middleware.test.ts @@ -104,7 +104,8 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru 'http.request.method': 'GET', 'http.request.method_original': 'GET', 'http.response.status_code': 200, - 'network.peer.address': '::1', + // localhost resolves to IPv4 or IPv6 depending on OS / container + 'network.peer.address': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'network.peer.port': 3030, 'otel.kind': 'CLIENT', 'sentry.op': 'http.client', diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts index 2020cfdd09b0..487574b2d6f9 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts @@ -29,7 +29,7 @@ test('strips and handles query params in spans of outgoing fetch requests', asyn 'http.request.method': 'GET', 'http.request.method_original': 'GET', 'http.response.status_code': 200, - 'network.peer.address': '::1', + 'network.peer.address': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'network.peer.port': expect.any(Number), 'otel.kind': 'CLIENT', 'server.port': expect.any(Number), diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts index 94ccd6c9702a..11a27a411d8a 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts @@ -31,7 +31,7 @@ test('strips and handles query params in spans of outgoing http requests', async 'http.response_content_length_uncompressed': 0, 'http.status_code': 200, 'http.status_text': 'OK', - 'net.peer.ip': '::1', + 'net.peer.ip': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'net.peer.name': 'localhost', 'net.peer.port': expect.any(Number), 'net.transport': 'ip_tcp', diff --git a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts index ac0ac3780a38..7d48487d1f60 100644 --- a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts @@ -118,10 +118,10 @@ describe('httpIntegration', () => { 'http.target': '/test?a=1&b=2', 'http.url': `http://localhost:${port}/test?a=1&b=2`, 'http.user_agent': 'node', - 'net.host.ip': '::1', + 'net.host.ip': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'net.host.name': 'localhost', 'net.host.port': port, - 'net.peer.ip': '::1', + 'net.peer.ip': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'net.peer.port': expect.any(Number), 'net.transport': 'ip_tcp', 'otel.kind': 'SERVER', @@ -160,10 +160,10 @@ describe('httpIntegration', () => { 'http.target': '/test?a=1&b=2', 'http.url': `http://localhost:${port}/test?a=1&b=2`, 'http.user_agent': 'node', - 'net.host.ip': '::1', + 'net.host.ip': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'net.host.name': 'localhost', 'net.host.port': port, - 'net.peer.ip': '::1', + 'net.peer.ip': expect.stringMatching(/^(127\.0\.0\.1|::1)$/), 'net.peer.port': expect.any(Number), 'net.transport': 'ip_tcp', 'otel.kind': 'SERVER', From 8e7790c994cc983ccf6fd8fbd68154f547641771 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 11:15:27 +0200 Subject: [PATCH 45/46] fix ip for cloudflare stuff ? --- .../e2e-tests/test-applications/astro-5-cf-workers/package.json | 2 +- .../e2e-tests/test-applications/astro-6-cf-workers/package.json | 2 +- .../e2e-tests/test-applications/cloudflare-hono/package.json | 2 +- .../test-applications/cloudflare-local-workers/package.json | 2 +- .../e2e-tests/test-applications/cloudflare-mcp/package.json | 2 +- .../e2e-tests/test-applications/cloudflare-workers/package.json | 2 +- .../test-applications/cloudflare-workersentrypoint/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/package.json b/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/package.json index 400ab6144248..24ff5ca9762e 100644 --- a/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/package.json +++ b/dev-packages/e2e-tests/test-applications/astro-5-cf-workers/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "astro dev", "build": "astro build", - "preview": "wrangler dev --port 3030", + "preview": "wrangler dev --ip 0.0.0.0 --port 3030", "test:build": "pnpm install && pnpm build", "test:assert": "TEST_ENV=production playwright test" }, diff --git a/dev-packages/e2e-tests/test-applications/astro-6-cf-workers/package.json b/dev-packages/e2e-tests/test-applications/astro-6-cf-workers/package.json index 2e7cfa8e62dd..86bba3c1cdb3 100644 --- a/dev-packages/e2e-tests/test-applications/astro-6-cf-workers/package.json +++ b/dev-packages/e2e-tests/test-applications/astro-6-cf-workers/package.json @@ -7,7 +7,7 @@ "build": "astro build", "preview": "astro preview", "astro": "astro", - "start": "wrangler dev --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --port 3030", + "start": "wrangler dev --ip 0.0.0.0 --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --port 3030", "test:build": "pnpm install && pnpm build", "test:assert": "TEST_ENV=production playwright test", "generate-types": "wrangler types" diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json index 3d536e6fbabe..ce61fc79ed09 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json @@ -1,7 +1,7 @@ { "name": "cloudflare-hono", "scripts": { - "dev": "wrangler dev", + "dev": "wrangler dev --ip 0.0.0.0", "build": "wrangler deploy --dry-run --var E2E_TEST_DSN=$E2E_TEST_DSN", "test": "vitest", "typecheck": "tsc --noEmit", diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-local-workers/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-local-workers/package.json index 160b8a9cdc03..1c2a620c86b1 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-local-workers/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-local-workers/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "deploy": "wrangler deploy", - "dev": "wrangler dev --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", + "dev": "wrangler dev --ip 0.0.0.0 --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", "build": "wrangler deploy --dry-run", "test": "vitest --run", "typecheck": "tsc --noEmit", diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-mcp/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-mcp/package.json index 37b3352bdcfc..01b1a895a0e2 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-mcp/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-mcp/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "deploy": "wrangler deploy", - "dev": "wrangler dev --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", + "dev": "wrangler dev --ip 0.0.0.0 --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", "build": "wrangler deploy --dry-run", "test": "vitest --run", "typecheck": "tsc --noEmit", diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-workers/package.json index 344337612165..3c526d5c9990 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "deploy": "wrangler deploy", - "dev": "wrangler dev --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", + "dev": "wrangler dev --ip 0.0.0.0 --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", "build": "wrangler deploy --dry-run", "test": "vitest --run", "typecheck": "tsc --noEmit", diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workersentrypoint/package.json b/dev-packages/e2e-tests/test-applications/cloudflare-workersentrypoint/package.json index a0a1b020df86..5b6d76ae0270 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workersentrypoint/package.json +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workersentrypoint/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "deploy": "wrangler deploy", - "dev": "wrangler dev --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", + "dev": "wrangler dev --ip 0.0.0.0 --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')", "build": "wrangler deploy --dry-run", "test": "vitest --run", "typecheck": "tsc --noEmit", From af4290996c43187c49bcb19fe1d82496436c6402 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Fri, 17 Apr 2026 11:41:35 +0200 Subject: [PATCH 46/46] some more test fixes --- .github/docker/playwright.Dockerfile | 12 ++++++++++++ .github/workflows/build.yml | 8 ++++++-- .github/workflows/canary.yml | 2 +- .../hydrogen-react-router-7/wrangler.toml | 3 +++ .../nestjs-bullmq/src/app.module.ts | 3 ++- .../nextjs-16-cf-workers/playwright.config.mjs | 3 ++- .../nextjs-16-cf-workers/wrangler.jsonc | 4 ++++ .../test-applications/remix-hydrogen/wrangler.toml | 6 ++++++ .../sveltekit-cloudflare-pages/package.json | 2 +- 9 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/remix-hydrogen/wrangler.toml diff --git a/.github/docker/playwright.Dockerfile b/.github/docker/playwright.Dockerfile index d4adeeb234a2..8fbcaa2ec9f9 100644 --- a/.github/docker/playwright.Dockerfile +++ b/.github/docker/playwright.Dockerfile @@ -36,3 +36,15 @@ RUN sudo git config --system --add safe.directory '*' # HOME=/github/home (owned by runner), but we can't override it. # The workflow sets HOME=/root via a step, and this ensures /root is ready. RUN mkdir -p /root + +# Docker CLI + Compose v2 for E2E apps that run `docker compose` against the +# host daemon (workflows mount /var/run/docker.sock). Image is built amd64 on GHA. +ARG DOCKER_VERSION=27.4.1 +ARG DOCKER_COMPOSE_VERSION=2.32.1 +RUN curl -fsSL "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" | sudo tar -xz -C /tmp && \ + sudo mv /tmp/docker/docker /usr/local/bin/docker && \ + sudo rm -rf /tmp/docker && \ + sudo mkdir -p /usr/local/lib/docker/cli-plugins && \ + sudo curl -fsSL "https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64" \ + -o /usr/local/lib/docker/cli-plugins/docker-compose && \ + sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0efe9e3faf6..89e9b6dc7733 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -930,7 +930,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 -v /var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -1006,6 +1006,10 @@ jobs: env: SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} + - name: Point BullMQ at host Redis (Docker-out-of-Docker) + if: matrix.test-application == 'nestjs-bullmq' + run: echo "REDIS_HOST=host.docker.internal" >> "$GITHUB_ENV" + - name: Run E2E test working-directory: dev-packages/tmp-test-application timeout-minutes: 10 @@ -1055,7 +1059,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 -v /var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index baad599692ce..8e2125ba9698 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -77,7 +77,7 @@ jobs: credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 + options: --ipc=host --user root --sysctl net.ipv6.conf.all.disable_ipv6=0 -v /var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/dev-packages/e2e-tests/test-applications/hydrogen-react-router-7/wrangler.toml b/dev-packages/e2e-tests/test-applications/hydrogen-react-router-7/wrangler.toml index b2de8e7d1321..81f734464407 100644 --- a/dev-packages/e2e-tests/test-applications/hydrogen-react-router-7/wrangler.toml +++ b/dev-packages/e2e-tests/test-applications/hydrogen-react-router-7/wrangler.toml @@ -1,3 +1,6 @@ name = "hydrogen-react-router-7" main = "server.ts" compatibility_flags = ["transformstream_enable_standard_constructor"] + +[dev] +ip = "0.0.0.0" diff --git a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/app.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/app.module.ts index be5fd107e4cb..9dfb0417025e 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/app.module.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/app.module.ts @@ -9,7 +9,8 @@ import { TestProcessor } from './jobs/test.processor'; imports: [ SentryModule.forRoot(), BullModule.forRoot({ - connection: { host: 'localhost', port: 6379 }, + // CI: Redis runs on the GHA host via docker compose; REDIS_HOST is set in the workflow. + connection: { host: process.env.REDIS_HOST || 'localhost', port: 6379 }, }), BullModule.registerQueue({ name: 'test-queue' }), ], diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/playwright.config.mjs b/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/playwright.config.mjs index 0f15639161dd..3a35d4c3e8ba 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/playwright.config.mjs +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/playwright.config.mjs @@ -7,7 +7,8 @@ if (!testEnv) { const getStartCommand = () => { if (testEnv === 'production') { - return 'pnpm cf:preview --port 3030'; + // --ip: CI Playwright container; fetch uses 127.0.0.1 while default bind can be ::1-only. + return 'pnpm cf:preview --ip 0.0.0.0 --port 3030'; } throw new Error(`Unknown test env: ${testEnv}`); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/wrangler.jsonc b/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/wrangler.jsonc index 4bf131c387e9..2b5a1a6e82e2 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/wrangler.jsonc +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cf-workers/wrangler.jsonc @@ -32,6 +32,10 @@ "observability": { "enabled": true, }, + // Listen on IPv4 in CI (Playwright job container); avoids ::1-only bind vs fetch to 127.0.0.1. + "dev": { + "ip": "0.0.0.0", + }, /** * Smart Placement * Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement diff --git a/dev-packages/e2e-tests/test-applications/remix-hydrogen/wrangler.toml b/dev-packages/e2e-tests/test-applications/remix-hydrogen/wrangler.toml new file mode 100644 index 000000000000..b01f7ccf2b2d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/remix-hydrogen/wrangler.toml @@ -0,0 +1,6 @@ +name = "remix-hydrogen-e2e" +main = "server.ts" +compatibility_flags = ["transformstream_enable_standard_constructor"] + +[dev] +ip = "0.0.0.0" diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json index e17a9b2bdabd..9f8c368720f8 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-cloudflare-pages/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite dev", "build": "vite build", - "preview": "wrangler pages dev ./.svelte-kit/cloudflare --port 4173", + "preview": "wrangler pages dev ./.svelte-kit/cloudflare --ip 0.0.0.0 --port 4173", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:e2e": "playwright test",