Skip to content

fix(workflows): repair squad-heartbeat 403 on fork PR close - #2155

Merged
tamirdresher merged 3 commits into
github:devfrom
tamirdresher:fix/heartbeat-fork-pr-permissions
Oct 2, 2026
Merged

tamirdresher merged 3 commits into
github:devfrom
tamirdresher:fix/heartbeat-fork-pr-permissions

Conversation

@tamirdresher

Copy link
Copy Markdown
Collaborator

Root cause

.github/workflows/squad-heartbeat.yml (and its 4 synced template copies) use:

on:
  pull_request:
    types: [closed]

For pull_request events triggered by a fork PR, GitHub forces GITHUB_TOKEN to read-only regardless of the workflow''s declared permissions: block. The "Ralph — Repair orphaned squad labels" step calls issues.listForRepo then issues.addLabels, which 403s whenever a fork PR closes.

Evidence: failed runs 37045805429 and 37036858649, both triggered by the pull_request: closed event from fork PR #2150 (head fb31ec7e), failing at POST /issues/2074/labels with 403 Resource not accessible by integration.

Fix

Switch the trigger from pull_request to pull_request_target in all 5 synced copies:

  • .github/workflows/squad-heartbeat.yml
  • templates/workflows/squad-heartbeat.yml
  • packages/squad-cli/templates/workflows/squad-heartbeat.yml
  • packages/squad-sdk/templates/workflows/squad-heartbeat.yml
  • .squad-templates/workflows/squad-heartbeat.yml

pull_request_target runs with base-repo token permissions regardless of fork origin, fixing the 403.

Why this is safe

pull_request_target is normally risky because it can combine elevated permissions with untrusted fork code execution. That risk does not apply here:

  • The actions/checkout step has no ref: override anywhere in the file — it always checks out the base ref, never the fork head.
  • No step reads or executes anything from the triggering PR''s diff/content; the label-repair step does a repo-wide issues.listForRepo scan, and the triage script (ralph-triage.js) is base-repo-owned code.

scripts/security-review.mjs (which specifically flags pull_request_target + fork-head checkout as a warning) reports zero findings against this change:

$ node scripts/security-review.mjs origin/dev HEAD
{ "findings": [], "summary": "✅ No security concerns found." }

Validation

  • All 5 modified YAML files parsed successfully (yaml.safe_load), confirmed on: triggers are now issues, pull_request_target, workflow_dispatch.
  • node scripts/security-review.mjs origin/dev HEAD → no findings.
  • No issue number exists for this bug yet; this PR is evidence-driven (the two failing run IDs above).

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Fork PRs trigger GITHUB_TOKEN read-only enforcement under the plain
pull_request event, so the 'Ralph - Repair orphaned squad labels' step's
issues.addLabels call 403s whenever a fork PR is closed (observed in
runs 37045805429 and 37036858649).

Switch the pull_request trigger to pull_request_target in all 5 synced
copies of squad-heartbeat.yml. This is safe here specifically because:
  - the checkout step has no ref: override, so it always checks out the
    base ref, never the fork head
  - no script in this workflow reads or executes fork-sourced content;
    the label-repair and triage steps only operate on repo-side state

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 21:31
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #2155

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 6
Files added 1
Files modified 5
Files deleted 0
Modules touched 5

🎯 Risk Factors

  • 6 files changed (6-20 → MEDIUM)
  • 5 modules touched (5-8 → HIGH)

📦 Modules Affected

ci-workflows (1 file)
  • .github/workflows/squad-heartbeat.yml
root (2 files)
  • .changeset/2155-heartbeat-fork-pr-labels.md
  • templates/workflows/squad-heartbeat.yml
squad-cli (1 file)
  • packages/squad-cli/templates/workflows/squad-heartbeat.yml
squad-sdk (1 file)
  • packages/squad-sdk/templates/workflows/squad-heartbeat.yml
templates (1 file)
  • .squad-templates/workflows/squad-heartbeat.yml

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 25f9d36

PR Scope: 🔧 Infrastructure

⚠️ 4 item(s) to address before review

Status Check Details
❌ Single commit 3 commits — consider squashing before review
✅ Not in draft Ready for review
✅ Branch up to date Up to date with dev
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean No .squad/ or docs/proposals/ files
✅ No merge conflicts No merge conflicts
❌ Copilot threads resolved 1 unresolved Copilot thread(s) — fix and resolve before merging
❌ CI passing 12 check(s) still running

Files Changed (6 files, +45 −5)

File +/−
.changeset/2155-heartbeat-fork-pr-labels.md +10 −0
.github/workflows/squad-heartbeat.yml +7 −1
.squad-templates/workflows/squad-heartbeat.yml +7 −1
packages/squad-cli/templates/workflows/squad-heartbeat.yml +7 −1
packages/squad-sdk/templates/workflows/squad-heartbeat.yml +7 −1
templates/workflows/squad-heartbeat.yml +7 −1

Total: +45 −5


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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.

🟡 Changes recommended

The required changeset is missing, causing the Changelog Gate to fail.

2 open findings
What changed in this PR

Switches Squad Heartbeat to pull_request_target, enabling label repairs after fork PRs close while continuing to execute base-branch code only.

Changes:

  • Replaces pull_request with pull_request_target.
  • Synchronizes the trigger and safety rationale across all workflow copies.
File Description
.github/​workflows/​squad-heartbeat.yml Updates the active workflow trigger.
.squad-templates/​workflows/​squad-heartbeat.yml Updates the canonical template.
templates/​workflows/​squad-heartbeat.yml Synchronizes the root template.
packages/​squad-cli/​templates/​workflows/​squad-heartbeat.yml Synchronizes the CLI template.
packages/​squad-sdk/​templates/​workflows/​squad-heartbeat.yml Synchronizes the SDK template.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

# Safe here because the checkout step below has no `ref:` override, so it
# always checks out the BASE ref — no fork code or fork-controlled input
# is ever read or executed by this job.
pull_request_target:
pull_request:
# pull_request_target (not pull_request): GITHUB_TOKEN is forced read-only
# for `pull_request` events triggered by a fork, so write steps below
# (addLabels/createComment) 403 on fork PR closes (#2080-class bug).
@tamirdresher
tamirdresher merged commit aa2dc2d into github:dev Oct 2, 2026
19 checks passed
tamirdresher added a commit to tamirdresher/squad that referenced this pull request Oct 2, 2026
)

fix(workflows): repair squad-heartbeat 403 on fork PR close
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