Skip to content

downstream action: .auto ref resolution broken against private repos after actions/checkout@v6 bump (duplicate Authorization header) #147

@vienthuong

Description

@vienthuong

Summary

Since 067df92 (2026-05-14, "chore: update all GitHub Actions to their latest major versions"), downstream/action.yml bumps actions/checkout@v4@v6. This breaks .auto ref resolution when the downstream repo is private: every git ls-remote issued by shopware-version from within the dispatcher fails with HTTP 400 because two Authorization headers end up on the request, and the .auto cascade falls through to the fallback (typically trunk).

Public-repo downstreams are unaffected because git ls-remote against public repos doesn't require auth.

Repro

Any pull_request against shopware/shopware where the PR branch has a matching branch in shopware/SwagCommercial (private).

Concrete example — the Commercial job from core PR #16169:

Observed (from the job log)

The branch feat/add-tiebreaker-for-dismax-queries exists in shopware/SwagCommercial (verified via gh api repos/shopware/SwagCommercial/git/refs/heads/feat/add-tiebreaker-for-dismax-queries), yet .auto falls back to trunk:

env:
  REF: refs/pull/16169/merge
  HEAD_REF: feat/add-tiebreaker-for-dismax-queries
  BASE_REF: trunk
  REPO: shopware/SwagCommercial
  ...
Using HEAD_REF as REF
ref: refs/heads/feat/add-tiebreaker-for-dismax-queries
base ref: refs/heads/trunk
Step 1: Checking if REF 'refs/heads/feat/add-tiebreaker-for-dismax-queries' exists in target repo 'https://github.com/shopware/SwagCommercial'
remote: Duplicate header: "Authorization"
fatal: unable to access 'https://github.com/shopware/SwagCommercial/': The requested URL returned error: 400
✗ REF not found, checking BASE_REF 'refs/heads/trunk'
remote: Duplicate header: "Authorization"
fatal: unable to access 'https://github.com/shopware/SwagCommercial/': The requested URL returned error: 400
✗ BASE_REF not found, checking next minor branch
  Checking next minor: refs/heads/trunk
remote: Duplicate header: "Authorization"
fatal: ... error: 400
✗ Next minor not found, checking next major branch
  Checking next major: refs/heads/trunk
remote: Duplicate header: "Authorization"
fatal: ... error: 400
✗ No matching branch found, checking fallback: trunk
remote: Duplicate header: "Authorization"
fatal: ... error: 400
refs/heads/feat/add-tiebreaker-for-dismax-queries not found in https://github.com/shopware/SwagCommercial, using hard-coded fallback = trunk
Matching shopware version: trunk

The dispatcher then runs gh workflow run "Downstream" --ref trunk instead of --ref feat/add-tiebreaker-for-dismax-queries, and the downstream workflow runs the trunk version of the extension against the upstream PR's core branch — causing confusing PHPStan / BC / test failures.

Root cause

downstream/action.yml first runs actions/checkout@v6, then manually sets:

- shell: bash
  run: |
    git config "http.https://github.com/".extraheader "AUTHORIZATION: basic ..."

actions/checkout@v6 already persists its own credential extraheader in the cloned repo's local config. Because the URLs the two configs are scoped to both match https://github.com/<owner>/<repo>, git sends both Authorization headers on the subsequent git ls-remote and GitHub rejects with HTTP 400. v4 did not have this conflict for whatever reason (different URL scoping or persistence default).

Timeline matches: the last successful Commercial run from a private-repo upstream PR was on 2026-05-22, just before this bump rolled out via @main. Every run since 2026-05-25 has failed to resolve .auto.

Proposed fix

Disable credential persistence on the dispatcher's initial checkout — the action sets its own extraheader right after anyway:

   - name: Checkout
     uses: actions/checkout@v6
+    with:
+      persist-credentials: false
   - uses: shopware/octo-sts-action@main
     ...
   - shell: bash
     run: |
       git config "http.https://github.com/".extraheader "AUTHORIZATION: basic $(echo -n "x-access-token:${{ inputs.token || steps.sts.outputs.token }}" | base64 -w0)"

(Same fix likely belongs in setup-extension/action.yml, which also bumped to actions/checkout@v6 in the same commit and does its own auth dance — though that path is less exercised in failure mode.)

Alternative: revert just the dispatcher checkout to @v4. Less clean.

Workaround

SwagCommercial worked around this in shopware/SwagCommercial#2776 by resolving the matching branch via the REST API on the downstream side and forwarding it as extensionRef to all child workflows — but that pattern would have to be repeated by every private-repo extension that uses this action, so an upstream fix is preferable.

Impact

Every private-repo extension that relies on .auto matching from shopware/github-actions/downstream@main has been silently running the wrong combination of branches in downstream CI for ~13 days. PRs with matching extension branches are particularly affected (the matching branch never gets used). PRs with no matching extension branch happen to work because the fallback path lands on trunk anyway.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No 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