From 365e9f02f71d9d32b994c9a5bdb1e64a9097530a Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Sun, 24 May 2026 15:26:23 -0500 Subject: [PATCH] fix(ci): plumb VERCEL_AUTOMATION_BYPASS_SECRET into preview-smoke + visual-diff (Brief 1 of fix-vercel-deployment-protection-in-ci) Closes the CI-infra half of P0 #7's follow-up. PR #16 (squash commit 7e97254) added scoped permissions to both workflows but exposed that Vercel Deployment Protection 401s anonymous GitHub-runner requests, causing both Playwright smoke and Screenshot diff to time out at 10 minutes on every PR. This brief plumbs the bypass secret end-to-end so the wait-action's healthcheck reaches 200. Per architect Decision A (.convoys/fix-vercel-deployment-protection-in-ci.md): - preview-smoke.yml + visual-diff.yml: wait-for-vercel-preview's `path:` input now carries the bypass as a query parameter `?x-vercel-protection-bypass=${{ secrets.* }}&x-vercel-set-bypass-cookie=true`. The action only logs the bare targetUrl (verified in action.js:357,360,363) so the secret stays out of workflow logs. Per Decision B: - max_timeout: 600 -> 120. PR #16 evidence shows Vercel previews are up within seconds of job start; 120s gives ample headroom and surfaces misconfigurations in ~2 minutes instead of ~10. Per Decision D (NEW -- surfaced by Boot-the-brief): - gate: job's Decide step now checks github.event.pull_request.head.repo.fork FIRST. Forks lack repo secrets, so they would otherwise burn ~4 minutes per PR on a misleading 401. The fork-check emits `::notice::` and short- circuits before the existing skip-via-PR-body directive runs. Forward-compat for adopt-playwright-smoke: - Both workflows' Playwright/screenshot-capture step now exports VERCEL_AUTOMATION_BYPASS_SECRET as env. The actual Playwright config consumes it via extraHTTPHeaders in adopt-playwright-smoke's brief. BASE_URL stays as the bare \${{ steps.vercel.outputs.url }} (no query string) so it remains safe to echo. Verification: - YAML parses (js-yaml load on both files: preview-smoke jobs [gate, smoke]; visual-diff jobs [gate, visual]) - actionlint not run (binary not installed locally); recommend installing for future PRs. Future adopt-actionlint convoy could add it to CI. - No `set -x`, `echo`, `cat`, or `printf` of the secret or bypass URL in any modified step - permissions: and concurrency: blocks unchanged (PR #16 contracts preserved) Co-authored-by: Cursor --- .github/workflows/preview-smoke.yml | 9 +++++++-- .github/workflows/visual-diff.yml | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/preview-smoke.yml b/.github/workflows/preview-smoke.yml index a4f7a73..976882b 100644 --- a/.github/workflows/preview-smoke.yml +++ b/.github/workflows/preview-smoke.yml @@ -41,7 +41,10 @@ jobs: - name: Decide id: check run: | - if echo "${{ github.event.pull_request.body }}" | grep -qE 'pipeline:.*skip.*\bsmoke\b'; then + if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then + echo "should_run=false" >> $GITHUB_OUTPUT + echo "::notice::Smoke skipped on fork PR (bypass secret unavailable to forks)" + elif echo "${{ github.event.pull_request.body }}" | grep -qE 'pipeline:.*skip.*\bsmoke\b'; then echo "should_run=false" >> $GITHUB_OUTPUT echo "::notice::Smoke skipped via pipeline directive" else @@ -62,7 +65,8 @@ jobs: uses: patrickedqvist/wait-for-vercel-preview@v1.3.2 with: token: ${{ secrets.GITHUB_TOKEN }} - max_timeout: 600 + max_timeout: 120 + path: /?x-vercel-protection-bypass=${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}&x-vercel-set-bypass-cookie=true - uses: actions/setup-node@v4 with: @@ -78,6 +82,7 @@ jobs: run: npx playwright test --project=smoke env: BASE_URL: ${{ steps.vercel.outputs.url }} + VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }} - name: Upload Playwright report on failure if: failure() diff --git a/.github/workflows/visual-diff.yml b/.github/workflows/visual-diff.yml index eec3606..8a12afa 100644 --- a/.github/workflows/visual-diff.yml +++ b/.github/workflows/visual-diff.yml @@ -37,7 +37,10 @@ jobs: steps: - id: check run: | - if echo "${{ github.event.pull_request.body }}" | grep -qE 'pipeline:.*skip.*\bvisual\b'; then + if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then + echo "should_run=false" >> $GITHUB_OUTPUT + echo "::notice::Visual diff skipped on fork PR (bypass secret unavailable to forks)" + elif echo "${{ github.event.pull_request.body }}" | grep -qE 'pipeline:.*skip.*\bvisual\b'; then echo "should_run=false" >> $GITHUB_OUTPUT echo "::notice::Visual diff skipped via pipeline directive" else @@ -58,7 +61,8 @@ jobs: uses: patrickedqvist/wait-for-vercel-preview@v1.3.2 with: token: ${{ secrets.GITHUB_TOKEN }} - max_timeout: 600 + max_timeout: 120 + path: /?x-vercel-protection-bypass=${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}&x-vercel-set-bypass-cookie=true - uses: actions/setup-node@v4 with: @@ -72,6 +76,7 @@ jobs: run: npx playwright test --project=visual --update-snapshots=none env: BASE_URL: ${{ steps.vercel.outputs.url }} + VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }} continue-on-error: true - name: Upload screenshots + diffs