ci: add workflow_dispatch trigger to PR Preview for Dependabot PRs#326
ci: add workflow_dispatch trigger to PR Preview for Dependabot PRs#326
Conversation
Dependabot PRs don't have access to secrets, so the deploy-preview job always fails. Add a manual workflow_dispatch trigger with a pr_number input so maintainers can trigger the preview deploy from the Actions tab. Changes: - Add workflow_dispatch trigger with required pr_number input - Add resolve step to fetch PR metadata (number + head SHA) for both triggers - Propagate resolved values via job outputs to deploy and comment steps - Guard cleanup job to only run on pull_request closed events
|
Note Gemini is unable to generate a summary for this pull request due to the file types involved not being currently supported. |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a manual Changes
Sequence Diagram(s)sequenceDiagram
participant User as Trigger (user)
participant GH as GitHub Actions
participant GHAPI as GitHub API (gh)
participant Runner as Actions runner
participant Pages as Cloudflare Pages (wrangler)
participant Comments as GitHub Issues API
rect rgba(100,149,237,0.5)
User->>GH: workflow_dispatch(pr_number) or pull_request event
end
GH->>GHAPI: Resolve PR metadata (pr_number, head_sha, state, repo)
GHAPI-->>GH: metadata (pr_number, head_sha, same_repo)
GH->>Runner: start Build job with pr metadata outputs
Runner->>Runner: checkout @ head_sha
Runner->>Pages: build & deploy preview (if same_repo && PR open)
Pages-->>Runner: preview URL
Runner->>Comments: post/update PR comment with preview URL
Note over GH: On PR close (pull_request only) -> Cleanup job deletes preview and comment
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
📝 Coding Plan
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #326 +/- ##
=======================================
Coverage 93.64% 93.64%
=======================================
Files 427 427
Lines 19177 19177
Branches 1846 1846
=======================================
Hits 17959 17959
Misses 943 943
Partials 275 275 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Greptile SummaryThis PR adds a Key changes:
One issue found: the Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([Trigger]) --> B{Event type?}
B -->|workflow_dispatch| C[Read pr_number input]
B -->|pull_request| D[Read pr_number from event context]
C --> E[gh pr view PR_NUMBER --json headRefOid,state,isCrossRepository]
E --> F{PR state == OPEN?}
F -->|No| FAIL1([Exit with error])
F -->|Yes| G[Resolve head_sha and same_repo from API response]
D --> H[Read head_sha and same_repo from event context]
G --> VALIDATE
H --> VALIDATE
VALIDATE[Validate pr_number is positive integer] --> BUILD
BUILD[Build MkDocs + Astro, inject preview banner] --> OUTPUTS
OUTPUTS[Emit pr_number, head_sha, same_repo as job outputs]
OUTPUTS --> I{same_repo == true?}
I -->|No| SKIP([deploy-preview skipped])
I -->|Yes| DEPLOY[Deploy to Cloudflare Pages branch pr-N]
DEPLOY --> COMMENT[Create or update PR preview comment]
OUTPUTS --> J{pull_request closed?}
J -->|No| END([Done])
J -->|Yes| CLEANUP[Delete preview comment + Cloudflare deployments]
Prompt To Fix All With AIThis is a comment left during a code review.
Path: .github/workflows/pages-preview.yml
Line: 64-67
Comment:
**Unreachable empty-JSON guard with `set -euo pipefail`**
The `if [ -z "$PR_JSON" ]` guard is effectively unreachable in any failure path. With `set -euo pipefail` active, if `gh pr view` exits non-zero (e.g., PR not found, auth error, network failure), bash exits immediately during the command substitution — `PR_JSON` is never assigned, and execution never reaches the empty check. The custom `::error::` annotation will therefore never fire; the workflow will just exit with gh's own error output.
If you want the custom error message to appear, you need to suppress the exit or capture the exit code explicitly:
```suggestion
CURL_EXIT=0
PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$GH_REPOSITORY" \
--json headRefOid,state,isCrossRepository 2>&1) || CURL_EXIT=$?
if [ "$CURL_EXIT" -ne 0 ] || [ -z "$PR_JSON" ]; then
echo "::error::Failed to fetch metadata for PR #$PR_NUMBER (exit $CURL_EXIT)"
exit 1
fi
```
Or alternatively, simply remove the dead guard and rely on gh's own error output (which is already clear) plus the `set -e` exit.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: .github/workflows/pages-preview.yml
Line: 237
Comment:
**Inline `${{ }}` expression in `env:` value for URL construction**
`${{ needs.build.outputs.pr_number }}` is used inline within the YAML string value of the `PREVIEW_URL` env var. While the value is validated upstream as `^[1-9][0-9]*$` (digits only), this is still an inline template expansion. Since `pr_number` can only be digits at this point, there is no actual injection risk here — but for consistency with the safe pattern used in the build step's `PR_INPUT` env var, consider assembling the URL in the script itself:
```suggestion
PREVIEW_URL: ""
PR_NUMBER: ${{ needs.build.outputs.pr_number }}
HEAD_SHA: ${{ needs.build.outputs.head_sha }}
```
Then construct the URL in the `script:` block: `const url = \`https://pr-${prNumber}.synthorg-pr-preview.pages.dev\`;`. This is a minor consistency suggestion since `pr_number` is already digit-validated.
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: 1c0543c |
There was a problem hiding this comment.
Pull request overview
This PR updates the PR Preview GitHub Actions workflow to support manual workflow_dispatch runs (primarily to enable previews for Dependabot PRs that don’t receive secret-bearing pull_request events), while keeping existing PR-triggered behavior working.
Changes:
- Adds a
workflow_dispatchtrigger with apr_numberinput and resolves the PR head SHA dynamically viagh pr view. - Propagates
pr_numberandhead_shathroughbuildjob outputs and updates checkout/banner/commenting to use those values. - Prevents the cleanup job from running on dispatch executions.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| permissions: | ||
| contents: read | ||
| outputs: | ||
| pr_number: ${{ steps.pr.outputs.pr_number }} | ||
| head_sha: ${{ steps.pr.outputs.head_sha }} | ||
| steps: | ||
| - name: Resolve PR metadata | ||
| id: pr | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| PR_NUMBER="${{ github.event.pull_request.number || github.event.inputs.pr_number }}" | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| HEAD_SHA=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json headRefOid -q .headRefOid) | ||
| else |
There was a problem hiding this comment.
The new gh pr view call will require pull-requests: read permission on the job token. Right now the workflow-level permissions are {} and this job only grants contents: read, so gh pr view is likely to 403 on workflow_dispatch runs. Add pull-requests: read (or move it to workflow-level if preferred) so PR metadata resolution works reliably.
| run: | | ||
| PR_NUMBER="${{ github.event.pull_request.number || github.event.inputs.pr_number }}" | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| HEAD_SHA=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json headRefOid -q .headRefOid) | ||
| else | ||
| HEAD_SHA="${{ github.event.pull_request.head.sha }}" | ||
| fi | ||
| echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | ||
| echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| persist-credentials: false | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
| ref: ${{ steps.pr.outputs.head_sha }} |
There was a problem hiding this comment.
The metadata resolution step doesn’t fail fast if the PR number is invalid or if gh pr view returns an empty HEAD_SHA. In that case actions/checkout will fall back to the default ref and you may deploy/comment against the wrong commit. Consider adding set -euo pipefail and explicit validation (non-empty PR_NUMBER and HEAD_SHA, with a clear error) before writing outputs.
.github/workflows/pages-preview.yml
Outdated
| if: >- | ||
| github.event_name == 'workflow_dispatch' || | ||
| github.event.pull_request.head.repo.full_name == github.repository |
There was a problem hiding this comment.
deploy-preview now runs unconditionally for workflow_dispatch, bypassing the existing same-repo guard. That makes it possible to deploy previews (using the Cloudflare token) for fork-based PRs if someone manually dispatches the workflow with that PR number. Consider enforcing the same-repo check for dispatch too (e.g., resolve headRepository.fullName in the metadata step and fail/skip when it doesn’t match github.repository, or add an explicit input to allow forks).
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/pages-preview.yml:
- Around line 41-53: The workflow reads PR_NUMBER from untrusted inputs and may
preserve leading zeros; sanitize and canonicalize PR_NUMBER after it's set in
the step with id "pr": validate it is an integer, strip any leading zeros to
produce a canonical decimal (e.g., "00123" -> "123"), and fail the job if the
result is empty or non-numeric; then write the sanitized PR_NUMBER to
GITHUB_OUTPUT (instead of the raw value) so downstream uses and cleanup keys
(e.g., the preview branch name) use the canonical form while leaving HEAD_SHA
handling unchanged.
- Around line 170-172: The current job conditional short-circuits eligibility
for manual runs; add a metadata step that resolves the pull_request state and
whether the head repo matches the target repo (set outputs like pr_state and
same_repo) and then change the job if to require those outputs for
workflow_dispatch as well (e.g. only proceed when
needs.metadata.outputs.pr_state == 'open' and needs.metadata.outputs.same_repo
== 'true'); update the conditional that currently uses
workflow_dispatch/pull_request head checks so both manual dispatches and PR
events are gated by the metadata outputs.
🪄 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
Run ID: 2460c43a-0a77-4cc2-81d4-b4e153e6cd93
📒 Files selected for processing (1)
.github/workflows/pages-preview.yml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Agent
- GitHub Check: Greptile Review
🧰 Additional context used
🪛 GitHub Actions: Workflow Security
.github/workflows/pages-preview.yml
[error] 46-46: template-injection: code injection via template expansion. PR_NUMBER expansion uses a potentially controllable expression '${{ github.event.pull_request.number || github.event.inputs.pr_number }}' which may expand into attacker-controlled code.
.github/workflows/pages-preview.yml
Outdated
| if: >- | ||
| github.event_name == 'workflow_dispatch' || | ||
| github.event.pull_request.head.repo.full_name == github.repository |
There was a problem hiding this comment.
Keep workflow_dispatch deploys limited to open, same-repo PRs.
Line 170 short-circuits the old eligibility checks for every manual run. That means a closed PR can get a fresh preview/comment even though cleanup-preview never runs for dispatch, and cross-repo PRs are no longer filtered out. Resolve the PR state/repo in the metadata step and gate this job on those outputs as well.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pages-preview.yml around lines 170 - 172, The current job
conditional short-circuits eligibility for manual runs; add a metadata step that
resolves the pull_request state and whether the head repo matches the target
repo (set outputs like pr_state and same_repo) and then change the job if to
require those outputs for workflow_dispatch as well (e.g. only proceed when
needs.metadata.outputs.pr_state == 'open' and needs.metadata.outputs.same_repo
== 'true'); update the conditional that currently uses
workflow_dispatch/pull_request head checks so both manual dispatches and PR
events are gated by the metadata outputs.
…ions
- Route all user-controlled inputs through env vars instead of inline
${{ }} interpolation in run blocks (fixes zizmor template-injection)
- Add pull-requests: read permission for gh pr view in build job
- Validate pr_number is a positive integer (rejects non-numeric and
leading zeros)
- Fail fast if gh pr view or HEAD SHA resolution fails
- Check PR is OPEN and same-repo on workflow_dispatch (prevents
deploying previews for closed or cross-repo PRs)
- Unify deploy-preview condition via same_repo job output
- Update CLAUDE.md PR Preview docs to reflect dispatch behavior
Addresses: zizmor CI failure, Greptile, Copilot, and CodeRabbit review
feedback (6 findings: 2 critical, 4 major)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/pages-preview.yml:
- Around line 43-88: The jq -r call extracting headRefOid can yield the literal
string "null" which bypasses the current empty check for HEAD_SHA; update the
logic around PR_JSON and the HEAD_SHA extraction (the jq -r '.headRefOid'
invocation and the subsequent HEAD_SHA variable) to treat both empty string and
the literal "null" as missing (e.g., after setting HEAD_SHA, test if HEAD_SHA is
empty or equals "null" and fail with the existing error path), and apply the
same "null" check pattern for any other jq-extracted variables you rely on (like
IS_CROSS_REPO or PR_STATE) so null JSON fields are treated as absent.
🪄 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
Run ID: b9c7898b-ce96-4679-a098-61ce613c355e
📒 Files selected for processing (2)
.github/workflows/pages-preview.ymlCLAUDE.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Greptile Review
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-03-12T11:06:11.009Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T11:06:11.009Z
Learning: NEVER create a PR directly with `gh pr create` — ALWAYS use `/pre-pr-review` to create PRs which runs automated checks + review agents + fixes before creating the PR
Applied to files:
.github/workflows/pages-preview.yml
📚 Learning: 2026-03-12T11:06:11.009Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-12T11:06:11.009Z
Learning: When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes), fix them all — no deferring or 'out of scope' skipping
Applied to files:
.github/workflows/pages-preview.yml
🔇 Additional comments (7)
.github/workflows/pages-preview.yml (6)
16-21: LGTM!The
workflow_dispatchtrigger with requiredpr_numberinput is well-defined for enabling manual previews of Dependabot PRs.
26-27: LGTM!The concurrency group correctly derives the PR number from either event type, ensuring stale builds are cancelled appropriately for both triggers.
202-205: LGTM!The deploy-preview job is now properly gated on
same_repo == 'true', addressing the earlier review concern. Combined with the OPEN-state validation in the build job (which fails fast for closed PRs), this ensures dispatch-triggered deploys are limited to open, same-repo PRs.
228-278: LGTM!The deploy and comment steps correctly consume PR metadata from build outputs. The
issue_numberfor the GitHub API call properly uses the resolvedprNumber, ensuring comments are posted to the correct PR regardless of trigger type.
284-287: LGTM!The cleanup job correctly guards against workflow_dispatch runs. Since dispatch events have no "close" action, limiting cleanup to
pull_requestevents is the right approach.
324-330: LGTM!Using
github.event.pull_request.numberdirectly is appropriate here since the cleanup job is gated topull_requestevents only (line 285), making the event context guaranteed to be available and trusted.CLAUDE.md (1)
184-194: Documentation accurately reflects the workflow changes.The updated PR Preview section correctly documents:
- The new
workflow_dispatchtrigger withpr_numberinput- Metadata resolution paths for both event types
- Validation rules and fail-fast behavior
- Same-repo gating for deploys
- Cleanup restriction to
pull_requestevents
| - name: Resolve PR metadata | ||
| id: pr | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| PR_INPUT: ${{ github.event.inputs.pr_number }} | ||
| PR_EVENT_NUMBER: ${{ github.event.pull_request.number }} | ||
| PR_EVENT_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
| PR_EVENT_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} | ||
| GH_REPOSITORY: ${{ github.repository }} | ||
| run: | | ||
| PR_NUMBER="${PR_EVENT_NUMBER:-$PR_INPUT}" | ||
| if ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then | ||
| echo "::error::PR number must be a positive integer, got: '$PR_NUMBER'" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ "$EVENT_NAME" = "workflow_dispatch" ]; then | ||
| PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$GH_REPOSITORY" \ | ||
| --json headRefOid,state,isCrossRepository) | ||
| if [ -z "$PR_JSON" ]; then | ||
| echo "::error::Failed to fetch metadata for PR #$PR_NUMBER" | ||
| exit 1 | ||
| fi | ||
| HEAD_SHA=$(echo "$PR_JSON" | jq -r '.headRefOid') | ||
| PR_STATE=$(echo "$PR_JSON" | jq -r '.state') | ||
| IS_CROSS_REPO=$(echo "$PR_JSON" | jq -r '.isCrossRepository') | ||
|
|
||
| if [ "$PR_STATE" != "OPEN" ]; then | ||
| echo "::error::PR #$PR_NUMBER is $PR_STATE, not OPEN — cannot deploy preview" | ||
| exit 1 | ||
| fi | ||
| SAME_REPO=$( [ "$IS_CROSS_REPO" = "false" ] && echo "true" || echo "false" ) | ||
| else | ||
| HEAD_SHA="$PR_EVENT_HEAD_SHA" | ||
| SAME_REPO=$( [ "$PR_EVENT_HEAD_REPO" = "$GH_REPOSITORY" ] && echo "true" || echo "false" ) | ||
| fi | ||
|
|
||
| if [ -z "$HEAD_SHA" ]; then | ||
| echo "::error::Failed to resolve HEAD SHA for PR #$PR_NUMBER" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | ||
| echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" | ||
| echo "same_repo=$SAME_REPO" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Well-implemented PR metadata resolution.
This addresses the security concerns from earlier reviews:
- Template injection mitigated: User-controlled inputs are routed through environment variables (
PR_INPUT,EVENT_NAME), preventing shell injection. - Leading zeros prevented: Regex
^[1-9][0-9]*$ensures canonical PR numbers (rejects00123). - Closed PRs rejected: Dispatch runs fail fast if PR is not
OPEN. - Cross-repo PRs filtered:
same_repooutput enables downstream gating.
One minor hardening suggestion: jq returns the literal string "null" for missing/null JSON fields, which would pass the empty check at line 81. Consider adding an explicit check:
🛡️ Optional hardening
+ if [ -z "$HEAD_SHA" ] || [ "$HEAD_SHA" = "null" ]; then
- if [ -z "$HEAD_SHA" ]; then
echo "::error::Failed to resolve HEAD SHA for PR #$PR_NUMBER"
exit 1
fi,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pages-preview.yml around lines 43 - 88, The jq -r call
extracting headRefOid can yield the literal string "null" which bypasses the
current empty check for HEAD_SHA; update the logic around PR_JSON and the
HEAD_SHA extraction (the jq -r '.headRefOid' invocation and the subsequent
HEAD_SHA variable) to treat both empty string and the literal "null" as missing
(e.g., after setting HEAD_SHA, test if HEAD_SHA is empty or equals "null" and
fail with the existing error path), and apply the same "null" check pattern for
any other jq-extracted variables you rely on (like IS_CROSS_REPO or PR_STATE) so
null JSON fields are treated as absent.
jq -r returns the string "null" for missing JSON fields, which would pass the empty-string check and cause checkout with an invalid ref.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if [ "$EVENT_NAME" = "workflow_dispatch" ]; then | ||
| PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$GH_REPOSITORY" \ | ||
| --json headRefOid,state,isCrossRepository) | ||
| if [ -z "$PR_JSON" ]; then | ||
| echo "::error::Failed to fetch metadata for PR #$PR_NUMBER" | ||
| exit 1 | ||
| fi | ||
| HEAD_SHA=$(echo "$PR_JSON" | jq -r '.headRefOid') | ||
| PR_STATE=$(echo "$PR_JSON" | jq -r '.state') | ||
| IS_CROSS_REPO=$(echo "$PR_JSON" | jq -r '.isCrossRepository') | ||
|
|
||
| if [ "$PR_STATE" != "OPEN" ]; then | ||
| echo "::error::PR #$PR_NUMBER is $PR_STATE, not OPEN — cannot deploy preview" | ||
| exit 1 | ||
| fi | ||
| SAME_REPO=$( [ "$IS_CROSS_REPO" = "false" ] && echo "true" || echo "false" ) | ||
| else |
There was a problem hiding this comment.
In workflow_dispatch runs, cross-repo PRs are not rejected—SAME_REPO is set to false, but the workflow still proceeds with the build job. This conflicts with the PR description/CLAUDE.md text that says cross-repo PRs are rejected. Either fail fast when isCrossRepository is true (exit 1) or update the documentation to say deploy is skipped for cross-repo PRs.
| - Builds site on PRs (same path triggers as Pages), injects "Development Preview" banner, deploys to Cloudflare Pages (`synthorg-pr-preview` project) via wrangler CLI | ||
| - Builds site on PRs (same path triggers as Pages) and on `workflow_dispatch` (with `pr_number` input, for Dependabot PRs that can't trigger `pull_request` with secrets) | ||
| - Dispatch runs resolve PR metadata (head SHA, state, same-repo check) via `gh pr view`; PR-triggered runs use event context directly | ||
| - Validates `pr_number` is a positive integer, rejects closed/cross-repo PRs on dispatch, and fails fast if HEAD SHA resolution fails |
There was a problem hiding this comment.
This bullet says dispatch runs "reject closed/cross-repo PRs", but the workflow currently only rejects non-OPEN PRs; cross-repo PRs still build and only skip deploy. Please align this documentation with the actual workflow behavior (or adjust the workflow to fail on cross-repo dispatch runs if that’s intended).
| - Validates `pr_number` is a positive integer, rejects closed/cross-repo PRs on dispatch, and fails fast if HEAD SHA resolution fails | |
| - Validates `pr_number` is a positive integer, rejects non-OPEN PRs on dispatch, and fails fast if HEAD SHA resolution fails |
| if [ -z "$PR_JSON" ]; then | ||
| echo "::error::Failed to fetch metadata for PR #$PR_NUMBER" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
Unreachable empty-JSON guard with set -euo pipefail
The if [ -z "$PR_JSON" ] guard is effectively unreachable in any failure path. With set -euo pipefail active, if gh pr view exits non-zero (e.g., PR not found, auth error, network failure), bash exits immediately during the command substitution — PR_JSON is never assigned, and execution never reaches the empty check. The custom ::error:: annotation will therefore never fire; the workflow will just exit with gh's own error output.
If you want the custom error message to appear, you need to suppress the exit or capture the exit code explicitly:
| if [ -z "$PR_JSON" ]; then | |
| echo "::error::Failed to fetch metadata for PR #$PR_NUMBER" | |
| exit 1 | |
| fi | |
| CURL_EXIT=0 | |
| PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$GH_REPOSITORY" \ | |
| --json headRefOid,state,isCrossRepository 2>&1) || CURL_EXIT=$? | |
| if [ "$CURL_EXIT" -ne 0 ] || [ -z "$PR_JSON" ]; then | |
| echo "::error::Failed to fetch metadata for PR #$PR_NUMBER (exit $CURL_EXIT)" | |
| exit 1 | |
| fi |
Or alternatively, simply remove the dead guard and rely on gh's own error output (which is already clear) plus the set -e exit.
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/pages-preview.yml
Line: 64-67
Comment:
**Unreachable empty-JSON guard with `set -euo pipefail`**
The `if [ -z "$PR_JSON" ]` guard is effectively unreachable in any failure path. With `set -euo pipefail` active, if `gh pr view` exits non-zero (e.g., PR not found, auth error, network failure), bash exits immediately during the command substitution — `PR_JSON` is never assigned, and execution never reaches the empty check. The custom `::error::` annotation will therefore never fire; the workflow will just exit with gh's own error output.
If you want the custom error message to appear, you need to suppress the exit or capture the exit code explicitly:
```suggestion
CURL_EXIT=0
PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$GH_REPOSITORY" \
--json headRefOid,state,isCrossRepository 2>&1) || CURL_EXIT=$?
if [ "$CURL_EXIT" -ne 0 ] || [ -z "$PR_JSON" ]; then
echo "::error::Failed to fetch metadata for PR #$PR_NUMBER (exit $CURL_EXIT)"
exit 1
fi
```
Or alternatively, simply remove the dead guard and rely on gh's own error output (which is already clear) plus the `set -e` exit.
How can I resolve this? If you propose a fix, please make it concise.| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | ||
| env: | ||
| PREVIEW_URL: "https://pr-${{ github.event.pull_request.number }}.synthorg-pr-preview.pages.dev" | ||
| PREVIEW_URL: "https://pr-${{ needs.build.outputs.pr_number }}.synthorg-pr-preview.pages.dev" |
There was a problem hiding this comment.
Inline ${{ }} expression in env: value for URL construction
${{ needs.build.outputs.pr_number }} is used inline within the YAML string value of the PREVIEW_URL env var. While the value is validated upstream as ^[1-9][0-9]*$ (digits only), this is still an inline template expansion. Since pr_number can only be digits at this point, there is no actual injection risk here — but for consistency with the safe pattern used in the build step's PR_INPUT env var, consider assembling the URL in the script itself:
| PREVIEW_URL: "https://pr-${{ needs.build.outputs.pr_number }}.synthorg-pr-preview.pages.dev" | |
| PREVIEW_URL: "" | |
| PR_NUMBER: ${{ needs.build.outputs.pr_number }} | |
| HEAD_SHA: ${{ needs.build.outputs.head_sha }} |
Then construct the URL in the script: block: const url = \https://pr-${prNumber}.synthorg-pr-preview.pages.dev\`;`. This is a minor consistency suggestion since pr_number is already digit-validated.
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/pages-preview.yml
Line: 237
Comment:
**Inline `${{ }}` expression in `env:` value for URL construction**
`${{ needs.build.outputs.pr_number }}` is used inline within the YAML string value of the `PREVIEW_URL` env var. While the value is validated upstream as `^[1-9][0-9]*$` (digits only), this is still an inline template expansion. Since `pr_number` can only be digits at this point, there is no actual injection risk here — but for consistency with the safe pattern used in the build step's `PR_INPUT` env var, consider assembling the URL in the script itself:
```suggestion
PREVIEW_URL: ""
PR_NUMBER: ${{ needs.build.outputs.pr_number }}
HEAD_SHA: ${{ needs.build.outputs.head_sha }}
```
Then construct the URL in the `script:` block: `const url = \`https://pr-${prNumber}.synthorg-pr-preview.pages.dev\`;`. This is a minor consistency suggestion since `pr_number` is already digit-validated.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
🤖 I have created a release *beep* *boop* --- ## [0.1.3](v0.1.2...v0.1.3) (2026-03-13) ### Features * add Mem0 memory backend adapter ([#345](#345)) ([2788db8](2788db8)), closes [#206](#206) * centralized single-writer TaskEngine with full CRUD API ([#328](#328)) ([9c1a3e1](9c1a3e1)) * incremental AgentEngine → TaskEngine status sync ([#331](#331)) ([7a68d34](7a68d34)), closes [#323](#323) * web dashboard pages — views, components, tests, and review fixes ([#354](#354)) ([b165ec4](b165ec4)) * web dashboard with Vue 3 + PrimeVue + Tailwind CSS ([#347](#347)) ([06416b1](06416b1)) ### Bug Fixes * harden coordination pipeline with validators, logging, and fail-fast ([#333](#333)) ([2f10d49](2f10d49)), closes [#205](#205) * repo-wide security hardening from ZAP, Scorecard, and CodeQL audit ([#357](#357)) ([27eb288](27eb288)) ### CI/CD * add pip-audit, hadolint, OSSF Scorecard, ZAP DAST, and pre-push hooks ([#350](#350)) ([2802d20](2802d20)) * add workflow_dispatch trigger to PR Preview for Dependabot PRs ([#326](#326)) ([4c7b6d9](4c7b6d9)) * bump astral-sh/setup-uv from 7.4.0 to 7.5.0 in the minor-and-patch group ([#335](#335)) ([98dd8ca](98dd8ca)) ### Maintenance * bump the minor-and-patch group across 1 directory with 3 updates ([#352](#352)) ([031b1c9](031b1c9)) * **deps:** bump devalue from 5.6.3 to 5.6.4 in /site in the npm_and_yarn group across 1 directory ([#324](#324)) ([9a9c600](9a9c600)) * migrate docs build from MkDocs to Zensical ([#330](#330)) ([fa8bf1d](fa8bf1d)), closes [#329](#329) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
workflow_dispatchtrigger topages-preview.ymlso PR previews can be manually triggered for Dependabot PRs (which don't getpull_requestevents with secrets access)pr_numberinput parameter and resolve PR metadata (head SHA) dynamically viagh pr viewfor dispatch runsgithub.event_name == 'pull_request'check so dispatch runs don't accidentally trigger cleanupTest plan
pull_requesttrigger still works as before (open/synchronize/close)pull_requestclose events, not on dispatchReview coverage
Quick mode (CI-only change, no Python code) — automated checks only, no agent review needed.