Skip to content

create_pull_request: create fallback issue with one-click PR link on permission error#19466

Merged
dsyme merged 2 commits intomainfrom
copilot/fix-github-actions-permissions
Mar 3, 2026
Merged

create_pull_request: create fallback issue with one-click PR link on permission error#19466
dsyme merged 2 commits intomainfrom
copilot/fix-github-actions-permissions

Conversation

Copy link
Contributor

Copilot AI commented Mar 3, 2026

When GitHub Actions lacks permission to create PRs, the handler was delegating to the conclusion job to create a generic "fix your settings" issue — leaving the already-pushed branch with no easy path to a PR.

Changes

  • create_pull_request.cjs: On "GitHub Actions is not permitted to create or approve pull requests" error, instead of setting an error output for the conclusion job, immediately create a fallback issue containing:

    • A one-click GitHub compare URL pre-populated with branch, base, and title so the user can open the PR directly
    • Instructions to fix the permissions setting
    • Patch preview (same as other fallback paths)
    • Returns { success: true, fallback_used: true } — consistent with push-failure fallback behavior
    • Only returns error_type: "permission_denied" if the fallback issue creation also fails
  • create_pull_request.test.cjs: Updated error type documentation to reflect that permission_denied is now the double-failure case, not the primary path

The compare URL format used:

https://github.com/{owner}/{repo}/compare/{base}...{head}?expand=1&title={encoded_title}

Branch path segments are individually encodeURIComponent-encoded to preserve / while safely encoding other special characters.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://v-api-github-com.286600.xyz/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE x_amd64/link git rev-�� --show-toplevel x_amd64/link (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha user.name Test User /usr/bin/git /tmp/go-build180git -trimpath 64/bin/go git bran�� /git/ref/tags/v8 go /usr/bin/git -json GO111MODULE x_amd64/vet git (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha runs/20260303-230327-27821/test-3680450890 /tmp/go-build3373587953/b153/vet.cfg /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet 12f9de6d07e84c14git GO111MODULE 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -ato�� -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --git-dir x_amd64/vet /usr/bin/git -json GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git -json GO111MODULE x_amd64/vet git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha pload-artifact/git/ref/tags/v7 64/pkg/tool/linux_amd64/vet /usr/bin/infocmp -json .cfg 64/pkg/tool/linu--show-toplevel infocmp -1 xterm-color 64/pkg/tool/linu--jq /usr/bin/git 34/001/test-frongit GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha user.name 3587953/b419/_testmain.go /usr/bin/git k/gh-aw/gh-aw/tmgit GOPROXY 64/bin/go git conf�� --get remote.origin.url ache/node/24.13.1/x64/bin/node /tmp/go-build180git -trimpath 64/bin/go ache/node/24.13.1/x64/bin/node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel -tests .cfg k/gh-aw/gh-aw/ingit GOPROXY 64/bin/go node t-11�� k/gh-aw/gh-aw/.github/workflows/archie.md /opt/hostedtoolc-buildtags /usr/bin/git erignore node 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel 64/pkg/tool/linuremote.origin.url /usr/bin/git 1394736971/.githgit .cfg x_amd64/link git rev-�� --show-toplevel x_amd64/link /usr/bin/git -json .cfg 64/pkg/tool/linu--show-toplevel git (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/download-artifact/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha -json GO111MODULE .cfg GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet env 3954978893 GO111MODULE .cfg GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linuremote.origin.url (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha se 3587953/b116/vet.cfg 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha g/sliceutil/sliceutil.go g/sliceutil/sliceutil_test.go ache/go/1.25.0/x64/pkg/tool/linu-nilfunc GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linu-tests -ato�� 3587953/b416/_pkg_.a -buildtags 3587953/b416=> -errorsas -ifaceassert -nilfunc /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha a820/Vgx0-6pZlp3GOSUMDB GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 05041/b419/impor/tmp/go-build3373587953/b164/vet.cfg /hom�� k/gh-aw/gh-aw/scripts/lint_errorGOINSECURE k/gh-aw/gh-aw/scripts/lint_errorGOMOD 64/bin/go **/*.json --ignore-path ../../../.pretti-bool /opt/hostedtoolc-buildtags (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha "prettier" --che-errorsas GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go git -c log.showsignature=false log 64/bin/go -n1 --format=format:-atomic fa4d8cac0e29 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha "prettier" --check '**/*.cjs' '*GOINSECURE ache/go/1.25.0/x64/src/internal/GOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc/tmp/go-build3373587953/b252/vet.cfg -o /tmp/go-build18005041/b355/_pkg_GOINSECURE -trimpath 64/bin/go -d main -lang=go1.25 go (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /tmp/compile-all-instructions-test-3941169603/.github/workflows rev-parse /usr/bin/git k/gh-aw/gh-aw/pkgit GOPROXY 64/bin/go git conf�� --get remote.origin.url ache/node/24.13.1/x64/bin/node /tmp/go-build180git -trimpath 64/bin/go ache/node/24.13.1/x64/bin/node (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha --get remote.origin.url /usr/bin/git go1.25.0 -c=4 -nolocalimports git conf�� user.name Test User ache/node/24.13.1/x64/bin/node -x c 64/bin/go ache/node/24.13.1/x64/bin/node (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -uns�� runs/20260303-230327-27821/test-2769033660/.github/workflows /tmp/go-build3373587953/b048/vet.cfg 3587953/b361/vet.cfg GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/actions/upload-artifact/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json GO111MODULE .cfg GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha VJ7UPr85U .cfg x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env ternal/tools/actions-build/main.go GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE Fj/loOf-cgjR6MKz0XVD7GS/mRL0tEU7JbrieQ94-F8q (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linu--jq env -json GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linuTest User (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE NB/VEeUdPO-3zV62hIVkQ_S/w6VgqTMxz0Q0X6nB667n (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json c5f51644:go.mod 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 4X/C061xVfYOKCjcDjyPxD-/1pjaMAEPwhrn9NjtCOgd (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env ty-test.md GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE 64/pkg/tool/linu-test.short=true GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet estl�� -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path ." GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 05041/b384/impor-buildtags /opt�� che/go-build/5a/-errorsas --check 64/bin/go --ignore-path .prettierignore 64/bin/go /opt/hostedtoolc-buildtags (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 on 64/bin/go go list�� -m -json 64/bin/go npx prettier --w/usr/bin/git (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha tmatter-with-arr.github/workflows/test.md GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 4206918492/.github/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env hub/workflows .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://v-api-github-com.286600.xyz/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOSUMDB GOWORK 64/bin/go sh -c "prettier" --che-errorsas sh 64/bin/go npx prettier --w/opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet on 64/bin/go go (http block)
  • https://v-api-github-com.286600.xyz/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build3373587953/b383/cli.test /tmp/go-build3373587953/b383/cli.test -test.testlogfile=/tmp/go-build3373587953/b383/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE 05041/b381/impor/tmp/go-build3373587953/b145/vet.cfg -c pkg/mod/github.com/stretchr/testGOINSECURE pkg/mod/github.com/stretchr/testGOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc/tmp/go-build3373587953/b266/vet.cfg (http block)
  • https://v-api-github-com.286600.xyz/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name tions-lock.json pkg/workflow/data/action_pins.json; \ echo "��� Action pins syn/tmp/go-build3373587953/b397/importcfg GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 05041/b402/impor-buildtags /opt�� k/gh-aw/gh-aw/pk-errorsas k/gh-aw/gh-aw/pk-ifaceassert 64/bin/go --ignore-path .prettierignore 64/bin/go /opt/hostedtoolc-buildtags (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>"GitHub Actions is not permitted to create or approve pull requests."</issue_title>
<issue_description>When the safe output handler for create_pull_request gets the error "GitHub Actions is not permitted to create or approve pull requests." it should instead push the branch (will already have been done) and create an issue populated with a create-a-pr incoming intent link to https://github.com/github/gh-aw/pulls/new with the right query parameters to pre-populate the branch, title etc.

https://github.com///pulls/new?title=...&body=...&base=...&head=...

check those query params, also check if labels can be added.</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

…cks PR permissions

When the create_pull_request safe output handler encounters the "GitHub Actions
is not permitted to create or approve pull requests" error, instead of setting
an error output for the conclusion job (which created a settings-fix issue),
it now:

1. Creates a fallback issue (branch has already been pushed at this point)
2. Includes a link to GitHub's compare URL pre-populated with title and branch
   info so the user can create the PR with one click
3. Returns success=true with fallback_used=true (consistent with other fallback paths)
4. Properly URL-encodes all path segments in the compare URL

If the fallback issue creation also fails, returns error_type: "permission_denied".

Co-authored-by: dsyme <7204669+dsyme@users.noreply.github.com>
Copilot AI changed the title [WIP] Handle GitHub Actions permission error for creating PRs create_pull_request: create fallback issue with one-click PR link on permission error Mar 3, 2026
Copilot finished work on behalf of dsyme March 3, 2026 23:06
@dsyme dsyme marked this pull request as ready for review March 3, 2026 23:28
Copilot AI review requested due to automatic review settings March 3, 2026 23:28
@dsyme dsyme merged commit 99b2107 into main Mar 3, 2026
108 checks passed
@dsyme dsyme deleted the copilot/fix-github-actions-permissions branch March 3, 2026 23:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the create_pull_request handler to handle GitHub Actions PR-creation permission errors by creating an immediate fallback issue that includes a one-click “create PR” link, rather than delegating to a conclusion job.

Changes:

  • On “GitHub Actions is not permitted to create or approve pull requests” errors, create a fallback issue with a compare URL and patch preview, returning { success: true, fallback_used: true } when successful.
  • Only return error_type: "permission_denied" when both PR creation and fallback issue creation fail.
  • Update test documentation/comments to reflect the revised permission_denied semantics.

Reviewed changes

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

File Description
actions/setup/js/create_pull_request.cjs Adds permission-error-specific fallback issue creation with a one-click PR link and updated return semantics.
actions/setup/js/create_pull_request.test.cjs Updates documented error-type expectations for the permission-denied path.
Comments suppressed due to low confidence (1)

actions/setup/js/create_pull_request.cjs:1042

  • This new permission-denied path changes behavior significantly (create fallback issue + return { success: true, fallback_used: true }). There isn't a unit/integration test covering (1) permission error -> issues.create called with a body containing the one-click link and patch preview, and (2) double-failure (issue creation fails) -> error_type: "permission_denied". Adding tests for these cases would prevent regressions in this error-handling flow.
      // Check if the error is the specific "GitHub actions is not permitted to create or approve pull requests" error
      if (errorMessage.includes("GitHub Actions is not permitted to create or approve pull requests")) {
        core.error("Permission error: GitHub Actions is not permitted to create or approve pull requests");

        // Branch has already been pushed - create a fallback issue with a link to create the PR via GitHub UI
        const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com";
        // Encode branch name path segments individually to preserve '/' while encoding other special characters
        const encodedBase = baseBranch.split("/").map(encodeURIComponent).join("/");
        const encodedHead = branchName.split("/").map(encodeURIComponent).join("/");
        const createPrUrl = `${githubServer}/${repoParts.owner}/${repoParts.repo}/compare/${encodedBase}...${encodedHead}?expand=1&title=${encodeURIComponent(title)}`;

        // Read patch content for preview
        let patchPreview = "";
        if (patchFilePath && fs.existsSync(patchFilePath)) {
          const patchContent = fs.readFileSync(patchFilePath, "utf8");
          patchPreview = generatePatchPreview(patchContent);
        }

        const fallbackBody =
          `${body}\n\n---\n\n` +
          `> [!NOTE]\n` +
          `> This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.\n` +
          `> The changes have been pushed to branch \`${branchName}\`.\n` +
          `>\n` +
          `> **[Click here to create the pull request](${createPrUrl})**\n\n` +
          `To fix the permissions issue, go to **Settings** → **Actions** → **General** and enable **Allow GitHub Actions to create and approve pull requests**.` +
          patchPreview;

        try {
          const { data: issue } = await githubClient.rest.issues.create({
            owner: repoParts.owner,
            repo: repoParts.repo,
            title: title,
            body: fallbackBody,
            labels: mergeFallbackIssueLabels(labels),
          });

          core.info(`Created fallback issue #${issue.number}: ${issue.html_url}`);

          await updateActivationComment(github, context, core, issue.html_url, issue.number, "issue");

          return {
            success: true,
            fallback_used: true,
            issue_number: issue.number,
            issue_url: issue.html_url,
            branch_name: branchName,
            repo: itemRepo,
          };
        } catch (issueError) {
          const error = `Failed to create pull request (permission denied) and failed to create fallback issue. PR error: ${errorMessage}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`;
          core.error(error);
          return {
            success: false,
            error,
            error_type: "permission_denied",
          };

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

Comment on lines +997 to +1002
// Read patch content for preview
let patchPreview = "";
if (patchFilePath && fs.existsSync(patchFilePath)) {
const patchContent = fs.readFileSync(patchFilePath, "utf8");
patchPreview = generatePatchPreview(patchContent);
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This block duplicates logic that already exists in the generic PR-creation fallback immediately below (reading patchFilePath for patchPreview, constructing a fallback issue body, and creating the issue). Consider extracting shared helpers for building the fallback issue body / reading the patch preview so the different fallback paths don't drift over time.

This issue also appears on line 986 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +992 to +995
// Encode branch name path segments individually to preserve '/' while encoding other special characters
const encodedBase = baseBranch.split("/").map(encodeURIComponent).join("/");
const encodedHead = branchName.split("/").map(encodeURIComponent).join("/");
const createPrUrl = `${githubServer}/${repoParts.owner}/${repoParts.repo}/compare/${encodedBase}...${encodedHead}?expand=1&title=${encodeURIComponent(title)}`;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The compare URL path format uses ... as a delimiter (/compare/{base}...{head}), but branch names are allowed to contain . and can include the sequence .... In that case the generated URL becomes ambiguous/broken because encodeURIComponent does not escape .. Consider switching to the pulls/new?base=...&head=... URL format (which avoids the delimiter), or explicitly percent-encoding . in the encoded base/head refs so ... can only appear as the separator.

Suggested change
// Encode branch name path segments individually to preserve '/' while encoding other special characters
const encodedBase = baseBranch.split("/").map(encodeURIComponent).join("/");
const encodedHead = branchName.split("/").map(encodeURIComponent).join("/");
const createPrUrl = `${githubServer}/${repoParts.owner}/${repoParts.repo}/compare/${encodedBase}...${encodedHead}?expand=1&title=${encodeURIComponent(title)}`;
const encodedBase = encodeURIComponent(baseBranch);
const encodedHead = encodeURIComponent(branchName);
const encodedTitle = encodeURIComponent(title);
const createPrUrl = `${githubServer}/${repoParts.owner}/${repoParts.repo}/pulls/new?base=${encodedBase}&head=${encodedHead}&title=${encodedTitle}`;

Copilot uses AI. Check for mistakes.
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.

"GitHub Actions is not permitted to create or approve pull requests."

3 participants