Fix lock file integrity check for cross-org reusable workflows#24057
Fix lock file integrity check for cross-org reusable workflows#24057
Conversation
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/addb4f0d-a52f-42ea-acbc-180202df9f66 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…ocal filesystem fallback Agent-Logs-Url: https://github.com/github/gh-aw/sessions/addb4f0d-a52f-42ea-acbc-180202df9f66 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…reEach Agent-Logs-Url: https://github.com/github/gh-aw/sessions/addb4f0d-a52f-42ea-acbc-180202df9f66 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes workflow lock file integrity checks failing in cross-org reusable workflow calls by adding a local workspace fallback when GitHub API access is unavailable.
Changes:
- Add a
$GITHUB_WORKSPACEfilesystem fallback for frontmatter hash comparison when GitHub API reads returnnullor throw. - Add Vitest coverage for API-failure → local-fallback scenarios.
- Update
conclusionjob concurrency group strings in two generated workflow lock files.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
actions/setup/js/check_workflow_timestamp_api.cjs |
Adds local filesystem fallback logic for frontmatter hash comparison when API access fails. |
actions/setup/js/check_workflow_timestamp_api.test.cjs |
Adds tests validating success/failure behavior for the new fallback path and API precedence. |
.github/workflows/stale-repo-identifier.lock.yml |
Changes conclusion job concurrency group to incorporate inputs.organization / github.run_id. |
.github/workflows/slide-deck-maintainer.lock.yml |
Changes conclusion job concurrency group to incorporate inputs.focus / github.run_id. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const workspace = process.env.GITHUB_WORKSPACE; | ||
| if (!workspace) { | ||
| core.info("GITHUB_WORKSPACE not available for local filesystem fallback"); | ||
| return null; | ||
| } | ||
|
|
||
| const localLockFilePath = path.join(workspace, lockFilePath); | ||
| const localMdFilePath = path.join(workspace, workflowMdPath); | ||
|
|
||
| core.info(`Attempting local filesystem fallback for hash comparison:`); | ||
| core.info(` Lock file: ${localLockFilePath}`); | ||
| core.info(` Source: ${localMdFilePath}`); | ||
|
|
||
| if (!fs.existsSync(localLockFilePath)) { | ||
| core.info(`Local lock file not found: ${localLockFilePath}`); | ||
| return null; | ||
| } | ||
|
|
||
| if (!fs.existsSync(localMdFilePath)) { | ||
| core.info(`Local source file not found: ${localMdFilePath}`); | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Local filesystem fallback builds paths by joining $GITHUB_WORKSPACE with lockFilePath/workflowMdPath, which are derived from GH_AW_WORKFLOW_FILE without any validation. If GH_AW_WORKFLOW_FILE contains path traversal segments (e.g. ../), the fallback could read files outside .github/workflows (and potentially outside the workspace). Consider normalizing with path.resolve() and enforcing that the resolved paths stay under ${GITHUB_WORKSPACE}/.github/workflows, or rejecting workflowFile values containing path separators / ...
| concurrency: | ||
| group: "gh-aw-conclusion-stale-repo-identifier" | ||
| group: "gh-aw-conclusion-stale-repo-identifier-${{ inputs.organization || github.run_id }}" | ||
| cancel-in-progress: false |
There was a problem hiding this comment.
This PR changes the conclusion job concurrency group to include ${{ inputs.organization || github.run_id }}, but the PR description focuses on the lockfile integrity check fallback and doesn’t mention workflow concurrency behavior changes. Please call out this workflow behavior change explicitly (or split it into a separate PR) so reviewers understand the intent and impact.
| concurrency: | ||
| group: "gh-aw-conclusion-slide-deck-maintainer" | ||
| group: "gh-aw-conclusion-slide-deck-maintainer-${{ inputs.focus || github.run_id }}" | ||
| cancel-in-progress: false |
There was a problem hiding this comment.
This PR changes the conclusion job concurrency group to include ${{ inputs.focus || github.run_id }}, but the PR description focuses on the lockfile integrity check fallback and doesn’t mention workflow concurrency behavior changes. Please call out this workflow behavior change explicitly (or split it into a separate PR) so reviewers understand the intent and impact.
| return { match, storedHash, recomputedHash }; | ||
| } catch (error) { | ||
| const errorMessage = getErrorMessage(error); | ||
| core.info(`Could not compute frontmatter hash: ${errorMessage}`); | ||
| return null; | ||
| core.info(`Could not compute frontmatter hash via API: ${errorMessage}`); | ||
| // Fall back to local filesystem when API is unavailable | ||
| // (e.g., cross-org reusable workflow where caller token lacks source repo access) | ||
| return await compareFrontmatterHashesFromLocalFiles(); | ||
| } |
There was a problem hiding this comment.
The new fallback-on-exception path in compareFrontmatterHashes() (catch block that logs Could not compute frontmatter hash via API: and then tries the local filesystem) isn’t covered by tests. Consider adding a test where the lock file fetch succeeds via API but the source .md fetch (via the GitHub fileReader) throws, and assert that the local fallback is attempted and the outcome matches the local hashes.
|
@copilot review comments |
…nrelated lock file changes Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2ad785e0-2404-49ac-9023-13704d9978d2 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed all three reviewer comments in commit
|
When a reusable workflow in
OrgA/repoAis called viaworkflow_callfromOrgB/repoB, the lock file integrity check fails because the caller'sGITHUB_TOKENcannot accessOrgA/repoAfiles via the GitHub API, causing anERR_CONFIGfailure before the agent starts.Changes
check_workflow_timestamp_api.cjs: Adds a local filesystem fallback tocompareFrontmatterHashes(). When the GitHub API returnsnullor throws (permission error, 404, etc.), the check falls back to reading from$GITHUB_WORKSPACE/.github/workflows/. This is always safe because theCheckout .github and .agents foldersstep — which already checks out the source repo (viatarget_repoinworkflow_callcontexts) — runs before the timestamp check. Path traversal protection is enforced: resolved paths are validated to stay within$GITHUB_WORKSPACE/.github/workflows/before any file is read.check_workflow_timestamp_api.test.cjs: Adds 7 tests covering the fallback path — API failure with matching/mismatched local hashes, missing workspace, missing lock file, API-takes-precedence when both are available, catch-block fallback when the.mdfile API fetch throws after the lock file fetch succeeds, and path traversal rejection.Works for same-repo, cross-repo same-org (API path), and cross-org reusable workflow calls (filesystem fallback).