Skip to content

Fix lock file integrity check for cross-org reusable workflows#24057

Merged
pelikhan merged 5 commits intomainfrom
copilot/fix-lock-file-integrity-check
Apr 2, 2026
Merged

Fix lock file integrity check for cross-org reusable workflows#24057
pelikhan merged 5 commits intomainfrom
copilot/fix-lock-file-integrity-check

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

When a reusable workflow in OrgA/repoA is called via workflow_call from OrgB/repoB, the lock file integrity check fails because the caller's GITHUB_TOKEN cannot access OrgA/repoA files via the GitHub API, causing an ERR_CONFIG failure before the agent starts.

Changes

  • check_workflow_timestamp_api.cjs: Adds a local filesystem fallback to compareFrontmatterHashes(). When the GitHub API returns null or throws (permission error, 404, etc.), the check falls back to reading from $GITHUB_WORKSPACE/.github/workflows/. This is always safe because the Checkout .github and .agents folders step — which already checks out the source repo (via target_repo in workflow_call contexts) — 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.

    Primary: GitHub API (owner/repo resolved from GITHUB_WORKFLOW_REF)
        ↓ returns null or throws (cross-org permission error)
    Fallback: $GITHUB_WORKSPACE/.github/workflows/ (already checked out)
        ↓ also unavailable
    Fail with ERR_CONFIG (existing behavior)
    
  • 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 .md file 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).

Copilot AI and others added 3 commits April 2, 2026 10:55
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>
Copilot AI changed the title [WIP] Fix lock file integrity check for reusable workflows Fix lock file integrity check for cross-org reusable workflows Apr 2, 2026
Copilot AI requested a review from pelikhan April 2, 2026 11:13
@pelikhan pelikhan marked this pull request as ready for review April 2, 2026 11:17
Copilot AI review requested due to automatic review settings April 2, 2026 11:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_WORKSPACE filesystem fallback for frontmatter hash comparison when GitHub API reads return null or throw.
  • Add Vitest coverage for API-failure → local-fallback scenarios.
  • Update conclusion job 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.

Comment on lines +90 to +111
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;
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copilot uses AI. Check for mistakes.
Comment on lines 901 to 903
concurrency:
group: "gh-aw-conclusion-stale-repo-identifier"
group: "gh-aw-conclusion-stale-repo-identifier-${{ inputs.organization || github.run_id }}"
cancel-in-progress: false
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 887 to 889
concurrency:
group: "gh-aw-conclusion-slide-deck-maintainer"
group: "gh-aw-conclusion-slide-deck-maintainer-${{ inputs.focus || github.run_id }}"
cancel-in-progress: false
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 168 to 175
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();
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 2, 2026

@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>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 2, 2026

@copilot review comments

Addressed all three reviewer comments in commit 47d01c5:

  1. Path traversal protection: Added path.resolve() normalization and validated that both resolved paths stay under ${GITHUB_WORKSPACE}/.github/workflows before any file I/O. A test for this (should reject path traversal in GH_AW_WORKFLOW_FILE) was also added.

  2. Missing catch-block test: Added should fall back to local files when API lock file fetch succeeds but md file fetch throws — covers the path where the first API call (lock file) returns content but the second (.md file) throws, triggering the catch-block fallback.

  3. Unrelated lock file changes: Reverted slide-deck-maintainer.lock.yml and stale-repo-identifier.lock.yml to their original state from 635bb78.

@pelikhan pelikhan merged commit 8cf5427 into main Apr 2, 2026
80 of 83 checks passed
@pelikhan pelikhan deleted the copilot/fix-lock-file-integrity-check branch April 2, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lock file integrity check should resolve the lock file from the reusable workflow source repository

3 participants