Skip to content

Fork-backed create_pull_request fails with duplicate Authorization HTTP 400 #48414

Description

@bryanchen-d

Summary

Fork-backed create_pull_request fails every git operation against head-repo with HTTP 400 when head-github-app supplies a separate fork token.

This appears to be the create_pull_request fork equivalent of #40280: the safe-output checkout retains the upstream repository's persisted http.https://github.com/.extraheader, while the fork path supplies head-github-token separately. Git sends duplicate/conflicting Authorization headers to the fork remote.

Environment

  • gh-aw compiler/setup: v0.83.1
  • create-pull-request.target-repo: microsoft/vscode
  • create-pull-request.head-repo: bryanchen-d/vscode
  • upstream credential: safe-outputs.github-app
  • fork credential: create-pull-request.head-github-app
  • runner: ubuntu-slim
safe-outputs:
  github-app:
    client-id: ${{ steps.kv-app.outputs.client-id }}
    private-key: ${{ steps.kv-app.outputs.pem }}
    owner: microsoft
    repositories: [vscode]
  create-pull-request:
    target-repo: microsoft/vscode
    head-repo: bryanchen-d/vscode
    allowed-repos: [microsoft/vscode, bryanchen-d/vscode]
    head-github-app:
      client-id: ${{ steps.kv-app.outputs.client-id }}
      private-key: ${{ steps.kv-app.outputs.pem }}

Observed

The head token mints successfully for exactly bryanchen-d/vscode. The handler generates a valid patch/bundle, then direct git push and its fallbacks fail with:

fatal: unable to access 'https://github.com/bryanchen-d/vscode.git/':
The requested URL returned error: 400

No fork branch is created. With fallback-as-issue: true, the handler creates a fallback issue and the workflow reports success.

Controlled probe

A temporary job minted a token from the same App key with the same scope:

owner: bryanchen-d
repositories: vscode
permission-contents: write

Using that token in the same runner/job:

  1. GitHub REST API ref create/delete succeeded.
  2. Plain git fetch succeeded.
  3. Plain git push creating a disposable fork branch succeeded.
  4. Plain git push deleting that branch succeeded.

The probe branch was deleted. This rules out App installation, repository selection, and effective contents-write permission.

Suspected code path

Current create_pull_request.cjs temporarily calls overridePersistedExtraheader(...) for ls-remote, then restores the upstream checkout header before pushSignedCommits(...) receives pushRemoteUrl plus the separate pushToken.

For a fork-backed PR, the persisted upstream header and fork credential must not both reach the fork request. The fork token should temporarily replace the persisted header for the entire fork remote operation, or the push should otherwise use exactly one Authorization source.

Expected

Fork branch is pushed with only the head-github-app token, then the upstream token creates the PR in target-repo.

Related

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions