Skip to content

Fix bundle-apply race: capture git stderr to recover missing prerequisite commits#32360

Merged
pelikhan merged 4 commits into
mainfrom
copilot/fix-bundle-apply-race-issue
May 15, 2026
Merged

Fix bundle-apply race: capture git stderr to recover missing prerequisite commits#32360
pelikhan merged 4 commits into
mainfrom
copilot/fix-bundle-apply-race-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 15, 2026

Bug Fix

What was the bug?

The safe_outputs job uses fetch-depth: 1, so if another PR merges to main between agent-time and safe_outputs-time, the bundle's base commit (present when the agent ran) is no longer reachable. git fetch <bundle> then fails with Repository lacks these prerequisite commits: <SHA>.

A recovery path already existed in create_pull_request.cjs to parse missing SHAs and fetch them from origin — but it was dead code. @actions/exec's exec() throws only "The process '/usr/bin/git' failed with exit code 1"; the actual git stderr (which contains the prerequisite SHA lines) is printed to the Actions log but never surfaced in the thrown Error. The SHA regex never matched, so recovery never ran.

push_to_pull_request_branch.cjs had no recovery path at all.

How did you fix it?

Switch the initial bundle fetch from exec() to getExecOutput(..., { ignoreReturnCode: true }), which returns { exitCode, stdout, stderr } without throwing. Pass the captured stderr to extractBundlePrerequisiteCommits, fetch the missing SHAs from origin, and retry.

// Before — stderr swallowed by exec() throw, recovery path unreachable
try {
  await execApi.exec("git", ["fetch", bundleFilePath, `${bundleBranchRef}:${bundleTempRef}`]);
} catch (err) {
  const shas = extractBundlePrerequisiteCommits(err.message); // always []
  ...
}

// After — stderr captured, recovery path actually runs
const result = await execApi.getExecOutput("git", ["fetch", bundleFilePath, `${bundleBranchRef}:${bundleTempRef}`], { ignoreReturnCode: true });
if (result.exitCode !== 0) {
  const shas = extractBundlePrerequisiteCommits(result.stderr); // parses real git output
  if (shas.length > 0) {
    await execApi.exec("git", ["fetch", "origin", ...shas]);
    await execApi.exec("git", ["fetch", bundleFilePath, `${bundleBranchRef}:${bundleTempRef}`]);
  }
}

Changes

  • git_helpers.cjs — moved extractBundlePrerequisiteCommits here from create_pull_request.cjs; exported it for both handlers
  • create_pull_request.cjs — initial bundle fetch switched to getExecOutput with ignoreReturnCode: true; prerequisite recovery path now actually receives git stderr
  • push_to_pull_request_branch.cjs — added prerequisite recovery path (was entirely absent); same pattern
  • Tests — all bundle-fetch mocks updated to reflect the getExecOutput-first pattern; added unit tests for extractBundlePrerequisiteCommits; new integration and recovery-path tests; fixed createExecApi in the bundle integration test to honour ignoreReturnCode and fire the onExec callback in getExecOutput

Copilot AI and others added 2 commits May 15, 2026 13:13
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…uisite recovery

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Hey @copilot-swe-agent 👋 — great start on tackling the bundle-apply race condition in safe_outputs fetch! The fix plan in the PR body is clear and well-structured.

A couple of things to address before this is ready for review:

  • Tests are missing — the current diff only contains .lock.yml file updates; none of the planned changes to git_helpers.cjs, create_pull_request.cjs, or push_to_pull_request_branch.cjs (and their test counterparts) have landed yet. The checklist items are all still unchecked.
  • WIP state — this is marked as a draft with [WIP] in the title and an all-unchecked task list. Once the implementation commits are in place, update the checklist and mark the PR ready for review.

If you'd like a hand completing the implementation, you can assign this prompt to your coding agent:

Implement the following changes to fix the bundle-apply race condition in safe_outputs fetch:
1. Move `extractBundlePrerequisiteCommits` from `create_pull_request.cjs` to `git_helpers.cjs` so it can be shared.
2. Fix `applyBundleToBranch` in `create_pull_request.cjs` to use `getExecOutput` with `ignoreReturnCode: true` so that stderr (containing prerequisite SHAs) is captured correctly.
3. Add a prerequisite-commit recovery path to `push_to_pull_request_branch.cjs`.
4. Update `create_pull_request.test.cjs` to use realistic `getExecOutput` mocks.
5. Update `push_to_pull_request_branch.test.cjs` with a recovery-path test.
6. Add `extractBundlePrerequisiteCommits` unit tests to `git_helpers.test.cjs`.
7. Verify all tests pass before marking the PR ready for review.

Generated by ✅ Contribution Check · ● 13.9M ·

Copilot AI changed the title [WIP] Fix bundle-apply race condition in safe_outputs fetch Fix bundle-apply race: capture git stderr to recover missing prerequisite commits May 15, 2026
Copilot AI requested a review from pelikhan May 15, 2026 13:28
@pelikhan pelikhan marked this pull request as ready for review May 15, 2026 13:34
Copilot AI review requested due to automatic review settings May 15, 2026 13:34
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

This PR fixes a race where applying a git bundle can fail in safe_outputs if the bundle’s prerequisite commits are no longer reachable (e.g., due to shallow checkout + main advancing). It does so by capturing the actual git fetch stderr (instead of losing it via exec() throwing a generic error), extracting missing prerequisite SHAs, fetching them from origin, and retrying the bundle fetch.

Changes:

  • Switch initial bundle fetch to getExecOutput(..., { ignoreReturnCode: true }) so git stderr is available for prerequisite SHA extraction/recovery.
  • Add/enable prerequisite recovery for both create_pull_request and push_to_pull_request_branch, and centralize SHA extraction in git_helpers.cjs.
  • Update unit/integration tests and exec mocks to reflect the new getExecOutput-first behavior.
Show a summary per file
File Description
actions/setup/js/git_helpers.cjs Adds/export extractBundlePrerequisiteCommits so multiple handlers can share the bundle prerequisite parsing logic.
actions/setup/js/git_helpers.test.cjs Adds unit tests for extractBundlePrerequisiteCommits behavior (empty, single/multi SHA, dedupe, case-insensitive header).
actions/setup/js/create_pull_request.cjs Uses getExecOutput to capture bundle-fetch stderr and activate prerequisite recovery; removes local extractor in favor of shared helper.
actions/setup/js/create_pull_request.test.cjs Updates mocks/assertions for getExecOutput-first fetch and adds coverage for prerequisite recovery scenarios.
actions/setup/js/create_pull_request_bundle_integration.test.cjs Updates the test exec API to honor ignoreReturnCode and to record getExecOutput invocations consistently.
actions/setup/js/push_to_pull_request_branch.cjs Adds bundle prerequisite recovery (extract SHAs from stderr, fetch missing SHAs from origin, retry bundle fetch).
actions/setup/js/push_to_pull_request_branch.test.cjs Updates bundle-fetch expectations (now getExecOutput) and adds a test for prerequisite recovery + retry.
.github/workflows/smoke-otel-backends.lock.yml Lockfile regen/update; includes new Sentry MCP permissions entries.
.github/workflows/mcp-inspector.lock.yml Lockfile regen/update; includes new Sentry MCP permissions entries.
.github/workflows/daily-token-consumption-report.lock.yml Lockfile regen/update; includes new Sentry MCP permissions entries and reordered commented tool list.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

actions/setup/js/create_pull_request.cjs:138

  • The prerequisite-recovery path fetches missing SHAs from origin without providing GIT_CONFIG_* auth env. In runs where clean_git_credentials.sh has stripped credentials from .git/config, git fetch origin <sha> (and the --unshallow inside ensureFullHistoryForBundle) can fail, which would make this recovery unreliable. Consider threading an auth-aware exec options object into applyBundleToBranch (e.g., { env: { ...process.env, ...getGitAuthEnv(config['github-token']) } }) and using it for ensureFullHistoryForBundle(...) and the git fetch origin ... call(s).
      if (prerequisiteCommits.length > 0) {
        core.warning(`Bundle fetch with ${bundleBranchRef} failed due to ${prerequisiteCommits.length} missing prerequisite commit(s); fetching prerequisites from origin and retrying`);
        core.info(`Prerequisite commits: ${summarizeListForLog(prerequisiteCommits)}`);
        core.info(`Fetching ${prerequisiteCommits.length} prerequisite commit(s) from origin`);
        await execApi.exec("git", ["fetch", "origin", ...prerequisiteCommits]);
  • Files reviewed: 10/10 changed files
  • Comments generated: 0

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

…ply-race-issue

# Conflicts:
#	.github/workflows/daily-token-consumption-report.lock.yml
#	.github/workflows/mcp-inspector.lock.yml
#	.github/workflows/smoke-otel-backends.lock.yml

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 15, 2026

@copilot merge main and recompile

Done — merged origin/main (resolved 3 lock-file conflicts by accepting main), rebuilt the binary, and recompiled all 229 workflows successfully. No further changes were needed after the recompile.

@pelikhan pelikhan merged commit d844bba into main May 15, 2026
@pelikhan pelikhan deleted the copilot/fix-bundle-apply-race-issue branch May 15, 2026 13:55
Copilot stopped work on behalf of pelikhan due to an error May 15, 2026 13:55
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.

Bundle-apply race: safe_outputs fetch-depth=1 loses ancestor commits between agent and safe_outputs jobs

3 participants