Fix cross-repo activation checkout for event-driven relay workflows#20583
Fix cross-repo activation checkout for event-driven relay workflows#20583
Conversation
Replace the broken `github.event_name == 'workflow_call' && github.action_repository || github.repository` expression with a proper runtime resolution step using GITHUB_WORKFLOW_REF. - Add resolve_host_repo.cjs: parses GITHUB_WORKFLOW_REF to determine platform repo - Add resolve_host_repo.test.cjs: 9 tests for all relay patterns including event-driven - Update generate_aw_info.cjs: add target_repo field to aw_info.json - Update compiler_activation_job.go: add generateResolveHostRepoStep() and insert before aw_info step for workflow_call triggers - Update compiler_yaml.go: pass GH_AW_INFO_TARGET_REPO when workflow_call trigger present - Update compiler_activation_job_test.go: update workflowCallRepo constant and add tests - Update golden test files to reflect new activation job structure - Recompile all 166 workflow lock files Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes cross-repo activation checkout for event-driven relay workflows by resolving the “host” repository from GITHUB_WORKFLOW_REF (instead of github.event_name) and plumbing that value into checkout and aw_info.json.
Changes:
- Add
resolve_host_repo.cjs+ tests to computetarget_repofromGITHUB_WORKFLOW_REFand expose it as a step output. - Update activation-job generation to run a “resolve host repo” step before
generate_aw_info, and use its output for.github/.agentscheckout. - Pass
target_repointogenerate_aw_infoand record it inaw_info.json; update smoke lock workflow and Go tests accordingly.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
pkg/workflow/compiler_activation_job.go |
Adds generateResolveHostRepoStep() and switches activation checkout to use steps.resolve-host-repo.outputs.target_repo. |
pkg/workflow/compiler_yaml.go |
Injects GH_AW_INFO_TARGET_REPO into the generate_aw_info env for workflow_call (non-inlined) workflows. |
pkg/workflow/compiler_activation_job_test.go |
Updates/extends tests to assert the new step output expression is used and the old event_name expression is absent. |
actions/setup/js/resolve_host_repo.cjs |
New github-script module that parses GITHUB_WORKFLOW_REF and sets target_repo. |
actions/setup/js/resolve_host_repo.test.cjs |
Unit tests covering same-repo, cross-repo, relay scenarios, and malformed/empty env inputs. |
actions/setup/js/generate_aw_info.cjs |
Adds target_repo field to aw_info.json (from GH_AW_INFO_TARGET_REPO). |
.github/workflows/smoke-workflow-call.lock.yml |
Updates generated workflow to include the new resolve step, pass env, and use resolved repo for checkout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // the checkout step. This is necessary for event-driven relays (e.g. on: issue_comment) | ||
| // where github.event_name is not 'workflow_call', making the previous expression | ||
| // (github.event_name == 'workflow_call' && github.action_repository || github.repository) | ||
| // unreliable. GITHUB_WORKFLOW_REF always reflects the executing workflow's repo regardless | ||
| // of how it was triggered. | ||
| if hasWorkflowCallTrigger(data.On) && !data.InlinedImports { |
There was a problem hiding this comment.
The new logic correctly avoids relying on github.event_name == 'workflow_call' for checkout, but the activation job still adds the "Cross-repo setup guidance" step with if: failure() && github.event_name == 'workflow_call' (same file, line 81). For event-driven relays (issue_comment/push → workflow_call chain), that condition will never be true, so the guidance won’t run when it’s most needed. Consider updating the guidance step condition to use the same discriminator as checkout (e.g., GITHUB_WORKFLOW_REF/resolve-host-repo output) or at minimum drop the event_name check so relays are covered.
|
If I'm not mistaken this would fix the issue only for the activation job, but I think the issue will remain for the |
|
@copilot the target_repo value needs to be propagated to the other jobs (agent/safe_outputs/...) and use whenever checkout is needed. Update the checkout manager. |
Agreed that 1. The GitHub App token - name: Generate GitHub App token
uses: actions/create-github-app-token@...
with:
repositories: ${{ github.event.repository.name }} # → caller repoThis token is passed as 2. The The compiled {"dispatch_workflow":{"max":1,"workflow_files":{"agentic-worker":".lock.yml"},"workflows":[...]}}Without a So propagating |
Per review feedback: add crossRepoTargetRepo to CheckoutManager so the platform (host) repo is accessible wherever checkout is needed. - Add crossRepoTargetRepo field + SetCrossRepoTargetRepo/GetCrossRepoTargetRepo to CheckoutManager - Expose target_repo as activation job output (needs.activation.outputs.target_repo) so agent/safe_outputs jobs can reference it - Use SetCrossRepoTargetRepo in generateCheckoutGitHubFolderForActivation instead of passing raw string - Set crossRepoTargetRepo on agent job's CheckoutManager using needs.activation.outputs.target_repo - Add TestCrossRepoTargetRepo and TestActivationJobTargetRepoOutput tests - Recompile 166 lock files + update golden test files Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in e449f3f. Changes made:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot recompile |
|
@copilot review comments in #20583 (comment) |
All 166 lock files were already up to date from the previous commit (e449f3f) — Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
…get-repo, and activation dependency Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed in 69ba76a. Three fixes applied for relay workflow scenarios:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
do a full review of the changes |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Reviewed and found one remaining issue: the "Cross-repo setup guidance" step still used Fixed in c5738f8 by replacing it with No other issues found — CI passes, all 166 lock files compile, tests green, lint clean. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@johnwilliams-12 take a peek. I think it's ready for testing. |
The activation job checkout introduced in #20301 used
github.event_name == 'workflow_call' && github.action_repository || github.repositoryto resolve the platform repo. This expression breaks for event-driven relays (on: issue_comment,on: push, etc.) where GitHub propagates the original triggering event through theworkflow_callchain — makingevent_namenever'workflow_call'inside the called workflow, so checkout always targets the caller's repo.Root cause
GITHUB_WORKFLOW_REF(always set to the executing workflow'sowner/repo/.github/workflows/file@ref) is the correct discriminator — unlikeevent_name, it reflects which workflow is running, not what triggered it.Changes
resolve_host_repo.cjs(new):actions/github-scriptscript that parsesGITHUB_WORKFLOW_REF, extracts theowner/repoprefix, compares againstGITHUB_REPOSITORYto detect cross-repo invocations, setstarget_repooutput, logs the decision, and writes a step summary when cross-repo is detected.compiler_activation_job.go: AddsgenerateResolveHostRepoStep()and inserts it beforegenerateCreateAwInfowhen aworkflow_calltrigger is present. UpdatesgenerateCheckoutGitHubFolderForActivation()to use theCheckoutManager.SetCrossRepoTargetRepoAPI. Exposestarget_repo: ${{ steps.resolve-host-repo.outputs.target_repo }}as an activation job output so agent and safe_outputs jobs can referenceneeds.activation.outputs.target_repo. Updates the "Cross-repo setup guidance" failure step condition fromgithub.event_name == 'workflow_call'tosteps.resolve-host-repo.outputs.target_repo != github.repository, so the guidance fires correctly for event-driven relays.checkout_manager.go: AddscrossRepoTargetRepofield withSetCrossRepoTargetRepo/GetCrossRepoTargetRepomethods — the canonical place for downstream jobs to carry the platform repo expression for any checkout step that needs it.compiler_yaml_main_job.go: Agent job'sCheckoutManagernow hascrossRepoTargetReposet to${{ needs.activation.outputs.target_repo }}when aworkflow_calltrigger is present, propagating the resolved platform repo to any checkout step generated in the agent job.compiler_yaml.go: PassesGH_AW_INFO_TARGET_REPO: ${{ steps.resolve-host-repo.outputs.target_repo }}into thegenerate_aw_infoenv when applicable.generate_aw_info.cjs: Recordstarget_repoinaw_info.jsonfor observability.compiler_safe_outputs_job.go: Thesafe_outputsjob now declaresactivationas a dependency when aworkflow_calltrigger is present, soneeds.activation.outputs.target_repois resolvable in that job.safe_outputs_config.go:buildGitHubAppTokenMintStepaccepts a newfallbackRepoExprparameter. When aworkflow_calltrigger is detected, callers incompiler_safe_outputs_job.go,safe_outputs_jobs.go, andnotify_comment.gopass${{ needs.activation.outputs.target_repo }}so the minted GitHub App token is scoped to the platform (host) repo rather than the caller's repo.dispatch_workflow.go/compiler_safe_outputs_config.go: AddedTargetRepoSlugfield toDispatchWorkflowConfigand updated thedispatch_workflowhandler builder to emittarget-repo.addHandlerManagerConfigEnvVarinjects${{ needs.activation.outputs.target_repo }}(via asafeOutputsWithDispatchTargetRepohelper) whenworkflow_callis present and no explicittarget-repois configured, ensuringdispatch_workflowtargets the host repo rather than the caller's.Tests:
resolve_host_repo.test.cjscovers same-repo, cross-repo, event-driven relay (issue_comment), empty/malformedGITHUB_WORKFLOW_REF, and undefinedGITHUB_REPOSITORY. Go tests updated to assert the new step expression and verify the brokenevent_name-based expression is absent.TestCrossRepoTargetRepocovers theCheckoutManagergetter/setter lifecycle.TestActivationJobTargetRepoOutputverifiestarget_repoappears (or is absent) in activation job outputs for all trigger combinations.The resulting activation job step sequence for
workflow_calltriggers:For
workflow_calltriggers, thesafe_outputsjob also:activation(to resolveneeds.activation.outputs.target_repo)repositories:is configuredtarget-repoon thedispatch_workflowhandler config so workflow dispatch targets the platform repo💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.