From a097b8c5e020f85d333ab22c282ab5ae768d6e48 Mon Sep 17 00:00:00 2001 From: Jeremy Hatfield Date: Tue, 18 Aug 2026 02:14:34 +0000 Subject: [PATCH 1/4] chore(ci): add timeout and retry to Playwright browser installs to prevent job-timeout hangs apt-get inside `playwright install --with-deps` can silently hang against a flaky Azure apt mirror with no timeout of its own, burning the full 60-minute job timeout and surfacing as a misleading cancelled run instead of a clear failure. Wrap all 10 Playwright browser install steps in nick-fields/retry (10min/attempt, 3 attempts, 15s backoff), matching the existing pattern already used in docker-build.yml. --- .github/workflows/e2e-tests-split.yml | 170 +++++++++++++++++--------- 1 file changed, 110 insertions(+), 60 deletions(-) diff --git a/.github/workflows/e2e-tests-split.yml b/.github/workflows/e2e-tests-split.yml index 3fb9611d6..29f1ce13e 100644 --- a/.github/workflows/e2e-tests-split.yml +++ b/.github/workflows/e2e-tests-split.yml @@ -324,12 +324,17 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium - run: | - echo "📦 Installing Chromium..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium..." + npx playwright install --with-deps chromium - name: Run Chromium Security Enforcement Tests run: | @@ -559,20 +564,30 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + npx playwright install --with-deps chromium - name: Install Playwright Firefox - run: | - echo "📦 Installing Firefox..." - npx playwright install --with-deps firefox - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Firefox..." + npx playwright install --with-deps firefox - name: Run Firefox Security Enforcement Tests run: | @@ -805,20 +820,30 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + npx playwright install --with-deps chromium - name: Install Playwright WebKit - run: | - echo "📦 Installing WebKit..." - npx playwright install --with-deps webkit - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing WebKit..." + npx playwright install --with-deps webkit - name: Run WebKit Security Enforcement Tests run: | @@ -1078,12 +1103,17 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium - run: | - echo "📦 Installing Chromium..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium..." + npx playwright install --with-deps chromium - name: Run Chromium Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | @@ -1316,20 +1346,30 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + npx playwright install --with-deps chromium - name: Install Playwright Firefox - run: | - echo "📦 Installing Firefox..." - npx playwright install --with-deps firefox - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Firefox..." + npx playwright install --with-deps firefox - name: Run Firefox Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | @@ -1562,20 +1602,30 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + npx playwright install --with-deps chromium - name: Install Playwright WebKit - run: | - echo "📦 Installing WebKit..." - npx playwright install --with-deps webkit - EXIT_CODE=$? - echo "✅ Install command completed (exit code: $EXIT_CODE)" - exit "$EXIT_CODE" + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 15 + retry_on: error + warning_on_retry: true + command: | + set -euo pipefail + echo "📦 Installing WebKit..." + npx playwright install --with-deps webkit - name: Run WebKit Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | From f98431a419911112ee0925705407d93dbd19b0f7 Mon Sep 17 00:00:00 2001 From: Jeremy Hatfield Date: Tue, 18 Aug 2026 02:49:14 +0000 Subject: [PATCH 2/4] fix(ci): replace nick-fields/retry with a bash timeout loop for Playwright installs nick-fields/retry's timeout handling calls process.kill() on the child process tree from its own Node process. `playwright install --with-deps` internally elevates part of that tree to root via sudo to run apt-get, so when the action's 10-minute timeout fires, the kill fails with EPERM (cross-UID kill) and throws unhandled instead of retrying. The step died on attempt 1 and never reached attempt 2 or 3. Replaced all 10 occurrences with a plain bash retry loop using coreutils `timeout`, which signals its own direct child and isn't subject to the EPERM bug class. Matches the existing bash retry-loop idiom already used in codecov-upload.yml and quality-checks.yml. --- .github/workflows/e2e-tests-split.yml | 240 ++++++++++++++------------ 1 file changed, 130 insertions(+), 110 deletions(-) diff --git a/.github/workflows/e2e-tests-split.yml b/.github/workflows/e2e-tests-split.yml index 29f1ce13e..5f42fe116 100644 --- a/.github/workflows/e2e-tests-split.yml +++ b/.github/workflows/e2e-tests-split.yml @@ -324,17 +324,19 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run Chromium Security Enforcement Tests run: | @@ -564,30 +566,34 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Install Playwright Firefox - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Firefox..." - npx playwright install --with-deps firefox + run: | + set -uo pipefail + echo "📦 Installing Firefox..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps firefox && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright firefox install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run Firefox Security Enforcement Tests run: | @@ -820,30 +826,34 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Install Playwright WebKit - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing WebKit..." - npx playwright install --with-deps webkit + run: | + set -uo pipefail + echo "📦 Installing WebKit..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps webkit && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright webkit install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run WebKit Security Enforcement Tests run: | @@ -1103,17 +1113,19 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run Chromium Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | @@ -1346,30 +1358,34 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Install Playwright Firefox - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Firefox..." - npx playwright install --with-deps firefox + run: | + set -uo pipefail + echo "📦 Installing Firefox..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps firefox && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright firefox install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run Firefox Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | @@ -1602,30 +1618,34 @@ jobs: run: npm ci --ignore-scripts - name: Install Playwright Chromium (required by security-tests dependency) - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium + run: | + set -uo pipefail + echo "📦 Installing Chromium (required by security-tests dependency)..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps chromium && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright chromium install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Install Playwright WebKit - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 15 - retry_on: error - warning_on_retry: true - command: | - set -euo pipefail - echo "📦 Installing WebKit..." - npx playwright install --with-deps webkit + run: | + set -uo pipefail + echo "📦 Installing WebKit..." + for attempt in 1 2 3; do + timeout 10m npx playwright install --with-deps webkit && break + if [ "$attempt" -lt 3 ]; then + echo "Attempt ${attempt}/3 failed; retrying in 15s..." >&2 + sleep 15 + else + echo "ERROR: Playwright webkit install failed after 3 attempts" >&2 + exit 1 + fi + done - name: Run WebKit Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) run: | From 4a3f8f03a89c621e81d929e13949d098d2cb702e Mon Sep 17 00:00:00 2001 From: Jeremy Hatfield Date: Tue, 18 Aug 2026 12:09:56 +0000 Subject: [PATCH 3/4] fix(frontend): associate Input labels with their controls via auto-generated id frontend/src/components/ui/Input.tsx rendered