fix: create protected-file review issue when push fails due to workflows permission#20106
fix: create protected-file review issue when push fails due to workflows permission#20106
Conversation
…ows permission (#20098) When protected-files: fallback-to-issue is set and the patch touches workflow files, the push is rejected by GitHub because the App doesn't have the 'workflows' permission. Previously the catch block created a generic 'git push failed' issue and returned early, so the manifestProtectionFallback block (which creates the proper PR-intent issue) was never reached. Fix: in the push catch, when manifestProtectionFallback is set, store the error in manifestProtectionPushFailedError and fall through (don't create generic issue). The manifestProtectionFallback block then detects this and uses a new template that provides patch artifact download instructions instead of the compare URL (since the branch was not pushed). New template: manifest_protection_push_failed_fallback.md
There was a problem hiding this comment.
Pull request overview
Ensures that when protected-files: fallback-to-issue is enabled and git push fails (e.g., due to missing workflows permission), the action creates the intended protected-files review issue (with manual patch-apply instructions) instead of a generic “git push failed” fallback issue.
Changes:
- Adds a new protected-files push-failure fallback template that includes artifact download + manual PR creation steps.
- Updates
create_pull_requestto defer push-failure handling to the protected-files fallback block when protected-files fallback is active. - Extends protected-files fallback logic to choose between compare-URL vs. patch-download templates depending on whether the push succeeded.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| actions/setup/js/create_pull_request.cjs | Adjusts push-failure control flow so protected-files fallback produces a protected-files review issue with the appropriate instructions when push fails. |
| actions/setup/md/manifest_protection_push_failed_fallback.md | New issue-body template for protected-files scenarios where the branch could not be pushed; instructs downloading/applying the patch artifact and creating the PR manually. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (manifestProtectionFallback) { | ||
| // Push failed specifically for a protected-file modification. Don't create | ||
| // a generic push-failed issue — fall through to the manifestProtectionFallback | ||
| // block below, which will create the proper protected-file review issue with | ||
| // patch artifact download instructions (since the branch was not pushed). | ||
| core.warning("Git push failed for protected-file modification - deferring to protected-file review issue"); | ||
| manifestProtectionPushFailedError = pushError; | ||
| } else if (!fallbackAsIssue) { |
There was a problem hiding this comment.
The new push-failed protected-files path isn’t covered by tests. Since this changes control flow (skip generic push-failed issue and instead create the protected-files review issue using the new template when git push throws), add a unit/integration test that mocks exec.exec to throw on git push and asserts githubClient.rest.issues.create is called with the push-failed protected-files template body.
| > | ||
| > This was originally intended as a pull request, but the patch modifies protected files: {files}. | ||
| > | ||
| > The push was rejected because GitHub Actions does not have `workflows` permission to push these changes, and is never allowed to make such changes, or other authorization being used does not have this permission. A human must create the pull request manually. |
There was a problem hiding this comment.
This message hard-codes the cause as missing workflows permission, but the code selects this template for any push failure when protected-files fallback is active. To avoid misleading reviewers, either (a) make the wording generic (e.g., permission denied / push rejected) or (b) add a placeholder for the actual push error and render it into the issue body.
| > The push was rejected because GitHub Actions does not have `workflows` permission to push these changes, and is never allowed to make such changes, or other authorization being used does not have this permission. A human must create the pull request manually. | |
| > The push was rejected while trying to apply these changes. This can happen if GitHub Actions or the authorization being used does not have sufficient permissions (for example, missing `workflows` permission), or due to another push error. A human must create the pull request manually. | |
| > | |
| > If available, the underlying push error is: | |
| > | |
| > ```text | |
| > {push_error} | |
| > ``` |
| # Create a new branch | ||
| git checkout -b {branch_name} {base_branch} | ||
|
|
There was a problem hiding this comment.
git checkout -b {branch_name} {base_branch} assumes {base_branch} exists locally. For users following these instructions in a fresh clone, it’s safer to fetch and base the branch off the remote ref (e.g., origin/{base_branch}) to avoid a checkout failure or creating the branch from the wrong commit.
| # Create a new branch | |
| git checkout -b {branch_name} {base_branch} | |
| # Fetch the latest base branch from origin | |
| git fetch origin {base_branch} | |
| # Create a new branch from the remote base branch | |
| git checkout -b {branch_name} origin/{base_branch} |
| if (manifestProtectionFallback) { | ||
| // Push failed specifically for a protected-file modification. Don't create | ||
| // a generic push-failed issue — fall through to the manifestProtectionFallback | ||
| // block below, which will create the proper protected-file review issue with | ||
| // patch artifact download instructions (since the branch was not pushed). | ||
| core.warning("Git push failed for protected-file modification - deferring to protected-file review issue"); | ||
| manifestProtectionPushFailedError = pushError; |
There was a problem hiding this comment.
This branch defers to the protected-files review issue for any git push failure when manifestProtectionFallback is set, but the later template/text assumes a permission-related rejection. If the push fails for other reasons (network/auth/remote errors), this will create a misleading protected-files issue and skip the existing generic push-failed fallback. Consider gating this path on the specific workflows-permission rejection message (or include the actual push error in the protected-files issue/template and keep using the generic fallback for non-permission push failures).
| # Push the branch and create the pull request | ||
| git push origin {branch_name} | ||
| gh pr create --title '{title}' --base {base_branch} --head {branch_name} --repo {repo} |
There was a problem hiding this comment.
The shell command in this template embeds the unescaped title value directly into gh pr create --title '{title}' ..., which allows shell command injection if title contains a single quote or other shell metacharacters. An attacker who can influence the pull request title (via the create_pull_request tool call) could craft a value like Fix bug'; rm -rf / # so that when a maintainer copy-pastes this snippet into a shell, the injected command executes on their machine. To mitigate this, ensure title is properly shell-escaped before substitution or avoid inserting untrusted values directly into shell commands (e.g., instruct users to supply/edit the title argument manually).
| # Push the branch and create the pull request | |
| git push origin {branch_name} | |
| gh pr create --title '{title}' --base {base_branch} --head {branch_name} --repo {repo} | |
| # Push the branch and create the pull request (you will be prompted to enter the title and description) | |
| git push origin {branch_name} | |
| gh pr create --base {base_branch} --head {branch_name} --repo {repo} |
Fixes #20103
Problem
When
protected-files: fallback-to-issueis configured and the agent patch touches a.github/workflows/file, GitHub rejects the push because the App lacksworkflowspermission:The
catchblock handling this push failure created a generic "git push failed" fallback issue and returned early — so themanifestProtectionFallbackblock that creates the proper PR-intent issue was never reached.Fix
In the push
catchblock, whenmanifestProtectionFallbackis set, the error is stored inmanifestProtectionPushFailedErrorand the function falls through instead of creating a generic issue. ThemanifestProtectionFallbackblock detectsmanifestProtectionPushFailedErrorand uses a new template (manifest_protection_push_failed_fallback.md) that provides patch artifact download + manual PR creation instructions, since the branch was never pushed.Before: Generic "git push failed" issue with no actionable instructions.
After: Protected-files review issue with copy-paste commands to download the patch artifact and create the PR manually.
Example output
The issue body now reads: