Thanks to visit codestin.com
Credit goes to github.com

Skip to content

create-pull-request: protected-files fallback-to-issue + bundle transport drops the branch (no link in fallback issue) #33605

@boydj

Description

@boydj

create-pull-request with protected-files: fallback-to-issue + bundle transport drops the branch — fallback issue has no link

Summary

When safe-outputs.create-pull-request is configured with
protected-files: fallback-to-issue and the default patch-format: bundle
transport, gh-aw skips the branch push as soon as the protected-files
fallback is triggered, then routes the fallback issue through the
"push-failed" template. The resulting review issue contains no link to
the agent's branch and no compare URL — only a copy-paste git am
recipe — so a human reviewer has no way to inspect the actual changes
on GitHub without manually downloading the patch artifact via
gh run download.

To be clear: the desired outcome is not to auto-create the PR.
fallback-to-issue should still create the issue (no PR). What's
broken is that the agent's branch is never pushed to origin, so the
issue can't link to it and reviewers can't view the diff in the
GitHub UI. The branch should be pushed; only the PR creation should
be replaced with an issue.

The non-bundle (patch-format: am) path does the right thing: it pushes
the branch first, then renders the normal fallback template with a
"Click here to create the pull request" compare URL — note the link is
a prefilled compare URL, not an automatic PR creation. A human still
clicks through to create the PR after reviewing the branch.

Why this matters

fallback-to-issue is the documented escape hatch for letting an agent
propose changes to manifests/CI files without hard-blocking the run. The
whole point is that a human can review the proposed change in GitHub's
diff UI before promoting it to a PR. Under the bundle transport, that
review surface never gets built — the branch isn't pushed, so there's
nothing to compare against. The resulting issue effectively says "trust
me, run these git commands locally," which defeats the safety story.

Multi-commit agent changes (and the merge-commit topology that the
bundle transport was specifically designed to preserve, per the schema
docs) are unreachable for any workflow that also wants
protected-files: fallback-to-issue. Today the only working
combination is patch-format: am, which trades away exactly the
properties bundle was added for.

Reproduction

Workflow frontmatter:

safe-outputs:
  create-pull-request:
    max: 1
    draft: true
    protected-files: fallback-to-issue
    # patch-format: bundle  ← default, bug appears here

Trigger the workflow with an agent prompt that modifies any default
protected file (e.g. README.md, requirements.txt, package.json).

Observed: a review issue is created with body rendered from
manifest_protection_push_failed_fallback.md. The body contains
gh run download <run_id> instructions and no branch URL or compare
URL. The branch is not on origin.

Expected: a review issue rendered from
manifest_protection_create_pr_fallback.md, with a clickable compare
URL pointing at the pushed agent branch.

Concrete example (cautious-spoon issue #11 in our internal GHES instance,
with patch-format unset → defaulted to bundle): the agent modified
README.md and requirements.txt, the branch was never pushed, the
fallback issue had no link.

Root cause

In actions/setup/js/create_pull_request.cjs, the bundle path
short-circuits the push when manifestProtectionFallback is set:

// create_pull_request.cjs:1485-1488
// Push the commits from the bundle to the remote branch
if (manifestProtectionFallback) {
  core.info(
    "Skipping branch push because protected-files fallback-to-issue was triggered",
  );
  manifestProtectionPushFailedError = new Error(
    "Push skipped because protected-files fallback-to-issue was triggered",
  );
} else {
  // ... pushSignedCommits(...) ...
}

Setting manifestProtectionPushFailedError then steers the issue body
selector at line ~1962 to the push-failed template:

// create_pull_request.cjs:1962-1984
let fallbackBody;
if (manifestProtectionPushFailedError) {
  // push-failed template (no branch link, no compare URL)
  fallbackBody = renderTemplateFromFile(pushFailedTemplatePath, { ... });
} else {
  // normal fallback (compare URL)
  const createPrUrl = buildManifestProtectionCreatePrUrl(...);
  fallbackBody = renderManifestProtectionFallbackBody(...);
}

The patch (am) path at lines 1745-1746 has the same skip logic — but
because that path apparently still has another push site that fires
before the fallback issue is built (or because the default bundle
transport is now the only path actually reached in our setup), the net
effect on the user is: bundle = no branch link; am = branch link.

Either way, the explicit core.info("Skipping branch push…") followed
by setting a pushFailedError looks intentional but seems wrong — the
review issue is exactly the case that needs the branch on origin most.

Expected behaviour

When protected-files: fallback-to-issue triggers, the branch should
be pushed using the same code path used for a successful PR (signed
commits via createCommitOnBranch GraphQL for the bundle transport,
git push for the am transport). The fallback issue should then render
the normal manifest_protection_create_pr_fallback.md template with the
compare URL.

The push-failed template should only render when the push actually
fails (e.g. missing workflows permission, GraphQL rejection, etc.) —
not as the default outcome of fallback-to-issue.

A reasonable fix:

  1. Remove the unconditional skip-and-mark-failed at
    create_pull_request.cjs:1486-1488 (and its sibling at 1745-1746).
  2. Let the push run normally.
  3. If the push genuinely fails, the existing try/catch around
    pushSignedCommits already sets manifestProtectionPushFailedError
    on real errors, so the push-failed template still renders for the
    actual failure case it was designed for.

Workaround

Set patch-format: am on create-pull-request. This routes through
the patch path, which (today) does push the branch before creating the
fallback issue. Trade-off: loses merge-commit topology and per-commit
authorship preservation that bundle transport was added for.

safe-outputs:
  create-pull-request:
    max: 1
    draft: true
    protected-files: fallback-to-issue
    patch-format: am # workaround for branch-link bug

Environment

  • gh-aw v0.74.4
  • actions/setup/js/create_pull_request.cjs (current main)

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions