From e563ee64a8bb30f22726e450ecaa88204538caae Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Fri, 6 Mar 2026 10:43:15 +0100 Subject: [PATCH 1/5] chore: improve CI workflow - Bump actions to v4, node to 24, pnpm/action-setup to v4 (no pinned version) - Add workflow_dispatch trigger - Remove Debug Conditions step - Use consistent OG_IMAGE_SECRET ternary syntax - Align preview deployment condition with preview deploy condition - Upload playwright report on all outcomes (!cancelled), add retention - Consistent naming --- .github/workflows/ci.yml | 56 ++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 024dc18..b08fbd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: pull_request: pull_request_target: types: [labeled] + workflow_dispatch: jobs: build-and-deploy: @@ -20,13 +21,11 @@ jobs: fetch-depth: 0 ref: "${{ github.event.pull_request.merge_commit_sha }}" - - uses: pnpm/action-setup@v2 - with: - version: 10 + - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: "22" + node-version: "24" cache: "pnpm" - name: Install @@ -40,9 +39,6 @@ jobs: with: { add: "pnpm-lock.yaml", fetch: false, message: "Update lockfile" } - - name: Sync Astro types - run: pnpm astro sync - - name: Run linter run: pnpm lint --quiet @@ -53,8 +49,9 @@ jobs: run: pnpm build env: OG_IMAGE_SECRET: - ${{ case(github.event.pull_request.head.repo.fork, - 'fork-og-image-secret', secrets.OG_IMAGE_SECRET) }} + ${{ github.event.pull_request.head.repo.fork + && 'fork-og-image-secret' + || secrets.OG_IMAGE_SECRET }} - name: Install Playwright browsers run: pnpm exec playwright install --with-deps chromium @@ -63,15 +60,16 @@ jobs: id: test run: pnpm test - - name: Upload Playwright artifacts - if: failure() + - name: Upload Playwright report + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: - name: playwright-artifacts - path: playwright-report + name: playwright-report + path: playwright-report/ + retention-days: 30 - name: Deploy Production to Vercel - if: github.ref_name == 'main' + if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} run: node .github/scripts/deploy.mjs --token=${{ secrets.VERCEL_TOKEN }} --prod @@ -83,23 +81,15 @@ jobs: contains(github.event.pull_request.labels.*.name, 'trusted'))) }} run: node .github/scripts/deploy.mjs --token=${{ secrets.VERCEL_TOKEN }} - - name: Debug Conditions - run: | - echo "Event: ${{ github.event_name }}" - echo "Is fork: ${{ github.event.pull_request.head.repo.fork }}" - echo "Ref name: ${{ github.ref_name }}" - echo "Has trusted: ${{ contains(github.event.pull_request.labels.*.name, 'trusted') }}" - echo "Condition eval: ${{ !github.event.pull_request.head.repo.fork || (github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'trusted')) }}" - - name: Create GitHub Preview Deployment - uses: chrnorm/deployment-action@v2 if: - ${{ !github.event.pull_request.head.repo.fork || (github.event_name == - 'pull_request_target' && - contains(github.event.pull_request.labels.*.name, 'trusted')) }} + ${{ github.event_name != 'push' && (!github.event.pull_request.head.repo.fork || + (github.event_name == 'pull_request_target' && + contains(github.event.pull_request.labels.*.name, 'trusted'))) }} + uses: chrnorm/deployment-action@v2 with: token: "${{ github.token }}" - environment-url: https://${{ env.DEPLOYMENT_ALIAS }} # <- set by deploy.mjs + environment-url: https://${{ env.DEPLOYMENT_ALIAS }} environment: Preview production-environment: false initial-status: success @@ -121,15 +111,13 @@ jobs: needs: build-and-deploy runs-on: ubuntu-latest if: - ${{ !github.event.pull_request.head.repo.fork || (github.event_name == - 'pull_request_target' && contains(github.event.pull_request.labels.*.name, - 'trusted')) }} + ${{ github.event_name != 'push' && (!github.event.pull_request.head.repo.fork || + (github.event_name == 'pull_request_target' && + contains(github.event.pull_request.labels.*.name, 'trusted'))) }} steps: - uses: actions/checkout@v4 - - name: Audit Preview + - name: Audit URLs uses: treosh/lighthouse-ci-action@v12 - # todo: we should post a link to report to the PR in a sticky comment - # this prints " No GitHub token set, skipping GitHub status check."" with: urls: | https://${{ needs.build-and-deploy.outputs.deployment }}/ From 98ab9b9c74ff241aac2d7b552e363d2f7db2f743 Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Fri, 6 Mar 2026 13:00:06 +0100 Subject: [PATCH 2/5] fix: run astro sync before lint, handle workflow_dispatch deploys - Add `astro sync` step to generate types before lint/typecheck - Route workflow_dispatch on main to production deploy - Exclude workflow_dispatch from preview deploy conditions - Restore lighthouse to run on all non-fork events --- .github/workflows/ci.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b08fbd6..fe10cd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,11 @@ jobs: with: { add: "pnpm-lock.yaml", fetch: false, message: "Update lockfile" } + - name: Generate types + run: pnpm astro sync + env: + OG_IMAGE_SECRET: placeholder + - name: Run linter run: pnpm lint --quiet @@ -69,21 +74,23 @@ jobs: retention-days: 30 - name: Deploy Production to Vercel - if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref_name == 'main' }} run: node .github/scripts/deploy.mjs --token=${{ secrets.VERCEL_TOKEN }} --prod - name: Deploy Preview to Vercel if: - ${{ github.event_name != 'push' && (!github.event.pull_request.head.repo.fork || + ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' && + (!github.event.pull_request.head.repo.fork || (github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'trusted'))) }} run: node .github/scripts/deploy.mjs --token=${{ secrets.VERCEL_TOKEN }} - name: Create GitHub Preview Deployment if: - ${{ github.event_name != 'push' && (!github.event.pull_request.head.repo.fork || + ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' && + (!github.event.pull_request.head.repo.fork || (github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'trusted'))) }} uses: chrnorm/deployment-action@v2 @@ -96,7 +103,7 @@ jobs: ref: ${{ github.event.pull_request.merge_commit_sha }} - name: Create GitHub Production Deployment - if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref_name == 'main' }} uses: chrnorm/deployment-action@v2 with: token: "${{ github.token }}" @@ -111,9 +118,9 @@ jobs: needs: build-and-deploy runs-on: ubuntu-latest if: - ${{ github.event_name != 'push' && (!github.event.pull_request.head.repo.fork || + ${{ !github.event.pull_request.head.repo.fork || (github.event_name == 'pull_request_target' && - contains(github.event.pull_request.labels.*.name, 'trusted'))) }} + contains(github.event.pull_request.labels.*.name, 'trusted')) }} steps: - uses: actions/checkout@v4 - name: Audit URLs From 3cdcd1cb9fad4ebcb313ef92db5a6fadf60a2c97 Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Fri, 6 Mar 2026 13:08:19 +0100 Subject: [PATCH 3/5] fix: gate pull_request_target on trusted label at job level Prevents untrusted fork PR code from running with secret access when a non-trusted label is added. Also reduces Playwright report retention to 7 days and adds ref comment. --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe10cd0..dfea543 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,9 @@ on: jobs: build-and-deploy: + if: >- + github.event_name != 'pull_request_target' + || contains(github.event.pull_request.labels.*.name, 'trusted') runs-on: ubuntu-latest permissions: deployments: write @@ -19,6 +22,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + # Empty on push/workflow_dispatch — falls back to default ref ref: "${{ github.event.pull_request.merge_commit_sha }}" - uses: pnpm/action-setup@v4 @@ -71,7 +75,7 @@ jobs: with: name: playwright-report path: playwright-report/ - retention-days: 30 + retention-days: 7 - name: Deploy Production to Vercel if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref_name == 'main' }} From 4eebf238b3886fb692ea485561eb81d92545efcb Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Fri, 6 Mar 2026 13:13:22 +0100 Subject: [PATCH 4/5] refactor: use case() for OG_IMAGE_SECRET conditional --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfea543..f08b77e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,9 +58,8 @@ jobs: run: pnpm build env: OG_IMAGE_SECRET: - ${{ github.event.pull_request.head.repo.fork - && 'fork-og-image-secret' - || secrets.OG_IMAGE_SECRET }} + ${{ case(github.event.pull_request.head.repo.fork, + 'fork-og-image-secret', secrets.OG_IMAGE_SECRET) }} - name: Install Playwright browsers run: pnpm exec playwright install --with-deps chromium From 5f72082b8563cb661b6149520b700ebfca6141e7 Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Fri, 6 Mar 2026 13:14:41 +0100 Subject: [PATCH 5/5] fix: use correct GitHub API endpoint to remove trusted label The label name must be in the URL path, not as a form parameter. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f08b77e..0a5959e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,7 +144,7 @@ jobs: steps: - name: Remove trusted label run: | - gh api /repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels -X DELETE -F label=trusted + gh api /repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels/trusted -X DELETE env: GITHUB_TOKEN: "${{ github.token }}"