Skip to content

ci: deploy fork-PR previews via label-gated workflow_run#965

Open
dante01yoon wants to merge 1 commit into
mainfrom
ci/preview-fork-pr-deploy
Open

ci: deploy fork-PR previews via label-gated workflow_run#965
dante01yoon wants to merge 1 commit into
mainfrom
ci/preview-fork-pr-deploy

Conversation

@dante01yoon

Copy link
Copy Markdown
Contributor

Problem

Preview deploys fail for PRs opened from forks (e.g. #950). On pull_request events from a fork, GitHub withholds repository secrets, so the Vercel step runs with an empty token:

Error: You defined "--token", but it's missing a value

The build itself passes — only the deploy step fails, surfacing a red X to external contributors.

Approach

Split the preview into build (untrusted, no secrets) and deploy (trusted, secrets) so the Vercel token never touches fork-authored build code:

  • preview-site.yml (pull_request) now only builds the Astro site and uploads the prebuilt .vercel/output + PR number as an artifact. No secrets, no deploy. Added labeled to the trigger types so applying the label re-runs the build and chains a deploy.
  • deploy-preview.yml (workflow_run) runs in the base-repo context (secrets available), is gated by the maintainer-only preview label, downloads the prebuilt artifact, and runs vercel deploy --prebuilt. It posts the preview URL as a sticky PR comment.

Because the deploy job only ships an already-built artifact (no pnpm build of fork code runs with the token in scope), this avoids the secret-exfiltration risk of pull_request_target/issue_comment patterns.

Maintainer usage

Add the preview label to a fork PR → the build re-runs → a preview is deployed and the URL is commented. Remove + re-add the label to redeploy after reviewing new commits.

Notes

  • PUBLIC_HUB_API_URL / PUBLIC_COMFY_CLOUD_URL are baked at build time and remain unset for fork builds (pre-existing). If correct preview endpoints are needed for fork PRs, move these non-secret public values to repo Variables. Out of scope here.
  • workflow_run workflows don't appear as PR status checks, so contributors no longer see a red X for the deploy.
  • actionlint passes on both files.

Fork PRs never receive repo secrets on pull_request events, so the
Vercel deploy step failed with a missing --token value. Split the
preview into two workflows:

- preview-site.yml now only builds the Astro site (no secrets) and
  uploads the prebuilt .vercel/output plus the PR number as an artifact.
- deploy-preview.yml runs on workflow_run in the base-repo context
  (secrets available), gated by the maintainer-only 'preview' label,
  and deploys only the prebuilt artifact. The Vercel token never
  touches fork-authored build code.
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Preview Site workflow is refactored to stop deploying to Vercel directly; instead it writes the PR number to a metadata file and uploads the prebuilt Vercel output as an artifact. A new Deploy Preview workflow triggers on Preview Site completion, checks for a preview label, deploys the artifact to Vercel, and posts a sticky PR comment with the resulting URL.

Changes

Two-workflow preview pipeline

Layer / File(s) Summary
preview-site.yml: narrowed trigger, reduced permissions, artifact upload
.github/workflows/preview-site.yml
pull_request trigger gains an explicit types filter; pull-requests: write permission is removed; Vercel deploy and PR comment steps are replaced with a pr-number metadata write and upload of the prebuilt output as the vercel-preview-output artifact (1-day retention).
deploy-preview.yml: trigger, concurrency, permissions, job gate, artifact resolution
.github/workflows/deploy-preview.yml
New workflow triggered via workflow_run on Preview Site completion; concurrency is scoped per repo+branch; token permissions are read-only except PR write; the deploy job is gated to successful pull_request runs; artifact download and pr-number metadata read drive subsequent step conditions.
deploy-preview.yml: label gate, Vercel deployment, sticky PR comment
.github/workflows/deploy-preview.yml
gh pr view checks for a preview label and sets an approved output; on approval, the prebuilt output is copied into .vercel/output and deployed via npx vercel deploy --prebuilt; the parsed preview URL is posted or updated as a sticky PR comment — no label, no deploy, no fuss!

Sequence Diagram

sequenceDiagram
  participant PR as Pull Request
  participant PreviewSite as preview-site.yml
  participant Artifact as vercel-preview-output
  participant DeployPreview as deploy-preview.yml
  participant GH_CLI as gh CLI
  participant Vercel as Vercel CLI
  participant Comment as Sticky PR Comment

  PR->>PreviewSite: Trigger on opened/sync/reopened/labeled
  PreviewSite->>PreviewSite: Build Astro site
  PreviewSite->>Artifact: Upload prebuilt output + pr-number metadata
  Artifact-->>DeployPreview: workflow_run completion event
  DeployPreview->>Artifact: Download artifact, read pr-number
  DeployPreview->>GH_CLI: gh pr view --json labels
  GH_CLI-->>DeployPreview: approved = true/false
  DeployPreview->>Vercel: npx vercel deploy --prebuilt (if approved)
  Vercel-->>DeployPreview: Preview URL
  DeployPreview->>Comment: Post/update sticky comment with preview URL
Loading
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/preview-fork-pr-deploy
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch ci/preview-fork-pr-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

🤖 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/deploy-preview.yml:
- Around line 35-41: The preview deployment workflow is passing an untrusted
artifact value from artifact/preview-meta/pr-number directly into GITHUB_OUTPUT,
which can later be expanded in shell templates; validate the value in the
artifact-handling step before setting number/found. In the workflow job that
reads the PR number, ensure the value is strictly numeric (for example, using a
pattern check) and only then emit it; otherwise mark the artifact invalid and
stop before the later shell usage in the deployment steps that reference the PR
number.
- Around line 79-80: The deploy-preview workflow currently uses a mutable Vercel
CLI invocation via npx vercel@latest while VERCEL_TOKEN is available, so update
the command in the deploy step to use a pinned, reviewed Vercel CLI version or a
lockfile-backed installation instead. Keep the change localized to the workflow
job that runs the deploy command, and make sure the pinned reference is explicit
so the CLI version cannot change unexpectedly.
- Line 25: The deploy preview workflow currently references mutable action tags,
so pin the actions used in this job to full commit SHAs instead of version tags.
Update the `actions/download-artifact` and
`marocchino/sticky-pull-request-comment` references in the workflow to fixed
commit hashes so the privileged deploy flow always runs against immutable action
versions.

In @.github/workflows/preview-site.yml:
- Line 54: The workflow step using actions/upload-artifact is still referenced
by a floating version tag, so pin it to an immutable commit SHA instead. Update
the upload-artifact usage in the preview-site workflow to the SHA-backed
reference for the same v4 release, keeping the rest of the job unchanged.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 39235756-f6cd-45da-8b6c-9999496cb44e

📥 Commits

Reviewing files that changed from the base of the PR and between cf4932e and 80b939e.

📒 Files selected for processing (2)
  • .github/workflows/deploy-preview.yml
  • .github/workflows/preview-site.yml

runs-on: ubuntu-latest
steps:
- name: Download prebuilt output
uses: actions/download-artifact@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e yml -e yaml .github/workflows -x rg -n 'uses:\s+[^#]+@(?:v[0-9]+|main|master|latest)\b' {}

Repository: Comfy-Org/workflow_templates

Length of output: 540


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
fd --type f --hidden --glob '.github/workflows/*' . | sed 's#^\./##' | sort

printf '\n== deploy-preview.yml ==\n'
nl -ba .github/workflows/deploy-preview.yml | sed -n '1,220p'

printf '\n== mutable uses refs in workflows ==\n'
python3 - <<'PY'
from pathlib import Path
import re
for path in sorted(Path('.github/workflows').rglob('*.[yY][aA][mM][lL]')) + sorted(Path('.github/workflows').rglob('*.yml')):
    text = path.read_text()
    for i, line in enumerate(text.splitlines(), 1):
        m = re.search(r'^\s*uses:\s*([^#\s]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            if ref in {'main', 'master', 'latest'} or re.fullmatch(r'v\d+(\.\d+)*', ref):
                print(f"{path}:{i}:{m.group(1)}@{ref}")
PY

Repository: Comfy-Org/workflow_templates

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
fd --type f --hidden --glob '.github/workflows/*' . | sed 's#^\./##' | sort

printf '\n== deploy-preview.yml ==\n'
nl -ba .github/workflows/deploy-preview.yml | sed -n '1,220p'

printf '\n== mutable uses refs in workflows ==\n'
python3 - <<'PY'
from pathlib import Path
import re
for path in sorted(Path('.github/workflows').rglob('*.[yY][aA][mM][lL]')) + sorted(Path('.github/workflows').rglob('*.yml')):
    text = path.read_text()
    for i, line in enumerate(text.splitlines(), 1):
        m = re.search(r'^\s*uses:\s*([^#\s]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            if ref in {'main', 'master', 'latest'} or re.fullmatch(r'v\d+(\.\d+)*', ref):
                print(f"{path}:{i}:{m.group(1)}@{ref}")
PY

Repository: Comfy-Org/workflow_templates

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== deploy-preview.yml ==\n'
sed -n '1,220p' .github/workflows/deploy-preview.yml | cat -n

printf '\n== mutable uses refs in workflows ==\n'
python3 - <<'PY'
from pathlib import Path
import re

workflow_dir = Path('.github/workflows')
for path in sorted([p for p in workflow_dir.rglob('*') if p.suffix.lower() in {'.yml', '.yaml'}]):
    for i, line in enumerate(path.read_text().splitlines(), 1):
        m = re.search(r'^\s*uses:\s*([^#\s]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            if ref in {'main', 'master', 'latest'} or re.fullmatch(r'v\d+(\.\d+)*', ref):
                print(f"{path}:{i}:{m.group(1)}@{ref}")
PY

Repository: Comfy-Org/workflow_templates

Length of output: 10443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== deploy-preview.yml ==\n'
sed -n '1,220p' .github/workflows/deploy-preview.yml | cat -n

printf '\n== mutable uses refs in workflows ==\n'
python3 - <<'PY'
from pathlib import Path
import re

workflow_dir = Path('.github/workflows')
for path in sorted([p for p in workflow_dir.rglob('*') if p.suffix.lower() in {'.yml', '.yaml'}]):
    for i, line in enumerate(path.read_text().splitlines(), 1):
        m = re.search(r'^\s*uses:\s*([^#\s]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            if ref in {'main', 'master', 'latest'} or re.fullmatch(r'v\d+(\.\d+)*', ref):
                print(f"{path}:{i}:{m.group(1)}@{ref}")
PY

Repository: Comfy-Org/workflow_templates

Length of output: 10443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== deploy-preview.yml ==\n'
sed -n '1,220p' .github/workflows/deploy-preview.yml | cat -n

printf '\n== mutable uses refs in workflows ==\n'
python3 - <<'PY'
from pathlib import Path
import re

workflow_dir = Path('.github/workflows')
for path in sorted([p for p in workflow_dir.rglob('*') if p.suffix.lower() in {'.yml', '.yaml'}]):
    for i, line in enumerate(path.read_text().splitlines(), 1):
        m = re.search(r'^\s*uses:\s*([^#\s]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            if ref in {'main', 'master', 'latest'} or re.fullmatch(r'v\d+(\.\d+)*', ref):
                print(f"{path}:{i}:{m.group(1)}@{ref}")
PY

Repository: Comfy-Org/workflow_templates

Length of output: 10443


Pin the workflow actions

actions/download-artifact@v4 and marocchino/sticky-pull-request-comment@v2 are mutable tags. Pin both to full commit SHAs before this privileged deploy runs—no tag-drift gremlins.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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 25, The deploy preview workflow
currently references mutable action tags, so pin the actions used in this job to
full commit SHAs instead of version tags. Update the `actions/download-artifact`
and `marocchino/sticky-pull-request-comment` references in the workflow to fixed
commit hashes so the privileged deploy flow always runs against immutable action
versions.

Source: Linters/SAST tools

Comment on lines +35 to +41
number="$(tr -d '[:space:]' < artifact/preview-meta/pr-number)"
if [ -z "$number" ]; then
echo "No PR number in artifact; nothing to deploy."
echo "found=false" >> "$GITHUB_OUTPUT"
else
echo "found=true" >> "$GITHUB_OUTPUT"
echo "number=$number" >> "$GITHUB_OUTPUT"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate the artifact PR number before using it in shell templates.

artifact/preview-meta/pr-number crosses from the untrusted build artifact into a privileged workflow_run. Without numeric validation, a crafted value can be emitted as an output and expanded into the shell at Lines 50 and 55, bypassing the label gate or running unintended commands.

Suggested change
       - name: Resolve PR number
         id: pr
         run: |
           number="$(tr -d '[:space:]' < artifact/preview-meta/pr-number)"
-          if [ -z "$number" ]; then
-            echo "No PR number in artifact; nothing to deploy."
+          if [[ ! "$number" =~ ^[0-9]+$ ]]; then
+            echo "Invalid PR number in artifact; nothing to deploy." >&2
             echo "found=false" >> "$GITHUB_OUTPUT"
           else
             echo "found=true" >> "$GITHUB_OUTPUT"
             echo "number=$number" >> "$GITHUB_OUTPUT"
           fi
@@
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          PR_NUMBER: ${{ steps.pr.outputs.number }}
+          REPOSITORY: ${{ github.repository }}
         run: |
-          labels="$(gh pr view "${{ steps.pr.outputs.number }}" --repo "${{ github.repository }}" --json labels --jq '.labels[].name')"
+          labels="$(gh pr view "$PR_NUMBER" --repo "$REPOSITORY" --json labels --jq '.labels[].name')"
           if printf '%s\n' "$labels" | grep -qx 'preview'; then
             echo "approved=true" >> "$GITHUB_OUTPUT"
           else
             echo "approved=false" >> "$GITHUB_OUTPUT"
-            echo "PR #${{ steps.pr.outputs.number }} has no 'preview' label — skipping deploy."
+            echo "PR #$PR_NUMBER has no 'preview' label — skipping deploy."
           fi

Also applies to: 50-55

🤖 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 35 - 41, The preview
deployment workflow is passing an untrusted artifact value from
artifact/preview-meta/pr-number directly into GITHUB_OUTPUT, which can later be
expanded in shell templates; validate the value in the artifact-handling step
before setting number/found. In the workflow job that reads the PR number,
ensure the value is strictly numeric (for example, using a pattern check) and
only then emit it; otherwise mark the artifact invalid and stop before the later
shell usage in the deployment steps that reference the PR number.

Source: Linters/SAST tools

Comment on lines +79 to +80
if npx vercel@latest deploy --cwd "$GITHUB_WORKSPACE" --prebuilt --yes \
--token="$VERCEL_TOKEN" >"$stdout_file" 2>"$stderr_file"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e json -e lock -e yml -e yaml -e toml -e js -e ts | xargs rg -n '"vercel"|vercel@|npx vercel'

Repository: Comfy-Org/workflow_templates

Length of output: 480


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deploy-preview workflow context =="
nl -ba .github/workflows/deploy-preview.yml | sed -n '60,95p'

echo
echo "== repo search for Vercel CLI references =="
rg -n -C 2 'npx vercel|vercel@latest|vercel@' . --glob '!site/pnpm-lock.yaml'

echo
echo "== package manifests mentioning vercel =="
rg -n -C 2 '"vercel"|vercel@' package.json site/package.json pnpm-lock.yaml site/pnpm-lock.yaml .github/workflows/*.yml .github/workflows/**/*.yml

Repository: Comfy-Org/workflow_templates

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deploy-preview workflow context =="
nl -ba .github/workflows/deploy-preview.yml | sed -n '60,95p'

echo
echo "== repo search for Vercel CLI references =="
rg -n -C 2 'npx vercel|vercel@latest|vercel@' . --glob '!site/pnpm-lock.yaml'

echo
echo "== package manifests mentioning vercel =="
rg -n -C 2 '"vercel"|vercel@' package.json site/package.json pnpm-lock.yaml site/pnpm-lock.yaml .github/workflows/*.yml .github/workflows/**/*.yml

Repository: Comfy-Org/workflow_templates

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deploy-preview workflow context =="
awk 'NR>=60 && NR<=95 { printf "%4d %s\n", NR, $0 }' .github/workflows/deploy-preview.yml

echo
echo "== repo search for Vercel CLI references =="
rg -n -C 2 'npx vercel|vercel@latest|vercel@' . --glob '!site/pnpm-lock.yaml'

echo
echo "== files that mention vercel =="
git ls-files | rg '(^|/)(package\.json|pnpm-lock\.yaml|.*\.yml|.*\.yaml|.*\.json|.*\.js|.*\.ts)$' | xargs rg -n -C 1 '"vercel"|vercel@|npx vercel' --glob '!site/pnpm-lock.yaml'

Repository: Comfy-Org/workflow_templates

Length of output: 1783


Pin the Vercel CLI in .github/workflows/deploy-preview.yml:79

npx vercel@latest can pull mutable code while VERCEL_TOKEN is in scope. Replace it with a pinned version or a reviewed lockfile-backed install; there’s no existing CLI pin in the repo to reuse.

🤖 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 79 - 80, The
deploy-preview workflow currently uses a mutable Vercel CLI invocation via npx
vercel@latest while VERCEL_TOKEN is available, so update the command in the
deploy step to use a pinned, reviewed Vercel CLI version or a lockfile-backed
installation instead. Keep the change localized to the workflow job that runs
the deploy command, and make sure the pinned reference is explicit so the CLI
version cannot change unexpectedly.

if: github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v2
- name: Upload prebuilt output
uses: actions/upload-artifact@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e yml -e yaml .github/workflows -x rg -n 'uses:\s+[^#]+@(?:v[0-9]+|main|master|latest)\b' {}

Repository: Comfy-Org/workflow_templates

Length of output: 540


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the workflow around the referenced line and list all action refs.
echo '--- preview-site.yml (relevant section) ---'
sed -n '1,220p' .github/workflows/preview-site.yml | cat -n

echo
echo '--- all uses: entries in .github/workflows ---'
rg -n --glob '.github/workflows/**/*.yml' --glob '.github/workflows/**/*.yaml' '^\s*uses:\s*[^#]+' .github/workflows

Repository: Comfy-Org/workflow_templates

Length of output: 11801


Pin actions/upload-artifact to a commit SHA. actions/upload-artifact@v4 is mutable; use an immutable SHA here to avoid supply-chain drift and keep the workflow from going off-key.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 54-54: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/preview-site.yml at line 54, The workflow step using
actions/upload-artifact is still referenced by a floating version tag, so pin it
to an immutable commit SHA instead. Update the upload-artifact usage in the
preview-site workflow to the SHA-backed reference for the same v4 release,
keeping the rest of the job unchanged.

Source: Linters/SAST tools


on:
pull_request:
types: [opened, synchronize, reopened, labeled]

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.

issue: labeled event type is functionally dead when combined with the paths: ['site/**'] filter. GitHub evaluates event types and paths as a conjunction, so adding the preview label to a fork PR that has no site/** changes will not trigger this workflow. The "remove + re-add the label to redeploy" workaround described in the PR description also fails for the same reason -- the only working path for a first deploy is a new push (synchronize) after the label is present.

Since the label gate is correctly enforced at deploy-time in deploy-preview.yml, the labeled type here is not needed. Suggest removing it, or moving label-triggered builds to a separate workflow file without a paths filter.

group: deploy-preview-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

permissions:

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.

issue: cancel-in-progress: true on a deploy workflow can leave a broken Vercel preview if a second push arrives while vercel deploy is mid-flight -- the runner is killed after the upload has started but before it completes, and Vercel may surface a stale or errored deployment. deploy-site.yml uses cancel-in-progress: false for exactly this reason. Deploy workflows should queue rather than cancel.


- name: Check for preview label
id: gate
if: steps.pr.outputs.found == 'true'

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.

issue: label approval can be consumed by a later, unreviewed commit. Sequence: (1) maintainer adds preview label to commit A; (2) fork author immediately pushes commit B; (3) Preview Site runs on commit B and uploads a new artifact; (4) this workflow fires, checks the label -- still present -- and deploys commit B's content. The label granted for commit A now covers commit B without maintainer re-review.

Two options: (a) add a pull_request: [synchronize] workflow that strips the preview label on every new push, forcing re-approval per commit; or (b) record the approved SHA when labeling and verify github.event.workflow_run.head_sha matches at deploy time.

id: pr
run: |
number="$(tr -d '[:space:]' < artifact/preview-meta/pr-number)"
if [ -z "$number" ]; then

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.

nitpick: (non-blocking) tr -d '[:space:]' strips whitespace but does not validate the result is a non-negative integer before writing to GITHUB_OUTPUT and passing to gh pr view. In practice github.event.pull_request.number is always a positive integer, but a defensive check costs nothing: if [[ ! "$number" =~ ^[0-9]+$ ]]; then echo "Invalid PR number" >&2; exit 1; fi

permissions:
contents: read
actions: read
pull-requests: write

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.

nitpick: (non-blocking) contents: read is listed but this workflow has no actions/checkout step and reads no repo contents. actions/download-artifact with run-id uses actions: read (already present). The existing workflow_run workflows in this repo (spellcheck-comment.yml, link-check-comment.yml) omit contents: read and work correctly.

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.

2 participants