From 392c571055d96976192fed5282da3a9fe7e43dfc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 12 Apr 2026 14:26:23 +0000 Subject: [PATCH 1/2] fix(ci): handle GitHub preview environment delete without failing The cleanup job calls DELETE /repos/.../environments/... which returns 403 for the default GITHUB_TOKEN. PR #70 removed invalid workflow permission environments: write, which did not fix token scope anyway. Catch 403 so PR-close cleanup succeeds after Cloudflare teardown. Use optional secret PREVIEW_ENV_CLEANUP_TOKEN when a repo wants automatic environment removal, and document it in the setup guide. Co-authored-by: Kent C. Dodds --- .github/workflows/preview.yml | 12 ++++++++++++ docs/agents/setup.md | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 2a0fc4e..c27bafd 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -561,6 +561,10 @@ jobs: INPUT_TARGET: ${{ inputs.target }} INPUT_PR_NUMBER: ${{ inputs.pr_number }} with: + # The default GITHUB_TOKEN cannot delete deployment environments (403). + # Optional: set repo secret PREVIEW_ENV_CLEANUP_TOKEN to a PAT with repo + # scope (classic) or Administration: write (fine-grained) for this repo. + github-token: ${{ secrets.PREVIEW_ENV_CLEANUP_TOKEN || github.token }} script: | const eventName = process.env.EVENT_NAME; let envName; @@ -606,6 +610,14 @@ jobs: core.info( `GitHub environment not found (already deleted): ${envName}`, ); + } else if (e.status === 403) { + core.warning( + [ + `Cannot delete GitHub environment "${envName}" with the current token (403).`, + "The default workflow token is not allowed to delete environments.", + "Add repository secret PREVIEW_ENV_CLEANUP_TOKEN (PAT: classic `repo`, or fine-grained with Administration read/write on this repository) to enable automatic removal.", + ].join(" "), + ); } else { throw e; } diff --git a/docs/agents/setup.md b/docs/agents/setup.md index 478d1db..8c7dd4f 100644 --- a/docs/agents/setup.md +++ b/docs/agents/setup.md @@ -121,6 +121,16 @@ each PR preview is isolated: When a PR is closed, the cleanup job deletes the preview Worker(s) and these resources as well. +The same cleanup job removes the matching GitHub deployment environment +(`preview-`). GitHub’s default `GITHUB_TOKEN` cannot call the delete +environment API (you would see HTTP 403). That step is non-fatal: the workflow +still succeeds and Cloudflare resources are still removed. To delete the GitHub +environment automatically, add an Actions secret named +`PREVIEW_ENV_CLEANUP_TOKEN` whose value is a personal access token with +permission to administer this repository (for example a classic PAT with the +`repo` scope, or a fine-grained PAT with **Administration** read and write on +this repo only). + Cloudflare Workers supports version `preview_urls`, but those preview URLs are not currently available for Workers that use Durable Objects. The main app Worker binds `MCP_OBJECT`, so app previews continue to use per-PR Worker names. From 95db2843fb214a23e59a64669f99a1f32a0b7d48 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 12 Apr 2026 14:29:20 +0000 Subject: [PATCH 2/2] Clarify preview env cleanup 403 warning Co-authored-by: Kent C. Dodds --- .github/workflows/preview.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index c27bafd..baa50d6 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -614,8 +614,8 @@ jobs: core.warning( [ `Cannot delete GitHub environment "${envName}" with the current token (403).`, - "The default workflow token is not allowed to delete environments.", - "Add repository secret PREVIEW_ENV_CLEANUP_TOKEN (PAT: classic `repo`, or fine-grained with Administration read/write on this repository) to enable automatic removal.", + "The current token may not have permission to delete environments.", + "If you're using the default workflow token, add repository secret PREVIEW_ENV_CLEANUP_TOKEN (PAT: classic `repo`, or fine-grained with Administration read/write on this repository). If you're already using a PAT, ensure it has the required permissions.", ].join(" "), ); } else {