Skip to content

fix: create protected-file review issue when push fails due to workflows permission#20106

Merged
dsyme merged 2 commits intomainfrom
fix/protected-files-push-fallback
Mar 8, 2026
Merged

fix: create protected-file review issue when push fails due to workflows permission#20106
dsyme merged 2 commits intomainfrom
fix/protected-files-push-fallback

Conversation

@dsyme
Copy link
Contributor

@dsyme dsyme commented Mar 8, 2026

Fixes #20103

Problem

When protected-files: fallback-to-issue is configured and the agent patch touches a .github/workflows/ file, GitHub rejects the push because the App lacks workflows permission:

! [remote rejected] repo-assist/eng-ci-cache-... (refusing to allow a GitHub App
  to create or update workflow .github/workflows/dotnet.yml without workflows permission)
error: failed to push some refs

The catch block handling this push failure created a generic "git push failed" fallback issue and returned early — so the manifestProtectionFallback block that creates the proper PR-intent issue was never reached.

Fix

In the push catch block, when manifestProtectionFallback is set, the error is stored in manifestProtectionPushFailedError and the function falls through instead of creating a generic issue. The manifestProtectionFallback block detects manifestProtectionPushFailedError and 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:

⚠️ Protected Files — Push Permission Denied

This was originally intended as a pull request, but the patch modifies protected files: .github/workflows/dotnet.yml.

The push was rejected because the GitHub App does not have workflows permission. A human must create the pull request manually.

gh run download {run_id} -n agent-artifacts ...
git am --3way ...
gh pr create ...

…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
Copilot AI review requested due to automatic review settings March 8, 2026 18:29
@dsyme dsyme merged commit 32c7af7 into main Mar 8, 2026
49 checks passed
@dsyme dsyme deleted the fix/protected-files-push-fallback branch March 8, 2026 18:35
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

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_request to 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.

Comment on lines +754 to +761
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) {
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

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.

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

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
> 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}
> ```

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +20
# Create a new branch
git checkout -b {branch_name} {base_branch}

Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
# 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}

Copilot uses AI. Check for mistakes.
Comment on lines +754 to +760
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;
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +26
# 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}
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

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).

Suggested change
# 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}

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.

Change to protected file not correctly using a fallback issue

2 participants