Skip to content

Bug: Activation checkout does not preserve callee workflow ref in caller-hosted relays #20697

@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 does not carry the callee workflow ref. As a result, activation checks out <org>/<platform-repo> on its default branch instead of <feature-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 an activation target_repo mismatch in the observed build. Source inspection suggests current gh-aw main already intends to handle that in resolve_host_repo.cjs, so this draft does not claim that repo-resolution path is definitely a separate source-level bug. It stays focused on the distinct target_ref gap, which source inspection does support directly.

The downstream dispatch repository-selection bug is now tracked publicly in #20694. The downstream dispatch branch/ref bug is now tracked publicly in #20696. 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.

Source inspection of gh-aw main shows:

  • actions/setup/js/resolve_host_repo.cjs already exists and is intended to derive target_repo from GITHUB_WORKFLOW_REF
  • pkg/workflow/compiler_activation_job.go already emits a resolve-host-repo step and exposes target_repo
  • pkg/workflow/checkout_manager.go renders the activation .github / .agents checkout with repository: support but no ref: support

So the remaining source-level problem is:

  1. 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:

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

The correct repository is the repository that owns the currently running reusable workflow. Current source inspection suggests gh-aw already intends to derive that part via resolve_host_repo.cjs.

Affected Code

Generated activation checkout in the caller-hosted gateway.

Broken behavior:

  • 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 checks out <org>/<platform-repo>:main
  • runtime-imported prompts and .github assets come from the wrong branch

Proposed Fix

This is a real source-level gap and should be fixed explicitly:

  1. in actions/setup/js/resolve_host_repo.cjs, 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

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_ref should be derived in actions/setup/js/resolve_host_repo.cjs 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 existing target_repo behavior unchanged
    • 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 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 that after the platform repo is selected, the checkout still uses the repo default branch instead of <feature-branch>.

Expected:

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

Observed:

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

Private run URLs omitted.

Relationship to #20658, #20508, #20694, and #20696

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)
  3. activation must checkout the platform repo with cross-repo auth
  4. activation must preserve the callee workflow branch (target_ref)

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions