Skip to content

safe-outputs: resolve base branch from origin/HEAD and harden full patch base selection#34066

Merged
pelikhan merged 14 commits into
mainfrom
copilot/fix-safe-outputs-base-branch-checkout
May 22, 2026
Merged

safe-outputs: resolve base branch from origin/HEAD and harden full patch base selection#34066
pelikhan merged 14 commits into
mainfrom
copilot/fix-safe-outputs-base-branch-checkout

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 22, 2026

safe-outputs could derive base_branch from the currently checked-out branch in side-repo flows, causing wrong workflow checkout targets and misbased patch generation. In some multi-repo cases this cascaded into fallback diffing against an unrelated ancient merge-base, inflating patches to repository-history scale.

  • Base branch resolution: use repo default branch metadata, not working branch

    • Updated get_base_branch side-repo git path to resolve from refs/remotes/origin/HEAD (default branch) instead of rev-parse --abbrev-ref HEAD.
    • Preserves existing fallback chain (payload/API/default env) when origin metadata is unavailable.
  • Patch base selection: reduce unsafe fallback surface in full mode

    • In generate_git_patch full mode, when origin/<base> is unavailable, merge-base now falls back to local refs/heads/<base> before dropping to later strategies.
    • Prevents avoidable escalation into broad cross-repo fallback behavior when a correct local base is present.
  • Behavioral regression coverage

    • Added tests proving:
      • feature-branch checkout + origin/HEAD -> origin/main resolves base_branch=main.
      • missing origin/HEAD falls back to payload default branch.
      • full-mode patch generation succeeds via local base branch when origin/<base> is absent.
    • Updated side-repo handler expectations to reflect default-branch-based patch anchoring.
// before (side-repo path)
git rev-parse --abbrev-ref HEAD  // => feature/FOO-123 (wrong base)

// after
git symbolic-ref refs/remotes/origin/HEAD // => refs/remotes/origin/main
// resolved base_branch => "main"

Copilot AI and others added 4 commits May 22, 2026 16:38
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix safe-outputs base branch extraction issue safe-outputs: resolve base branch from origin/HEAD and harden full patch base selection May 22, 2026
Copilot AI requested a review from pelikhan May 22, 2026 16:49
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot do a deep review of the changes

pelikhan and others added 3 commits May 22, 2026 11:25
… expected git errors

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

Copilot AI commented May 22, 2026

@copilot do a deep review of the changes

Completed a deep review and followed up with a surgical fix in get_base_branch.cjs: removed unreachable fallback logic and suppressed expected origin/HEAD lookup noise while preserving fallback behavior. Validated with targeted tests (get_base_branch, generate_git_patch, safe_outputs_handlers). Addressed in commit 322e8bdf97.

@github-actions github-actions Bot mentioned this pull request May 22, 2026
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

…uts-base-branch-checkout

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

Copilot AI commented May 22, 2026

@copilot merge main and recompile

Done — merged origin/main and ran recompilation/validation (make recompile, make validate-workflows). Applied in commit c5c952a.

@pelikhan pelikhan marked this pull request as ready for review May 22, 2026 21:38
Copilot AI review requested due to automatic review settings May 22, 2026 21:38
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review this issue #34108 in the context if this PR changes and apply fixes if necessary.

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 hardens safe-outputs branch/base resolution for side-repo (multi-checkout) workflows so patches and checkouts anchor to the repository’s default branch (via origin/HEAD) rather than the currently checked-out working branch, and improves full-mode patch base selection to avoid unsafe fallbacks when a suitable local base ref exists.

Changes:

  • Resolve side-repo base_branch from refs/remotes/origin/HEAD (default branch metadata) instead of the checked-out branch.
  • In generateGitPatch full mode, when origin/<base> is missing, compute merge-base against a local <base> branch when available before falling through to broader strategies.
  • Add/adjust regression tests for origin/HEAD behavior and the new local-base fallback in full-mode patch generation.
Show a summary per file
File Description
actions/setup/js/safe_outputs_handlers.test.cjs Updates side-repo patch expectations to reflect default-branch anchoring via origin/HEAD.
actions/setup/js/safe_outputs_handlers.cjs Adjusts handler commentary to match the new base-branch resolution strategy for side-repos.
actions/setup/js/get_base_branch.test.cjs Adds regression tests for origin/HEAD-based default branch resolution and fallback behavior.
actions/setup/js/get_base_branch.cjs Changes side-repo base-branch inference to use refs/remotes/origin/HEAD with suppressed expected git errors.
actions/setup/js/generate_git_patch.test.cjs Adds a full-mode regression test ensuring local base branch fallback when origin/<base> is absent.
actions/setup/js/generate_git_patch.cjs Implements full-mode merge-base fallback to local <base> when origin/<base> cannot be resolved.

Copilot's findings

Tip

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

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment on lines +218 to +238
it("should resolve repository default branch from origin/HEAD instead of checked-out feature branch", async () => {
const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), "gh-aw-get-base-branch-"));
try {
execSync("git init -b main", { cwd: repoDir, stdio: "pipe" });
execSync("git config user.email 'test@example.com'", { cwd: repoDir, stdio: "pipe" });
execSync("git config user.name 'Test User'", { cwd: repoDir, stdio: "pipe" });
fs.writeFileSync(path.join(repoDir, "README.md"), "base\n");
execSync("git add README.md", { cwd: repoDir, stdio: "pipe" });
execSync("git commit -m 'base commit'", { cwd: repoDir, stdio: "pipe" });
execSync("git checkout -b feature/FOO-123", { cwd: repoDir, stdio: "pipe" });

// Simulate checkout metadata where repository default branch is main.
const mainSha = execSync("git rev-parse main", { cwd: repoDir, stdio: "pipe" }).toString().trim();
execSync("git remote add origin https://github.com/test-owner/test-repo.git", { cwd: repoDir, stdio: "pipe" });
execSync(`git update-ref refs/remotes/origin/main ${mainSha}`, { cwd: repoDir, stdio: "pipe" });
execSync("git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main", { cwd: repoDir, stdio: "pipe" });

const { getBaseBranch } = await import("./get_base_branch.cjs");
const result = await getBaseBranch({ owner: "test-owner", repo: "test-repo" }, { preferCheckedOutBranch: true, cwd: repoDir });

expect(result).toBe("main");
Comment on lines 23 to +28
* lookup (step 6b) use this instead of context.repo, which is needed for
* cross-repo scenarios where the target repo differs from the workflow repository.
* @param {{preferCheckedOutBranch?: boolean, cwd?: string}|null} [options] - Optional resolution hints.
* When preferCheckedOutBranch is true and cwd is set, git is queried directly for the
* checked-out branch in that repository before falling back to the repository default branch.
* When preferCheckedOutBranch is true and cwd is set, git is queried for
* refs/remotes/origin/HEAD in that repository to derive the repository default branch
* before falling back to payload/API-based default branch resolution.
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 22, 2026

@copilot review this issue #34108 in the context if this PR changes and apply fixes if necessary.

Reviewed #34108 against this PR. No additional fix is needed here: this PR only changes side-repo default-branch resolution and full-mode merge-base fallback, while push_to_pull_request_branch already uses the incremental origin/<pr-head-branch>..HEAD path and records diff_size from that incremental base rather than from the target repo base branch. I re-ran the relevant coverage locally: get_base_branch.test.cjs, generate_git_patch.test.cjs, git_patch_integration.test.cjs, safe_outputs_handlers.test.cjs, and push_to_pull_request_branch.test.cjs.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all pull request review comments

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

Copilot AI commented May 22, 2026

@copilot review all pull request review comments

Addressed the valid review feedback in 450a3a7: hardened the get_base_branch origin/HEAD tests with a core stub so the git path is exercised, renamed the side-repo option to preferLocalDefaultBranchMetadata, and kept preferCheckedOutBranch as a backward-compatible alias. Re-ran npm run typecheck plus vitest for get_base_branch.test.cjs and safe_outputs_handlers.test.cjs.

@pelikhan pelikhan merged commit 7b925a9 into main May 22, 2026
7 checks passed
@pelikhan pelikhan deleted the copilot/fix-safe-outputs-base-branch-checkout branch May 22, 2026 22:30
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.

safe-outputs: base_branch derived from target repo HEAD causes extract-base-branch to checkout wrong branch

3 participants