From 10efb47e1b1d2f5a36171166533a12e4082a1f68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:48:38 +0000 Subject: [PATCH 1/8] Handle update_pull_request branch permission errors as non-fatal Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 8 +++++++- actions/setup/js/update_pull_request.test.cjs | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index adac21ada2c..1321de282ff 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,7 +40,13 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head"); + return ( + message.includes("there are no new commits on the base branch") || + message.includes("merge conflict between base and head") || + message.includes("refusing to allow a github app to create or update workflow") || + message.includes("without `workflows` permission") || + message.includes("without workflows permission") + ); } /** diff --git a/actions/setup/js/update_pull_request.test.cjs b/actions/setup/js/update_pull_request.test.cjs index b33d7361847..3f78b385430 100644 --- a/actions/setup/js/update_pull_request.test.cjs +++ b/actions/setup/js/update_pull_request.test.cjs @@ -879,4 +879,24 @@ describe("update_pull_request.cjs - update_branch behavior", () => { }); expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("branch from base (non-fatal)")); }); + + it("should continue title/body updates when updateBranch is blocked by workflows permission", async () => { + mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(new Error("refusing to allow a GitHub App to create or update workflow `.github/workflows/test.lock.yml` without `workflows` permission")); + + const handler = await updatePRModule.main({ update_branch: true }); + const result = await handler({ + pull_request_number: 100, + title: "Updated PR", + }); + + expect(result.success).toBe(true); + expect(mockGithub.rest.pulls.updateBranch).toHaveBeenCalledTimes(1); + expect(mockGithub.rest.pulls.update).toHaveBeenCalledWith({ + owner: "testowner", + repo: "testrepo", + pull_number: 100, + title: "Updated PR", + }); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("branch from base (non-fatal)")); + }); }); From 2e83d6250c62b6819b52730bf7cd35822ea63100 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:51:14 +0000 Subject: [PATCH 2/8] Treat update_branch workflow-permission errors as non-fatal Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 1321de282ff..013d6d13660 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,13 +40,8 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - return ( - message.includes("there are no new commits on the base branch") || - message.includes("merge conflict between base and head") || - message.includes("refusing to allow a github app to create or update workflow") || - message.includes("without `workflows` permission") || - message.includes("without workflows permission") - ); + const hasWorkflowsPermissionError = message.includes("refusing to allow a github app to create or update workflow") || (message.includes("without") && message.includes("workflows") && message.includes("permission")); + return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } /** From 6623ed40a4c82ba5c63afde23f4b2c23f83de039 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:53:37 +0000 Subject: [PATCH 3/8] Refine workflows permission error matching for update_branch Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 013d6d13660..4d14893ed1f 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,7 +40,7 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - const hasWorkflowsPermissionError = message.includes("refusing to allow a github app to create or update workflow") || (message.includes("without") && message.includes("workflows") && message.includes("permission")); + const hasWorkflowsPermissionError = /refusing to allow.*workflow|without.*workflows.*permission/i.test(message); return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } From 8de97afe7a508c29bc0517786f07f9ac7b341ae4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:54:46 +0000 Subject: [PATCH 4/8] Tighten update_branch workflows-permission error detection Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 4d14893ed1f..ef270e4efb6 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,7 +40,7 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - const hasWorkflowsPermissionError = /refusing to allow.*workflow|without.*workflows.*permission/i.test(message); + const hasWorkflowsPermissionError = /refusing to allow a github app to create or update workflow|without\s+`?workflows`?\s+permission/i.test(message); return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } From a9c078078c68d69a0cddc1d32d0c7ace3d888196 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:55:59 +0000 Subject: [PATCH 5/8] Narrow workflow permission regex for update_branch failures Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index ef270e4efb6..44745be6600 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,7 +40,7 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - const hasWorkflowsPermissionError = /refusing to allow a github app to create or update workflow|without\s+`?workflows`?\s+permission/i.test(message); + const hasWorkflowsPermissionError = /refusing to allow a github app to create or update workflow .* without\s+`?workflows`?\s+permission|without\s+`?workflows`?\s+permission/i.test(message); return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } From ea5065077d850d31def069b38a180ca708cc4c4b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:56:56 +0000 Subject: [PATCH 6/8] Simplify update_branch workflows-permission failure detection Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 44745be6600..1cdd3234097 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -40,7 +40,9 @@ function isNonFatalUpdateBranchError(error) { // - cannot auto-update due to conflict ("merge conflict between base and head") // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); - const hasWorkflowsPermissionError = /refusing to allow a github app to create or update workflow .* without\s+`?workflows`?\s+permission|without\s+`?workflows`?\s+permission/i.test(message); + const hasWorkflowsPermissionPhrase = /without\s+`?workflows`?\s+permission/i.test(message); + const hasWorkflowMutationRefusal = message.includes("refusing to allow a github app to create or update workflow"); + const hasWorkflowsPermissionError = hasWorkflowsPermissionPhrase && (hasWorkflowMutationRefusal || message.includes("update pull request")); return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } From 59386edca7715fc5b3230f801d3403af5083248b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 20:57:54 +0000 Subject: [PATCH 7/8] Document non-fatal workflows permission matching intent Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 1cdd3234097..64d790fc217 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -42,6 +42,8 @@ function isNonFatalUpdateBranchError(error) { const message = getErrorMessage(error).toLowerCase(); const hasWorkflowsPermissionPhrase = /without\s+`?workflows`?\s+permission/i.test(message); const hasWorkflowMutationRefusal = message.includes("refusing to allow a github app to create or update workflow"); + // Require both permission wording and update-branch context to avoid treating unrelated + // "workflows permission" errors as non-fatal for pull request branch updates. const hasWorkflowsPermissionError = hasWorkflowsPermissionPhrase && (hasWorkflowMutationRefusal || message.includes("update pull request")); return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } From 2b8eb852f2f46d1244dba7154f3edb0edd6ad27b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 21:27:20 +0000 Subject: [PATCH 8/8] Handle workflow-permission 403 as non-fatal in update_branch Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/update_pull_request.cjs | 22 ++++++++++++------- actions/setup/js/update_pull_request.test.cjs | 6 +++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 64d790fc217..4944e62f34a 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -31,20 +31,26 @@ function isNonFatalUpdateBranchError(error) { status = candidateStatus; } } - if (status !== undefined && status !== 422) { - return false; - } - - // GitHub update-branch API can return these 422 messages for benign conditions: - // - already up to date ("There are no new commits on the base branch") - // - cannot auto-update due to conflict ("merge conflict between base and head") - // These should not fail safe output processing. const message = getErrorMessage(error).toLowerCase(); const hasWorkflowsPermissionPhrase = /without\s+`?workflows`?\s+permission/i.test(message); const hasWorkflowMutationRefusal = message.includes("refusing to allow a github app to create or update workflow"); // Require both permission wording and update-branch context to avoid treating unrelated // "workflows permission" errors as non-fatal for pull request branch updates. const hasWorkflowsPermissionError = hasWorkflowsPermissionPhrase && (hasWorkflowMutationRefusal || message.includes("update pull request")); + + if (status !== undefined) { + if (status === 403 && hasWorkflowsPermissionError) { + return true; + } + if (status !== 422) { + return false; + } + } + + // GitHub update-branch API can return these 422 messages for benign conditions: + // - already up to date ("There are no new commits on the base branch") + // - cannot auto-update due to conflict ("merge conflict between base and head") + // These should not fail safe output processing. return message.includes("there are no new commits on the base branch") || message.includes("merge conflict between base and head") || hasWorkflowsPermissionError; } diff --git a/actions/setup/js/update_pull_request.test.cjs b/actions/setup/js/update_pull_request.test.cjs index 3f78b385430..618fd88c2c8 100644 --- a/actions/setup/js/update_pull_request.test.cjs +++ b/actions/setup/js/update_pull_request.test.cjs @@ -880,8 +880,10 @@ describe("update_pull_request.cjs - update_branch behavior", () => { expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("branch from base (non-fatal)")); }); - it("should continue title/body updates when updateBranch is blocked by workflows permission", async () => { - mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(new Error("refusing to allow a GitHub App to create or update workflow `.github/workflows/test.lock.yml` without `workflows` permission")); + it("should continue title/body updates when updateBranch gets workflows-permission 403", async () => { + const permissionError = new Error("refusing to allow a GitHub App to create or update workflow `.github/workflows/test.lock.yml` without `workflows` permission"); + permissionError.status = 403; + mockGithub.rest.pulls.updateBranch.mockRejectedValueOnce(permissionError); const handler = await updatePRModule.main({ update_branch: true }); const result = await handler({