Skip to content

Bug: Activation checkout resolves wrong repo/ref in caller-hosted event-driven relays #20696

@johnwilliams-12

Description

@johnwilliams-12

Summary

Observed on gh-aw main as of 2026-03-12, after manually patching the generated Checkout actions folder steps per #20658 and after restoring cross-repository activation auth. In a caller-hosted relay topology where <org>/<app-repo> calls <org>/<platform-repo>/.github/workflows/<platform-gateway>.lock.yml@<feature-branch>, the generated activation checkout for .github and .agents resolves the correct target repository but does not carry the callee workflow ref. As a result, activation checks out <org>/<platform-repo> on its default branch instead of <feature-branch>. The relay therefore starts with the right platform repository but the wrong platform branch.

This means a caller-hosted relay pinned to a feature branch cannot reliably test branch-local prompt content, workflow imports, or .github assets unless the generated lock file is manually patched to propagate a target_ref and use it in the activation checkout.

Important prerequisite note: live event-driven relay testing on 2026-03-12 also showed that activation target_repo resolution is still not reliable in this topology. In the failing caller run, the generated Resolve host repo for activation checkout step still produced the caller repository slug instead of the platform repository slug, so a manual target_repo override was also required to reach the branch-selection problem at all. That behavior appears to mean the fix line associated with #20567 is still incomplete or regressed for this relay shape. This draft remains focused on the separate target_ref gap once target_repo is corrected.

The downstream dispatch repository-selection bug is now tracked publicly in #20694. This draft stays focused on activation-stage repo/ref resolution before the workflow reaches safe outputs.

Root Cause

The activation checkout path is split across runtime JavaScript and Go compiler emitters, and it is still incomplete in two ways for caller-hosted event-driven relays:

  1. runtime host-repo resolution is still not reliable enough for target_repo in this topology
  2. the compiler/runtime combination does not emit or use target_ref for the activation checkout

Current generated behavior is effectively:

- name: Resolve host repo for activation checkout
  id: resolve-host-repo
  uses: actions/github-script@<sha>
  with:
    script: |
      await main();
      # emits target_repo only

- name: Checkout .github and .agents folders
  uses: actions/checkout@<sha>
  with:
    token: ${{ steps.activation-app-token.outputs.token }}
    repository: ${{ steps.resolve-host-repo.outputs.target_repo }}
    sparse-checkout: |
      .github
      .agents

What is missing:

  • target_repo is still wrong in live event-driven relay runs unless manually overridden
  • no target_ref output from the host-repo resolution step
  • no ref: on the .github / .agents checkout

In a caller-hosted relay, the correct branch is not the caller repo branch and not the platform repo default branch. It is the ref encoded in the currently running platform workflow reference, i.e. the @<feature-branch> portion of GITHUB_WORKFLOW_REF.

And the correct repository is not the caller repository from the triggering event payload. It is the repository that owns the currently running reusable workflow.

Affected Code

Generated activation checkout in the caller-hosted gateway.

Broken behavior:

  • repository: is still wrong in live event-driven caller-hosted relays unless manually overridden
  • ref: is omitted
  • actions/checkout therefore falls back to the target repo default branch

Result:

  • relay definition points to <platform-gateway>.lock.yml@<feature-branch>
  • activation still checks out <org>/<platform-repo>:main
  • runtime-imported prompts and .github assets come from the wrong branch

Proposed Fix

Fix both activation checkout inputs explicitly, in the files that actually own this behavior:

  1. in actions/setup/js/resolve_host_repo.cjs, resolve the platform workflow repository correctly as target_repo, and also emit target_ref
  2. in the Go compiler code that emits the activation job checkout, add target_ref as an activation output and wire it into the .github / .agents checkout ref:

The runtime helper currently exists already:

  • pkg/workflow/compiler_activation_job.go emits the Resolve host repo for activation checkout step
  • that step calls actions/setup/js/resolve_host_repo.cjs
  • pkg/workflow/checkout_manager.go currently emits the activation .github / .agents checkout with repository: support but no ref: support

So the minimal real fix shape is:

- name: Resolve host repo for activation checkout
  id: resolve-host-repo
  uses: actions/github-script@<sha>
  with:
    script: |
      const { main } = require('/opt/gh-aw/actions/resolve_host_repo.cjs');
      await main();

- name: Checkout .github and .agents folders
  uses: actions/checkout@<sha>
  with:
    token: ${{ steps.activation-app-token.outputs.token }}
    repository: ${{ steps.resolve-host-repo.outputs.target_repo }}
    ref: ${{ steps.resolve-host-repo.outputs.target_ref }}
    sparse-checkout: |
      .github
      .agents

In other words, the issue is not “add inline YAML logic by hand”; it is:

  • update the existing runtime helper in actions/setup/js/resolve_host_repo.cjs
  • update the Go compiler emitters that expose outputs and render the activation checkout step

Concretely:

  • target_repo should continue to be derived in actions/setup/js/resolve_host_repo.cjs from the reusable-workflow host repository, not from the caller event repository
  • target_ref should also be derived there from GITHUB_WORKFLOW_REF when that workflow reference points at the reusable workflow being executed
  • pkg/workflow/compiler_activation_job.go should expose target_ref the same way it already exposes target_repo
  • pkg/workflow/checkout_manager.go should grow support for a checkout ref: so activation can checkout .github / .agents from the resolved callee branch

Implementation Plan

  1. Update the runtime helper in actions/setup/js/resolve_host_repo.cjs
    - Keep resolving target_repo from GITHUB_WORKFLOW_REF
    - Fix any remaining event-driven relay mismatch that still returns the caller repo in live runs
    - Also emit target_ref
    - Derive target_ref from GITHUB_WORKFLOW_REF when available
    - Fall back to GITHUB_REF only when no workflow ref is available

  2. Update the Go compiler emitters
    - In pkg/workflow/compiler_activation_job.go, expose target_ref as an activation output in the same way target_repo is exposed today
    - Update generateResolveHostRepoStep() to continue calling the shared runtime helper rather than inlining separate logic

  3. Update checkout rendering
    - In pkg/workflow/checkout_manager.go, extend GenerateGitHubFolderCheckoutStep(...) so it can emit a ref: in addition to repository:
    - Ensure repository: ${{ steps.resolve-host-repo.outputs.target_repo }} resolves to the reusable-workflow host repo in caller-hosted relays
    - Add ref: ${{ steps.resolve-host-repo.outputs.target_ref }} to the activation .github / .agents checkout step

  4. Add tests
    - In actions/setup/js/resolve_host_repo.test.cjs, add coverage for the failing event-driven relay shape and for target_ref output
    - In pkg/workflow/compiler_activation_job_test.go, assert activation outputs include both target_repo and target_ref
    - In pkg/workflow/compiler_activation_job_test.go or pkg/workflow/activation_checkout_test.go, assert the activation checkout emits both repository: and ref: when a workflow_call trigger is present
    - Compile a caller-hosted relay fixture pinned to @feature-branch
    - Assert branch-local .github assets are used during activation

  5. Validate
    - event-driven cross-repo relay on default branch: confirm activation checks out the platform repo, not the caller repo
    - event-driven cross-repo relay pinned to a non-default platform branch
    - confirm activation loads .github and .agents from that branch

Reproduction

  1. Use gh-aw main as of 2026-03-12.
  2. Create <org>/<platform-repo>/.github/workflows/<platform-gateway>.lock.yml on a non-default branch such as <feature-branch>.
  3. In <org>/<app-repo>, create a caller-hosted relay that calls <platform-gateway>.lock.yml@<feature-branch>.
  4. Trigger the relay.
  5. Inspect the activation checkout of .github and .agents.
  6. Observe one or both of the following in current builds:
  • the checkout resolves the caller repo instead of <org>/<platform-repo>
  • after manually overriding target_repo, the checkout still uses the repo default branch instead of <feature-branch>

Expected:

  • activation checkout uses <org>/<platform-repo>@<feature-branch>

Observed:

  • activation checkout may first resolve <org>/<app-repo> instead of <org>/<platform-repo>
  • activation checkout uses <org>/<platform-repo>@main

Private run URLs omitted.

Relationship to #20658, #20508, and #20694

This issue is related to both, but not the same as either.

In practice, caller-hosted branch testing needs all three layers to be correct:

  1. Checkout actions folder must checkout github/gh-aw correctly (Bug: Checkout actions folder emitted without repository: or ref:Setup Scripts fails in cross-repo relay #20658)
  2. activation must resolve the platform repo correctly (target_repo) — this still appears incomplete in the fix line associated with Cross-repo activation checkout still broken for event-driven relay workflows after #20301 #20567
  3. activation must checkout the platform repo with cross-repo auth
  4. activation must preserve the callee workflow branch (target_ref)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions