Skip to content

Add gh-pages deployment pipeline with PR preview support#32

Open
kertal wants to merge 3 commits into
mainfrom
claude/gh-pages-deployment-pipeline-jcT6K
Open

Add gh-pages deployment pipeline with PR preview support#32
kertal wants to merge 3 commits into
mainfrom
claude/gh-pages-deployment-pipeline-jcT6K

Conversation

@kertal

@kertal kertal commented Feb 20, 2026

Copy link
Copy Markdown
Owner

Split deployment into two workflows:

  • deploy.yml: production deployment on push to main using
    peaceiris/actions-gh-pages with keep_files to preserve previews
  • pr-preview.yml: automatic PR preview deployments to
    /pr-preview/pr-/ using rossjrw/pr-preview-action,
    with automatic cleanup on PR close

The PR preview workflow leverages the existing VITE_BASE_PATH env var
to build with the correct base path for each preview subdirectory.

https://claude.ai/code/session_01K7Zr3qqq3S12eDnou4ySBU

Split deployment into two workflows:
- deploy.yml: production deployment on push to main using
  peaceiris/actions-gh-pages with keep_files to preserve previews
- pr-preview.yml: automatic PR preview deployments to
  /pr-preview/pr-<number>/ using rossjrw/pr-preview-action,
  with automatic cleanup on PR close

The PR preview workflow leverages the existing VITE_BASE_PATH env var
to build with the correct base path for each preview subdirectory.

https://claude.ai/code/session_01K7Zr3qqq3S12eDnou4ySBU
Split deploy.yml into separate build and deploy jobs. The build job
now runs on both push and pull_request events, ensuring the production
build (with default base path) is always verified before merging.
The deploy job only runs on push to main.

https://claude.ai/code/session_01K7Zr3qqq3S12eDnou4ySBU
@coderabbitai

coderabbitai Bot commented Feb 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Restructures CI/CD: main deployment workflow now builds artifacts and deploys via peaceiris/actions-gh-pages@v4, adds a new PR preview workflow to build and deploy preview sites per PR, and updates the local deploy script and messaging (Node.js bumped to 20, .nojekyll moved to dist, concurrent workflow controls adjusted).

Changes

Cohort / File(s) Summary
Main deployment workflow
.github/workflows/deploy.yml
Normalized triggers to main, reduced permissions to contents: write, increased Node to 20, reorganized build/upload steps (artifact-based), updated concurrency key, and switched deploy action to peaceiris/actions-gh-pages@v4 with artifact download in deploy job.
PR preview workflow
.github/workflows/pr-preview.yml
New workflow triggered on PR events to build a preview (npm ci, npm run build) with PR-specific env vars and deploy using rossjrw/pr-preview-action@v1; steps are skipped when the PR action is closed.
Deploy script
deploy.sh
Added safety (set -e), moved creation of .nojekyll into dist/, removed cd dist, simplified and consolidated user-facing messages, and clarified deployment option guidance.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant GH as GitHub Events
  participant Runner as Actions Runner
  participant Artifact as Actions Artifact Store
  participant Pages as GitHub Pages (peaceiris action)

  GH->>Runner: trigger deploy workflow (push to main)
  Runner->>Runner: checkout, setup node (v20), install, build
  Runner->>Artifact: upload build artifact (production-build)
  GH->>Runner: start deploy job
  Runner->>Artifact: download production-build
  Runner->>Pages: invoke peaceiris/actions-gh-pages@v4 (publish_dir -> dist)
  Pages-->>GH: publish site to GitHub Pages
Loading
sequenceDiagram
  autonumber
  participant GH as GitHub PR Event
  participant Runner as Actions Runner
  participant ArtifactStore as PR Preview Action (rossjrw)
  participant PreviewHost as PR Preview Hosting

  GH->>Runner: trigger pr-preview workflow (PR opened/sync/reopen)
  Runner->>Runner: checkout, setup node, install, build (VITE vars set)
  Runner->>ArtifactStore: deploy `./dist` to umbrella `pr-preview`
  ArtifactStore->>PreviewHost: publish PR-specific preview site
  GH->>Runner: if PR closed -> skip build & deploy, optionally remove preview
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through workflows, tidy and spry,

artifacts kept, previews fly by,
Node twenty bounds, .nojekyll in place,
Deployments hum soft in their new little space.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding gh-pages deployment pipeline with PR preview support, which aligns with the addition of two new/refactored workflows (deploy.yml and pr-preview.yml) and related deployment script changes.
Description check ✅ Passed The description clearly explains the split deployment approach into two workflows with specific details about each workflow's purpose, triggering mechanism, and deployment strategy, directly relating to the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/gh-pages-deployment-pipeline-jcT6K

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

@github-actions

github-actions Bot commented Feb 20, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://kertal.github.io/git-vegas/pr-preview/pr-32/

Built to branch gh-pages at 2026-02-21 21:45 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@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: 1

🧹 Nitpick comments (1)
.github/workflows/deploy.yml (1)

13-14: Consider grouping by ref for push concurrency.
Using the sha means each main push gets a unique group, so older deployments won’t be cancelled. Grouping by github.ref for pushes helps ensure only the latest main deployment runs.

♻️ Suggested concurrency grouping
 concurrency:
-  group: pages-${{ github.event_name }}-${{ github.event.number || github.sha }}
+  group: pages-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 13 - 14, Change the concurrency
group expression so push events are grouped by ref instead of SHA: replace the
current "group: pages-${{ github.event_name }}-${{ github.event.number ||
github.sha }}" with a conditional expression that uses github.ref for push
events (e.g. evaluate github.event_name == 'push' ? github.ref :
github.event.number || github.sha) so pushes to the same branch share a group
and cancel previous runs while keeping the existing behavior for other event
types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pr-preview.yml:
- Around line 16-18: The workflow’s preview job uses the pull_request trigger
which gives forked PRs a read-only GITHUB_TOKEN, causing
rossjrw/pr-preview-action to fail; update the preview job (job name "preview")
to either switch the workflow trigger to pull_request_target and adopt a safe
checkout strategy before running rossjrw/pr-preview-action, or add a guard to
skip forked PRs by adding an if condition on the preview job such as checking
github.event.pull_request.head.repo.fork == false (or ensuring github.repository
== github.event.pull_request.head.repo.full_name) so the action only runs for
non-fork PRs where the GITHUB_TOKEN has write permissions.

---

Nitpick comments:
In @.github/workflows/deploy.yml:
- Around line 13-14: Change the concurrency group expression so push events are
grouped by ref instead of SHA: replace the current "group: pages-${{
github.event_name }}-${{ github.event.number || github.sha }}" with a
conditional expression that uses github.ref for push events (e.g. evaluate
github.event_name == 'push' ? github.ref : github.event.number || github.sha) so
pushes to the same branch share a group and cancel previous runs while keeping
the existing behavior for other event types.

Comment thread .github/workflows/pr-preview.yml
- pr-preview.yml: Skip preview deployment for forked PRs since
  pull_request provides a read-only GITHUB_TOKEN for forks, which
  would cause the gh-pages push to fail
- deploy.yml: Use event number (PRs) or ref (pushes) for concurrency
  grouping so concurrent main deploys cancel stale runs instead of
  each getting a unique SHA-based group

https://claude.ai/code/session_01K7Zr3qqq3S12eDnou4ySBU
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Feb 21, 2026

Copy link
Copy Markdown

Deploying git-vegas with  Cloudflare Pages  Cloudflare Pages

Latest commit: ce2177c
Status: ✅  Deploy successful!
Preview URL: https://6e0cc8df.git-vegas.pages.dev
Branch Preview URL: https://claude-gh-pages-deployment-p.git-vegas.pages.dev

View logs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a GitHub Pages deployment pipeline split into production deployments on main and per-PR preview deployments, using the existing Vite base-path configuration to support serving under subdirectories.

Changes:

  • Reworks production deployment workflow to publish via peaceiris/actions-gh-pages and preserve preview directories.
  • Adds a dedicated PR preview workflow that deploys to /pr-preview/pr-<number>/ and cleans up on PR close.
  • Updates deploy.sh messaging/behavior for local build/manual deployment guidance.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
deploy.sh Updates local build script notes and .nojekyll creation to align with GH Actions-based deployments.
.github/workflows/deploy.yml Switches production deployment to actions-gh-pages and adds artifact-based build/deploy separation.
.github/workflows/pr-preview.yml Introduces PR preview builds/deployments using rossjrw/pr-preview-action.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 11
on:
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]
branches: [main]

permissions:
contents: read
pages: write
id-token: write
contents: write

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

This workflow runs on pull_request but requests contents: write at the workflow level. That grants a write-capable GITHUB_TOKEN to all steps when the workflow runs for same-repo PRs, which is unnecessary for the build and increases blast radius if a PR is compromised. Consider removing the pull_request trigger here (since previews have their own workflow) and/or scoping permissions to contents: read by default with job-level permissions: contents: write only on the deploy job.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +33
permissions:
contents: write
pull-requests: write

concurrency:
group: pr-preview-${{ github.event.number }}
cancel-in-progress: true

jobs:
preview:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
if: github.event.action != 'closed'
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
if: github.event.action != 'closed'

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

This workflow checks out and executes PR code (npm ci/npm run build) with a write-capable GITHUB_TOKEN (contents: write). That allows same-repo PRs to use the token to push arbitrary commits/tags or otherwise modify the repository beyond the intended gh-pages updates. Consider splitting into a read-only build job and a separate deploy/cleanup job with elevated permissions, and/or gating deployments to same-repo branches only (e.g., skip if github.event.pull_request.head.repo.fork == true).

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +42
VITE_BASE_PATH: /git-vegas/pr-preview/pr-${{ github.event.number }}/
VITE_SCOPE: /git-vegas/pr-preview/pr-${{ github.event.number }}/
VITE_START_URL: /git-vegas/pr-preview/pr-${{ github.event.number }}/

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

The preview base path is hard-coded to /git-vegas/.... If the repo name or Pages base path changes, previews will break. Prefer deriving the repo path from GitHub context (e.g., /${{ github.event.repository.name }}/...) to keep previews portable.

Suggested change
VITE_BASE_PATH: /git-vegas/pr-preview/pr-${{ github.event.number }}/
VITE_SCOPE: /git-vegas/pr-preview/pr-${{ github.event.number }}/
VITE_START_URL: /git-vegas/pr-preview/pr-${{ github.event.number }}/
VITE_BASE_PATH: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/
VITE_SCOPE: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/
VITE_START_URL: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/

Copilot uses AI. Check for mistakes.
Comment thread deploy.sh
echo ""
echo " Automatic (recommended):"
echo " Push to main -> production deployment to GitHub Pages"
echo " Open a PR -> preview deployment at /pr-preview/pr-<number>/"

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

The script prints the preview URL as /pr-preview/pr-<number>/, but the build/workflow configuration uses /git-vegas/pr-preview/pr-<number>/ (repo subpath on GitHub Pages). Update the message to reflect the actual served path so local/manual users aren’t misled.

Suggested change
echo " Open a PR -> preview deployment at /pr-preview/pr-<number>/"
echo " Open a PR -> preview deployment at /git-vegas/pr-preview/pr-<number>/"

Copilot uses AI. Check for mistakes.
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
keep_files: true

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

keep_files: true preserves PR preview directories, but it also prevents the action from deleting removed/renamed production assets at the site root. Over time this can leave stale JS/CSS and other artifacts in gh-pages, increasing size and potentially serving outdated files if referenced. Consider adding a cleanup step that removes everything except pr-preview/ before publishing, or an alternative deployment strategy that preserves previews without keeping all historical production files.

Suggested change
keep_files: true

Copilot uses AI. Check for mistakes.
Comment on lines 51 to +63
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: production-build
path: ./dist

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4 No newline at end of file
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
keep_files: true

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

peaceiris/actions-gh-pages expects a git working copy (a .git directory) to commit/push to the gh-pages branch. The deploy job currently only downloads the build artifact, so it will run outside a checked-out repository and is likely to fail. Add an actions/checkout@v4 step (or otherwise ensure a git repo is present) before the deploy action.

Copilot uses AI. Check for mistakes.
Comment on lines 12 to +14
concurrency:
group: "pages"
cancel-in-progress: false
group: pages-${{ github.event.number || github.ref }}
cancel-in-progress: true

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

The concurrency group includes ${{ github.sha }} for push events, which makes the group unique per commit. That prevents cancel-in-progress from ever canceling prior runs and also allows multiple main deployments to run concurrently, potentially causing racing pushes to gh-pages. Use a stable group key for push to main (e.g., based on github.ref) so deployments serialize or cancel as intended.

Copilot uses AI. Check for mistakes.

@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: 1

🧹 Nitpick comments (1)
.github/workflows/pr-preview.yml (1)

36-42: Use github.event.repository.name instead of hardcoding the repository name.
This makes the workflow portable to repository renames. The variable is available in pull_request event contexts and will correctly reference the target repository.

♻️ Suggested change
-          VITE_BASE_PATH: /git-vegas/pr-preview/pr-${{ github.event.number }}/
-          VITE_SCOPE: /git-vegas/pr-preview/pr-${{ github.event.number }}/
-          VITE_START_URL: /git-vegas/pr-preview/pr-${{ github.event.number }}/
+          VITE_BASE_PATH: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/
+          VITE_SCOPE: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/
+          VITE_START_URL: /${{ github.event.repository.name }}/pr-preview/pr-${{ github.event.number }}/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr-preview.yml around lines 36 - 42, Replace the hardcoded
repository prefix "/git-vegas" in the VITE_* env vars with the pull request
event variable github.event.repository.name so the workflow remains correct
after repo renames; update VITE_BASE_PATH, VITE_SCOPE, and VITE_START_URL to
build paths like /${{ github.event.repository.name }}/pr-${{ github.event.number
}}/ (keeping the existing /pr-${{ github.event.number }}/ suffix) so these
variables reference the target repository dynamically in pull_request contexts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/deploy.yml:
- Around line 9-11: The workflow currently sets workflow-level permissions to
"contents: write" which grants write access to all jobs; change the top-level
permissions key to "contents: read" and then add a job-level permissions
override for the deploy job (the job named "deploy") setting "permissions:
contents: write" so only the deploy job has write access while all other jobs
(e.g., build on pull_request) run with read-only content access.

---

Nitpick comments:
In @.github/workflows/pr-preview.yml:
- Around line 36-42: Replace the hardcoded repository prefix "/git-vegas" in the
VITE_* env vars with the pull request event variable
github.event.repository.name so the workflow remains correct after repo renames;
update VITE_BASE_PATH, VITE_SCOPE, and VITE_START_URL to build paths like /${{
github.event.repository.name }}/pr-${{ github.event.number }}/ (keeping the
existing /pr-${{ github.event.number }}/ suffix) so these variables reference
the target repository dynamically in pull_request contexts.

Comment on lines 9 to 11
permissions:
contents: read
pages: write
id-token: write
contents: write

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find and examine the deploy.yml workflow file
find . -name "deploy.yml" -path "*/.github/workflows/*"

Repository: kertal/git-vegas

Length of output: 90


🏁 Script executed:

# Once found, examine the file to see the current permissions setup
cat -n .github/workflows/deploy.yml | head -60

Repository: kertal/git-vegas

Length of output: 1731


🌐 Web query:

GitHub Actions job-level permissions override workflow-level permissions

💡 Result:

Yes—job-level permissions override workflow-level permissions for that specific job.

How the effective GITHUB_TOKEN permissions are calculated

  1. Start with the default permissions set at the enterprise/org/repo level.
  2. Apply any permissions: set at the workflow level.
  3. Apply any jobs.<job_id>.permissions: set at the job level (this is the override step).
  4. If triggered by a fork PR (and write tokens aren’t allowed), any remaining write permissions may be reduced. [1]

Important details

  • When you use permissions (at workflow or job scope), any permissions you don’t specify are set to none (except metadata, which always has read access). [1][2]

Example

permissions:
  contents: read   # default for all jobs in this workflow

jobs:
  build:
    runs-on: ubuntu-latest
    steps: ...

  release:
    runs-on: ubuntu-latest
    permissions:        # overrides workflow-level permissions for this job only
      contents: write
    steps: ...

Reusable workflows nuance

If a job calls a reusable workflow, the called workflow can only downgrade (not elevate) the permissions passed from the caller job. [3]

Sources: GitHub Docs on permission calculation and unspecified permissions behavior [1][2], and reusable workflows permission rules [3].

[1] (docs.github.com)
[2] (docs.github.com)
[3] (docs.github.com)

Citations:


🌐 Web query:

GitHub Actions pull_request event security considerations write permissions

💡 Result:

pull_request event: security + write-permission reality

  • Fork PRs are intentionally “untrusted”:

    • Workflows triggered by pull_request from forks get a read-only GITHUB_TOKEN and no repository secrets (even if your workflow YAML requests write). This prevents external contributors from exfiltrating secrets or pushing to your repo. [1], [2]
  • Same-repo PRs can be “trusted” (but still risky if you run attacker-controlled input):

    • For PRs where the author can push branches in the same repo, the workflow is not treated like a fork, so the effective token privileges depend on your repo/org token-permissions settings and the workflow’s permissions: block. Injection bugs (e.g., unsafe use of PR title/body in scripts) can still be exploited. [3]
  • Default token permissions might be broader than you think:

    • GitHub provides controls to set the default GITHUB_TOKEN permissions at the org/repo level (commonly read/write by default, unless you change it). Best practice is to set defaults to read-only and grant write scopes only per-workflow/job. [4], [5]

What to do if you need “write” actions on PRs (comments/labels/status updates)

  • Prefer pull_request for building/testing untrusted code, and keep it minimally privileged:

    • Set explicit least-privilege permissions (often contents: read) and don’t rely on secrets. [4], [5]
  • Be very careful with pull_request_target:

    • pull_request_target runs in the base repo context and can have secrets + write token—if you check out and execute PR code in that context, you can create a “pwn request” (untrusted code with elevated privileges). Use it only for safe, non-code-executing tasks like labeling/commenting based on metadata. [6], [7]
  • Safer pattern for “test untrusted code, then do privileged updates”:

    • Run CI on pull_request (untrusted, no secrets), upload results as artifacts; then use a second workflow triggered by workflow_run (trusted context) to post comments/update PRs using artifacts. [6], [7]

Minimal example: lock down pull_request

on: pull_request

permissions:
  contents: read

(Then add only the exact additional scopes you need per job.) [4], [5]

Special case: Dependabot PRs

  • Workflows triggered by Dependabot PRs are treated like fork PRs for pull_request: read-only token, no secrets, so writes will fail unless you redesign using trusted triggers/patterns. [8]

Sources

[1] GitHub Security Lab: preventing “pwn requests” and event behaviors. (securitylab.github.com)
[2] Synacktiv: fork PR GITHUB_TOKEN restrictions + no secrets. (synacktiv.com)
[3] GitHub Blog: handling untrusted input + notes on pull_request privilege boundaries/injection risk. (github.blog)
[4] GitHub Docs: automatic token authentication / modifying GITHUB_TOKEN permissions. (docs.github.com)
[5] GitHub Changelog: controls for GITHUB_TOKEN permissions; fork PRs remain read-only. (github.blog)
[6] GitHub Well-Architected Actions security: avoid pull_request_target pitfalls. (wellarchitected.github.com)
[7] GitHub Blog (product news): pull_request_target and workflow_run trusted-context behavior. (github.blog)
[8] GitHub Changelog: Dependabot PRs run with read-only permissions. (github.blog)

Citations:


Scope write permissions to deploy job only.
The workflow grants contents: write for all jobs including pull_request events, where the build job executes PR code via npm run build. Tighten to least privilege by setting workflow-level permissions to contents: read and granting contents: write only to the deploy job, which is the only job that requires write access.

Suggested change
 permissions:
-  contents: write
+  contents: read
 
 concurrency:
   group: pages-${{ github.event.number || github.ref }}
   cancel-in-progress: true
 
 jobs:
   build:
     runs-on: ubuntu-latest
 
     steps:
       - name: Checkout
         uses: actions/checkout@v4
 
       - name: Setup Node.js
         uses: actions/setup-node@v4
         with:
           node-version: '20'
           cache: 'npm'
 
       - name: Install dependencies
         run: npm ci
 
       - name: Build
         run: npm run build
 
       - name: Create .nojekyll
         run: touch ./dist/.nojekyll
 
       - name: Upload build artifact
         if: github.event_name == 'push' && github.ref == 'refs/heads/main'
         uses: actions/upload-artifact@v4
         with:
           name: production-build
           path: ./dist
 
   deploy:
     needs: build
     if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+    permissions:
+      contents: write
     runs-on: ubuntu-latest
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
contents: read
pages: write
id-token: write
contents: write
permissions:
contents: read
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 9 - 11, The workflow currently
sets workflow-level permissions to "contents: write" which grants write access
to all jobs; change the top-level permissions key to "contents: read" and then
add a job-level permissions override for the deploy job (the job named "deploy")
setting "permissions: contents: write" so only the deploy job has write access
while all other jobs (e.g., build on pull_request) run with read-only content
access.

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.

3 participants