Skip to content

Cross-repo workflow_call: hash check fails because github.workflow_ref and GITHUB_EVENT_NAME resolve to caller, not callee #24918

@bbonafed

Description

@bbonafed

Note
The bug and fix were generated by my agent. Although it was looked over by me, I am still not 100% confident. Let me know if my logic is wrong and/or there is a different workaround.

Summary

When a reusable workflow (compiled .lock.yml) is called cross-repo via uses: org/repo/.github/workflows/workflow.lock.yml@ref, the "Check workflow lock file" step fails with:

ERR_CONFIG: Lock file 'workflow.lock.yml' is outdated or unverifiable!
Could not verify frontmatter hash for 'workflow.md'.
Run 'gh aw compile' to regenerate the lock file.

The hash check looks for the lock file in the caller's repo instead of the callee's repo, gets a 404, falls back to the local filesystem (also the caller's workspace), and fails.

Root Cause

Two incorrect assumptions in check_workflow_timestamp_api.cjs:

1. ${{ github.workflow_ref }} does NOT resolve to the callee

The compiler (compiler_activation_job.go, line ~227) injects:

GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"

The comment states:

Unlike the GITHUB_WORKFLOW_REF env var (which always reflects the top-level caller in workflow_call), ${{ github.workflow_ref }} correctly refers to the current reusable workflow being executed.

This is wrong. Per GitHub Actions docs and confirmed via debug output, github.workflow_ref in a reusable workflow returns the caller's workflow ref, not the callee's:

##[debug]Evaluating: github.workflow_ref
##[debug]=> 'caller-org/caller-repo/.github/workflows/caller.yml@refs/heads/main'

The test at line ~800 of check_workflow_timestamp_api.test.cjs encodes this same incorrect assumption:

// Test assumes GH_AW_CONTEXT_WORKFLOW_REF = callee, but GitHub Actions sets it to caller
process.env.GH_AW_CONTEXT_WORKFLOW_REF = "platform-owner/platform-repo/.github/workflows/test.lock.yml@refs/heads/main";

2. referenced_workflows API fallback never fires

The fallback at line ~106 checks if (eventName === "workflow_call"). However, GITHUB_EVENT_NAME inside the reusable workflow appears to be the original trigger event (e.g., push), not workflow_call. The fallback branch never executes — confirmed by the absence of any "workflow_call event detected" log line in the debug output.

What Happens

  1. GH_AW_CONTEXT_WORKFLOW_REF resolves to the caller's workflow → owner/repo parsed as the caller
  2. GITHUB_EVENT_NAME is not workflow_callreferenced_workflows API lookup is skipped
  3. Hash check fetches lock file from the caller's repo via API → 404
  4. Falls back to local filesystem ($GITHUB_WORKSPACE) → also the caller's repo → file not found
  5. Step fails with ERR_CONFIG

Reproduction

  1. Create a reusable workflow in repo A, compile it with gh aw compile
  2. In repo B, create a caller workflow that uses it:
    jobs:
      my-job:
        uses: org/repo-a/.github/workflows/workflow.lock.yml@main
        secrets:
          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
  3. Trigger repo B's workflow (e.g., push to main)
  4. The "Check workflow lock file" step fails with ERR_CONFIG

gh-aw version: v0.67.1

Proposed Fix

The referenced_workflows API approach (lines 105-149) is the right idea but needs to fire for ALL events, not just workflow_call. The fix should:

  1. Remove the eventName === "workflow_call" gate — or broaden it to always attempt the referenced_workflows lookup when GH_AW_WORKFLOW_FILE indicates a .lock.yml that might be cross-repo.

  2. Fix GH_AW_CONTEXT_WORKFLOW_REF — either stop relying on ${{ github.workflow_ref }} (since it returns the caller) or use a different mechanism. resolve_host_repo.cjs already uses GITHUB_WORKFLOW_REF env var with the comment "GITHUB_WORKFLOW_REF always reflects the currently executing workflow file" — though this also appears to resolve to the caller in practice.

  3. Update the test at line ~800 to reflect actual GitHub Actions behavior where both github.workflow_ref and GITHUB_WORKFLOW_REF return the caller's ref in reusable workflows.

Related

Metadata

Metadata

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