@@ -794,25 +794,28 @@ engine: copilot
794794 } ) ;
795795 } ) ;
796796
797- describe ( "cross-repo invocation via workflow_call ( GH_AW_CONTEXT_WORKFLOW_REF fix) " , ( ) => {
797+ describe ( "manual GH_AW_CONTEXT_WORKFLOW_REF fallback override " , ( ) => {
798798 // Regression test for https://github.com/github/gh-aw/issues/23935
799- // When a reusable workflow is invoked cross-repo via workflow_call:
800- // - GITHUB_WORKFLOW_REF (env var) = top-level CALLER's workflow (e.g., repo-b/caller.yml@main)
801- // - GH_AW_CONTEXT_WORKFLOW_REF (injected from ${{ github.workflow_ref }}) = the CALLEE's reusable workflow
802- // Without this fix, the script would look for lock files in the caller's repo (404).
799+ // In reusable workflow contexts, both GITHUB_WORKFLOW_REF and
800+ // ${{ github.workflow_ref }} resolve to the caller's workflow.
801+ // The referenced_workflows API lookup is the primary fix for identifying the callee
802+ // workflow. These tests cover the fallback path used when that API lookup is bypassed
803+ // by the short-circuit (the env ref already ends with the current workflow file, meaning
804+ // GH_AW_CONTEXT_WORKFLOW_REF was manually set to the callee's ref as a targeted override).
803805
804806 beforeEach ( ( ) => {
805807 process . env . GH_AW_WORKFLOW_FILE = "test.lock.yml" ;
806- // Simulate workflow_call cross-repo: reusable workflow defined in platform-repo,
807- // called from caller-repo. GITHUB_WORKFLOW_REF wrongly points to the caller's workflow.
808+ // Simulate a caller workflow context where GITHUB_WORKFLOW_REF points at the caller.
808809 process . env . GITHUB_WORKFLOW_REF = "caller-owner/caller-repo/.github/workflows/caller.yml@refs/heads/main" ;
809810 process . env . GITHUB_REPOSITORY = "caller-owner/caller-repo" ;
810- // GH_AW_CONTEXT_WORKFLOW_REF is injected by the compiler from ${{ github.workflow_ref }}
811- // which correctly identifies the reusable workflow being executed.
811+ // Manually inject GH_AW_CONTEXT_WORKFLOW_REF to exercise the fallback/override path.
812+ // This value intentionally points to the callee repo (platform-repo) so the env ref
813+ // ends with "/.github/workflows/test.lock.yml", triggering the short-circuit and
814+ // bypassing the API lookup.
812815 process . env . GH_AW_CONTEXT_WORKFLOW_REF = "platform-owner/platform-repo/.github/workflows/test.lock.yml@refs/heads/main" ;
813816 } ) ;
814817
815- it ( "should use GH_AW_CONTEXT_WORKFLOW_REF to identify source repo, not GITHUB_WORKFLOW_REF " , async ( ) => {
818+ it ( "should use GH_AW_CONTEXT_WORKFLOW_REF override to identify source repo when env ref matches workflow file " , async ( ) => {
816819 const validHash = "c2a79263dc72f28c76177afda9bf0935481b26da094407a50155a6e0244084e3" ;
817820 const lockFileContent = `# frontmatter-hash: ${ validHash } \nname: Test\n` ;
818821 const mdFileContent = "---\nengine: copilot\n---\n# Test" ;
@@ -827,7 +830,7 @@ engine: copilot
827830
828831 await main ( ) ;
829832
830- // Must use the platform repo (from GH_AW_CONTEXT_WORKFLOW_REF), not the caller repo
833+ // Must use the platform repo (from GH_AW_CONTEXT_WORKFLOW_REF override ), not the caller repo
831834 expect ( mockGithub . rest . repos . getContent ) . toHaveBeenCalledWith ( expect . objectContaining ( { owner : "platform-owner" , repo : "platform-repo" } ) ) ;
832835 expect ( mockGithub . rest . repos . getContent ) . not . toHaveBeenCalledWith ( expect . objectContaining ( { owner : "caller-owner" , repo : "caller-repo" } ) ) ;
833836 expect ( mockCore . setFailed ) . not . toHaveBeenCalled ( ) ;
@@ -840,7 +843,7 @@ engine: copilot
840843 await main ( ) ;
841844
842845 expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "GH_AW_CONTEXT_WORKFLOW_REF: platform-owner/platform-repo/.github/workflows/test.lock.yml@refs/heads/main" ) ) ;
843- expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "GITHUB_WORKFLOW_REF: caller-owner/caller-repo/.github/workflows/caller.yml@refs/heads/main " ) ) ;
846+ expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "available as env fallback " ) ) ;
844847 } ) ;
845848
846849 it ( "should detect cross-repo invocation using GH_AW_CONTEXT_WORKFLOW_REF source vs GITHUB_REPOSITORY" , async ( ) => {
@@ -919,13 +922,30 @@ engine: copilot
919922 expect ( mockGithub . rest . repos . getContent ) . toHaveBeenCalledWith ( expect . objectContaining ( { ref : "refs/heads/main" } ) ) ;
920923 expect ( mockGithub . rest . repos . getContent ) . not . toHaveBeenCalledWith ( expect . objectContaining ( { ref : "abc123" } ) ) ;
921924 } ) ;
925+
926+ it ( "should skip referenced_workflows API when env ref already matches the workflow file, even with a valid GITHUB_RUN_ID" , async ( ) => {
927+ // Short-circuit: if the env ref ends with the current workflowFile, the API call is
928+ // skipped to avoid unnecessary rate-limit usage in normal (non-reusable) runs.
929+ process . env . GITHUB_RUN_ID = "99999" ;
930+ mockGithub . rest . repos . getContent . mockResolvedValue ( { data : null } ) ;
931+
932+ await main ( ) ;
933+
934+ // API must NOT be called — env ref already identifies this workflow
935+ expect ( mockGithub . rest . actions . getWorkflowRun ) . not . toHaveBeenCalled ( ) ;
936+ expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "skipping referenced_workflows API lookup" ) ) ;
937+ } ) ;
922938 } ) ;
923939
924940 describe ( "cross-repo reusable workflow via referenced_workflows API (issue #24422)" , ( ) => {
925- // Fix for https://github.com/github/gh-aw/issues/24422
926- // When a reusable workflow is triggered by workflow_call, github.workflow_ref
927- // can still point to the caller's workflow. This fix uses referenced_workflows
928- // from the GitHub Actions API run object to reliably identify the callee's repo.
941+ // Fix for https://github.com/github/gh-aw/issues/24422 and cross-repo bug
942+ // When a reusable workflow is triggered, GITHUB_EVENT_NAME reflects the ORIGINAL trigger
943+ // event (e.g., "push", "issues"), NOT "workflow_call". We therefore cannot rely on event
944+ // name to detect cross-repo scenarios.
945+ //
946+ // Additionally, github.workflow_ref (injected as GH_AW_CONTEXT_WORKFLOW_REF) resolves to
947+ // the CALLER's workflow ref, not the callee's. The referenced_workflows API lookup from
948+ // the caller's run object is the reliable way to identify the callee's repo and ref.
929949 //
930950 // In the workflow_call context, GITHUB_RUN_ID and GITHUB_REPOSITORY are set to
931951 // the caller's run and repo. The caller's run object includes referenced_workflows
@@ -937,7 +957,7 @@ engine: copilot
937957 process . env . GITHUB_RUN_ID = "12345" ;
938958 // GITHUB_REPOSITORY is the caller's repo in a workflow_call context
939959 process . env . GITHUB_REPOSITORY = "caller-owner/caller-repo" ;
940- // GH_AW_CONTEXT_WORKFLOW_REF (from ${{ github.workflow_ref }}) may still point to caller
960+ // GH_AW_CONTEXT_WORKFLOW_REF (from ${{ github.workflow_ref }}) resolves to the caller
941961 process . env . GH_AW_CONTEXT_WORKFLOW_REF = "caller-owner/caller-repo/.github/workflows/caller.yml@refs/heads/main" ;
942962 process . env . GITHUB_WORKFLOW_REF = "caller-owner/caller-repo/.github/workflows/caller.yml@refs/heads/main" ;
943963 } ) ;
@@ -994,7 +1014,7 @@ engine: copilot
9941014
9951015 await main ( ) ;
9961016
997- expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "workflow_call event detected " ) ) ;
1017+ expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "Checking for cross-repo callee via referenced_workflows API " ) ) ;
9981018 expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "Resolved callee repo from referenced_workflows: callee-owner/callee-repo" ) ) ;
9991019 } ) ;
10001020
@@ -1044,13 +1064,29 @@ engine: copilot
10441064 expect ( mockGithub . rest . repos . getContent ) . toHaveBeenCalledWith ( expect . objectContaining ( { owner : "caller-owner" , repo : "caller-repo" } ) ) ;
10451065 } ) ;
10461066
1047- it ( "should not call referenced_workflows API for non-workflow_call events" , async ( ) => {
1067+ it ( "should call referenced_workflows API even for non-workflow_call events" , async ( ) => {
1068+ // In reusable workflows, GITHUB_EVENT_NAME reflects the original trigger event (e.g.,
1069+ // "push"), not "workflow_call". We must try referenced_workflows regardless of event name.
10481070 process . env . GITHUB_EVENT_NAME = "push" ;
1071+ mockGithub . rest . actions . getWorkflowRun . mockResolvedValueOnce ( {
1072+ data : {
1073+ referenced_workflows : [
1074+ {
1075+ path : "callee-owner/callee-repo/.github/workflows/callee-workflow.lock.yml@refs/heads/main" ,
1076+ sha : "deadbeef" ,
1077+ ref : "refs/heads/main" ,
1078+ } ,
1079+ ] ,
1080+ } ,
1081+ } ) ;
10491082 mockGithub . rest . repos . getContent . mockResolvedValue ( { data : null } ) ;
10501083
10511084 await main ( ) ;
10521085
1053- expect ( mockGithub . rest . actions . getWorkflowRun ) . not . toHaveBeenCalled ( ) ;
1086+ // API must be called even for "push" events
1087+ expect ( mockGithub . rest . actions . getWorkflowRun ) . toHaveBeenCalled ( ) ;
1088+ // Resolves to callee repo even though GITHUB_EVENT_NAME is "push"
1089+ expect ( mockGithub . rest . repos . getContent ) . toHaveBeenCalledWith ( expect . objectContaining ( { owner : "callee-owner" , repo : "callee-repo" } ) ) ;
10541090 } ) ;
10551091
10561092 it ( "should prefer sha over ref from referenced_workflows entry" , async ( ) => {
@@ -1112,7 +1148,7 @@ engine: copilot
11121148
11131149 // API must not be called with a NaN run_id
11141150 expect ( mockGithub . rest . actions . getWorkflowRun ) . not . toHaveBeenCalled ( ) ;
1115- expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "run ID is unavailable or invalid" ) ) ;
1151+ expect ( mockCore . info ) . toHaveBeenCalledWith ( expect . stringContaining ( "Run ID is unavailable or invalid" ) ) ;
11161152 // Falls back to caller repo from GH_AW_CONTEXT_WORKFLOW_REF
11171153 expect ( mockGithub . rest . repos . getContent ) . toHaveBeenCalledWith ( expect . objectContaining ( { owner : "caller-owner" , repo : "caller-repo" } ) ) ;
11181154 } ) ;
0 commit comments