Skip to content

checkout_pr_branch: GitHub App bot actors are always refused since #63011 (collaborator permission API returns "none" for apps) #64788

Closed

Description

@jaroslawgajewski

Since github/gh-aw#63011 (shipped in v0.89.22), assertTrustedCheckoutRuntime() in actions/setup/js/checkout_pr_branch.cjs no longer short-circuits for sender.type === "Bot". Bot and app actors now go through the same repos.getCollaboratorPermissionLevel floor as users. For a GitHub App actor ([bot]), that endpoint returns HTTP 200 with permission: "none", not a 404. Apps are never repository collaborators, regardless of their installation permissions. So the new code takes the hasWriteOrHigher === false branch, and the 404 disambiguation added for bots never runs.

As a result, every PR opened or updated by a GitHub App fails at Checkout PR branch, including same-repository PRs from apps that have contents: write (they created the branch themselves).

Reproduction

pull_request-triggered gh-aw workflow (reusable via workflow_call, Copilot engine) that checks out the PR branch
PR opened by a GitHub App (sender.type: Bot), head.repo.id == base.repo.id, repository is not a fork
GET /repos/{owner}/{repo}/collaborators/%5Bbot%5D/permission → 200 {"permission":"none","role_name":""}
##[error]Error message: ERR_PERMISSION: Refusing PR checkout: actor '[bot]' has 'none' permission (requires write or higher)

Same workflow, repository and bot, three hours earlier on setup 924af5f (v0.89.21):

Runtime safety check passed for bot/app actor '[bot]' (sender type: Bot)
Is fork PR: false (same repository)

Root cause: in 65fe582 (github/gh-aw#63011) the if (senderType === "Bot") return; branch was removed and replaced by the comment "They still must satisfy the same repository permission floor". The intent is right, since sender.type alone should not be trusted. But a GitHub App can never meet the collaborator-permission floor, so for apps the check becomes "always refuse" rather than "verify".

Suggested fix: for pull_request / pull_request_target (and issue_comment on a PR, after the PR is fetched), when sender.type === "Bot", accept the actor if pull_request.head.repo.id === context.payload.repository.id. Creating or pushing to a branch in the base repository already requires write access to it. Cross-fork bot PRs and workflow_dispatch replays would still be refused. Checking the app's installation permissions isn't an option, because it needs an app JWT and can't be done with GITHUB_TOKEN.

Impact: repositories whose PRs come from automation apps lose every agentic workflow that checks out the PR branch. The job fails with no review and no comment, and consumers have no repository-side setting to fix it.

Versions: broken in v0.89.22, v0.90.0 and v0.90.1 (setup@7c1d4b7). Last working version: v0.89.21 (setup@924af5f). Upstream main still has the change as of 2026-10-01.

Activity

  1. locked and limited conversation to collaborators on Oct 1, 2026
  2. unlocked this conversation on Oct 1, 2026
  3. cgwalters commented on Oct 1, 2026

    @cgwalters

    We also hit this, a ton of LLM generated details in cgwalters-forge/gh-agentic-workflows#4 (comment)

  4. locked and limited conversation to collaborators on Oct 1, 2026
  5. unlocked this conversation on Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions