Skip to content

chore: add preview deployments#26

Merged
gameroman merged 6 commits into
mainfrom
add-preview-deploy
Jul 10, 2026
Merged

chore: add preview deployments#26
gameroman merged 6 commits into
mainfrom
add-preview-deploy

Conversation

@gameroman

@gameroman gameroman commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added automated “Build Preview” and “Deploy Preview” workflows for pull requests, including generated preview links.
    • Automatically posts and updates a PR comment to reflect deployment progress and final success/failure.
  • Bug Fixes

    • Tightened GitHub Actions permissions to least privilege for CI and preview workflows.
    • Updated CI to use Bun’s CI routine for dependency preparation.
  • Chores

    • Added a preview deployment script and refreshed the Wrangler compatibility date.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
dependents-dev cd9e267 Commit Preview URL

Branch Preview URL
Jul 07 2026, 07:08 PM

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c2fdb21e-84e1-4864-bfcc-219c5871d901

📥 Commits

Reviewing files that changed from the base of the PR and between 4e6c49e and d210ed9.

📒 Files selected for processing (1)
  • .github/workflows/deploy-preview.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/deploy-preview.yml

📝 Walkthrough

Walkthrough

Adds preview build and deployment workflows for pull requests, passing build and PR metadata through artifacts, deploying with Wrangler, and updating PR comments. It also tightens CI permissions, changes the Bun install command, and updates Wrangler configuration.

Changes

Preview Build and Deploy Pipeline

Layer / File(s) Summary
Build Preview workflow: trigger and build
.github/workflows/build-preview.yml
A pull request workflow configures permissions and concurrency, installs Bun dependencies with bun ci, builds the project, and uploads dist/ as build-output.
Build Preview workflow: preview metadata
.github/workflows/build-preview.yml
The workflow writes the PR number, pr-<PR_NUM> alias, and preview URL to pr-metadata/, then uploads the metadata artifact.
Deploy Preview workflow: trigger, comments, and deploy
.github/workflows/deploy-preview.yml, package.json, wrangler.jsonc
A successful Build Preview run triggers deployment, reads both artifacts, updates the PR deployment comment, runs wrangler versions upload with the preview alias, and reports success or failure. Wrangler retains the asset configuration, removes its build block, and updates the compatibility date.
CI workflow permissions and install command
.github/workflows/ci.yml
CI sets top-level permissions to empty and changes dependency installation from bun install --frozen-lockfile to bun ci.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant BuildPreview
  participant ArtifactStorage
  participant DeployPreview
  participant Cloudflare

  PullRequest->>BuildPreview: pull_request event
  BuildPreview->>BuildPreview: bun ci and bun run build
  BuildPreview->>ArtifactStorage: upload build-output and pr-metadata
  ArtifactStorage->>DeployPreview: download artifacts
  DeployPreview->>DeployPreview: update deployment comment
  DeployPreview->>Cloudflare: wrangler versions upload
  Cloudflare-->>DeployPreview: deployment result
  DeployPreview->>PullRequest: update deployment comment
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding preview deployment workflows and supporting scripts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-preview-deploy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
.github/workflows/build-preview.yml (2)

22-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin bun-version instead of latest.

Using latest makes builds non-reproducible and can silently break CI when a new Bun release changes behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-preview.yml around lines 22 - 24, The build workflow
is using a moving Bun version, which makes CI behavior non-reproducible. Update
the setup step that uses oven-sh/setup-bun so bun-version is pinned to a
specific released version instead of latest, keeping the workflow stable and
predictable across runs.

44-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded WORKER_NAME/SUBDOMAIN duplicate deployment config.

These values must stay in sync with the actual Cloudflare Worker name/subdomain used by wrangler.toml/wrangler versions upload. If either changes, the preview_url written here will silently point to a dead URL with no build-time validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-preview.yml around lines 44 - 50, The preview URL
generation in the workflow is hardcoding the Worker name and subdomain, so
update the logic around the preview_url write to derive these values from the
same deployment config used by wrangler.toml / wrangler versions upload instead
of duplicating them as WORKER_NAME and SUBDOMAIN. Keep the preview_alias and
preview_url construction in sync with the actual Cloudflare Worker identifiers
so changes only need to be made in one place.
.github/workflows/deploy-preview.yml (1)

42-46: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Template expansion of metadata values directly into JS script bodies.

prNumber, previewUrl, and commitSHA are interpolated via ${{ }} directly into inline github-script code rather than passed through env: + process.env. While these particular values currently originate from trusted GitHub context fields and the build-preview metadata files, this pattern is inherently fragile — any future change that lets attacker-influenced content flow into these outputs becomes an injection vector. Static analysis flags this as template-injection risk.

🔒 Example refactor using env passthrough
       - name: Comment deployment in progress
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+        env:
+          PR_NUMBER: ${{ steps.metadata.outputs.pr_number }}
+          PREVIEW_URL: ${{ steps.metadata.outputs.preview_url }}
+          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
         with:
           script: |
-            const prNumber = parseInt('${{ steps.metadata.outputs.pr_number }}', 10);
-            const previewUrl = '${{ steps.metadata.outputs.preview_url }}';
-            const commitSHA = '${{ github.event.workflow_run.head_sha }}';
+            const prNumber = parseInt(process.env.PR_NUMBER, 10);
+            const previewUrl = process.env.PREVIEW_URL;
+            const commitSHA = process.env.COMMIT_SHA;

Also applies to: 77-81, 94-97

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-preview.yml around lines 42 - 46, The inline
github-script block is interpolating metadata values directly into JavaScript,
which creates a template-injection risk. In the workflow steps that use
prNumber, previewUrl, and commitSHA, move these values into env: and read them
from process.env inside the script instead of using direct ${{
}} expansion. Update the affected github-script uses consistently so the script
body only contains fixed code and all dynamic values come from environment
variables.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-preview.yml:
- Around line 18-19: Disable credential persistence in the Checkout step of the
build preview workflow by setting the checkout action’s persist-credentials
option to false. Update the existing actions/checkout usage in the Checkout job
so the token is not retained after source checkout, especially for the
pull_request trigger path.

In @.github/workflows/ci.yml:
- Around line 9-10: The CI workflow is stripping all token permissions, but the
job still uses actions/checkout, so add job-level contents: read to the workflow
permissions alongside the existing minimal scopes. Update the CI job in
.github/workflows/ci.yml to match the checkout requirements used in
build-preview so the checkout step can access the repository without relying on
alternate authentication.

In @.github/workflows/deploy-preview.yml:
- Around line 67-70: The Deploy Preview step has an unterminated string in the
run command, which will break shell parsing. Fix the `run` line in the `Deploy
Preview` job so `steps.metadata.outputs.preview_alias` is fully wrapped in
matching double quotes, keeping the command in
`.github/workflows/deploy-preview.yml` syntactically valid.
- Around line 3-6: The deploy-preview workflow currently triggers on
workflow_run without verifying the source PR is safe, which can rerun untrusted
PR code under secrets during wrangler versions upload. Add a guard in the deploy
job before calling the deploy logic in this workflow to ensure the run only
proceeds for same-repository or otherwise approved PRs, and reference the
workflow_run-triggered deploy steps and the wrangler upload path when
implementing the check.

---

Nitpick comments:
In @.github/workflows/build-preview.yml:
- Around line 22-24: The build workflow is using a moving Bun version, which
makes CI behavior non-reproducible. Update the setup step that uses
oven-sh/setup-bun so bun-version is pinned to a specific released version
instead of latest, keeping the workflow stable and predictable across runs.
- Around line 44-50: The preview URL generation in the workflow is hardcoding
the Worker name and subdomain, so update the logic around the preview_url write
to derive these values from the same deployment config used by wrangler.toml /
wrangler versions upload instead of duplicating them as WORKER_NAME and
SUBDOMAIN. Keep the preview_alias and preview_url construction in sync with the
actual Cloudflare Worker identifiers so changes only need to be made in one
place.

In @.github/workflows/deploy-preview.yml:
- Around line 42-46: The inline github-script block is interpolating metadata
values directly into JavaScript, which creates a template-injection risk. In the
workflow steps that use prNumber, previewUrl, and commitSHA, move these values
into env: and read them from process.env inside the script instead of using
direct ${{
}} expansion. Update the affected github-script uses consistently so the script
body only contains fixed code and all dynamic values come from environment
variables.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 32f6a12f-52db-4e0c-885a-17c853302c67

📥 Commits

Reviewing files that changed from the base of the PR and between c46ffd6 and cd9e267.

📒 Files selected for processing (4)
  • .github/workflows/build-preview.yml
  • .github/workflows/ci.yml
  • .github/workflows/deploy-preview.yml
  • package.json

Comment thread .github/workflows/build-preview.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/deploy-preview.yml
Comment thread .github/workflows/deploy-preview.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/deploy-preview.yml (1)

88-90: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a fallback to create the comment when none exists.

The "complete" and "failed" steps only call updateComment if an existing comment is found. If the "in progress" step failed or was skipped, there's no comment to update and the deployment status is silently lost. Fall back to createComment when existing is undefined.

💚 Proposed fix for the "complete" step (apply similarly to "failed")
             if (existing) {
               await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body });
+            } else {
+              await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body });
             }

Also applies to: 103-105

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-preview.yml around lines 88 - 90, The
deploy-preview workflow only updates an existing GitHub issue comment, so if the
earlier “in progress” comment was never created the deployment status
disappears. Update the “complete” and “failed” comment handling in the workflow
to branch on existing: keep using github.rest.issues.updateComment when existing
is present, and fall back to github.rest.issues.createComment with the same body
when it is undefined.
🧹 Nitpick comments (3)
.github/workflows/deploy-preview.yml (3)

45-48: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass artifact-derived values via environment variables instead of template expansion.

zizmor flags template injection on these lines. While the values originate from the trusted build-preview workflow (generated from GitHub event data, not user input), interpolating artifact contents directly into JavaScript string literals is a fragile pattern. If any upstream change ever allows user-controlled data into these artifacts, it becomes an injection vector. Use env inputs on the github-script step and reference process.env instead.

♻️ Example for the "in progress" step (apply similarly to all three)
       - name: Comment deployment in progress
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+        env:
+          PR_NUMBER: ${{ steps.metadata.outputs.pr_number }}
+          PREVIEW_URL: ${{ steps.metadata.outputs.preview_url }}
+          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
+          RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
         with:
           script: |
-            const prNumber = parseInt('${{ steps.metadata.outputs.pr_number }}', 10);
-            const previewUrl = '${{ steps.metadata.outputs.preview_url }}';
-            const commitSHA = '${{ github.event.workflow_run.head_sha }}';
-            const runUrl = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}';
+            const prNumber = parseInt(process.env.PR_NUMBER, 10);
+            const previewUrl = process.env.PREVIEW_URL;
+            const commitSHA = process.env.COMMIT_SHA;
+            const runUrl = process.env.RUN_URL;
             const body = `**Preview deployment**\n\n🔄 Deployment in progress...\n\n- **Latest commit:** ${commitSHA}\n- **Preview:** ${previewUrl}\n- **Workflow run:** [View logs](${runUrl})`;

Also applies to: 80-83, 97-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-preview.yml around lines 45 - 48, The github-script
step is interpolating artifact-derived values directly into JavaScript string
literals, which triggers template injection warnings. Update the affected
github-script steps to pass prNumber, previewUrl, commitSHA, and runUrl through
step env inputs instead of `${{ ... }}` expansion, and read them from
process.env inside the script. Apply the same env-based pattern consistently in
all referenced github-script blocks so the values are not embedded directly in
the script body.

Sources: Learnings, Linters/SAST tools


73-73: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Use an environment variable for preview_alias in the shell command.

Same template-injection concern as the github-script steps — preview_alias is interpolated directly into a run command. Pass it via env and reference it as a shell variable to eliminate the injection surface.

♻️ Proposed fix
       - name: Deploy Preview
         env:
           CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+          PREVIEW_ALIAS: ${{ steps.metadata.outputs.preview_alias }}
-        run: bun run deploy-preview -- --preview-alias "${{ steps.metadata.outputs.preview_alias }}"
+        run: bun run deploy-preview -- --preview-alias "$PREVIEW_ALIAS"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-preview.yml at line 73, The deploy-preview shell
step interpolates `steps.metadata.outputs.preview_alias` directly into the run
command, creating a template-injection surface. Update the workflow step to pass
`preview_alias` through env and reference that shell variable in the bun command
instead, using the existing deploy-preview step as the target location.

Source: Linters/SAST tools


41-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract shared comment logic to reduce duplication.

The three github-script blocks repeat nearly identical find/update/create comment logic. Consider extracting a small reusable composite action or a shared script file to keep the comment-formatting and comment-lookup logic in one place.

Also applies to: 75-91, 92-106

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-preview.yml around lines 41 - 62, The three
github-script steps repeat the same comment lookup and create/update flow, so
extract that shared logic into one reusable place instead of duplicating it.
Move the common comment-handling code used by the “Comment deployment in
progress” block and the other deployment comment blocks into a shared composite
action or script module, and have each workflow step pass only the varying
message/body content and metadata. Keep the existing github.rest.issues
listComments/updateComment/createComment behavior centralized so the workflow
stays maintainable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/deploy-preview.yml:
- Around line 88-90: The deploy-preview workflow only updates an existing GitHub
issue comment, so if the earlier “in progress” comment was never created the
deployment status disappears. Update the “complete” and “failed” comment
handling in the workflow to branch on existing: keep using
github.rest.issues.updateComment when existing is present, and fall back to
github.rest.issues.createComment with the same body when it is undefined.

---

Nitpick comments:
In @.github/workflows/deploy-preview.yml:
- Around line 45-48: The github-script step is interpolating artifact-derived
values directly into JavaScript string literals, which triggers template
injection warnings. Update the affected github-script steps to pass prNumber,
previewUrl, commitSHA, and runUrl through step env inputs instead of `${{ ...
}}` expansion, and read them from process.env inside the script. Apply the same
env-based pattern consistently in all referenced github-script blocks so the
values are not embedded directly in the script body.
- Line 73: The deploy-preview shell step interpolates
`steps.metadata.outputs.preview_alias` directly into the run command, creating a
template-injection surface. Update the workflow step to pass `preview_alias`
through env and reference that shell variable in the bun command instead, using
the existing deploy-preview step as the target location.
- Around line 41-62: The three github-script steps repeat the same comment
lookup and create/update flow, so extract that shared logic into one reusable
place instead of duplicating it. Move the common comment-handling code used by
the “Comment deployment in progress” block and the other deployment comment
blocks into a shared composite action or script module, and have each workflow
step pass only the varying message/body content and metadata. Keep the existing
github.rest.issues listComments/updateComment/createComment behavior centralized
so the workflow stays maintainable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d3a8a158-0eb4-4211-a1e9-db51481bc183

📥 Commits

Reviewing files that changed from the base of the PR and between cd9e267 and 5045574.

📒 Files selected for processing (3)
  • .github/workflows/build-preview.yml
  • .github/workflows/deploy-preview.yml
  • wrangler.jsonc
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build-preview.yml

@gameroman

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gameroman

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gameroman gameroman merged commit 98838b1 into main Jul 10, 2026
3 checks passed
@gameroman gameroman deleted the add-preview-deploy branch July 10, 2026 15:49
@coderabbitai coderabbitai Bot mentioned this pull request Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant