Skip to content

fix: sync PR head ref on the actual reopen path - #38733

Open
lunny wants to merge 1 commit into
go-gitea:mainfrom
lunny:lunny/fix_38718
Open

fix: sync PR head ref on the actual reopen path#38733
lunny wants to merge 1 commit into
go-gitea:mainfrom
lunny:lunny/fix_38718

Conversation

@lunny

@lunny lunny commented Jul 31, 2026

Copy link
Copy Markdown
Member

The GitHub-flow head-ref consistency check in NewComment is gated on branchOtherUnmergedPR != nil. That value is non-nil exactly when another open unmerged PR already exists for the same head/base branches, which is when the reopen is refused and ReopenIssue is never called. The gate was introduced by 7b17234; before that the block ran on every reopen attempt.

So the check runs in both wrong directions:

  • A genuine reopen never refreshes refs/pull/<index>/head, so a PR whose head branch moved while it was closed is reopened against a stale ref.
  • A refused reopen force-pushes into the base repo for a PR that stays closed, changing what that closed PR shows.

This moves the block onto the path where the PR is actually reopened, and syncs the ref before StartPullRequestCheckImmediately so the patch is regenerated against the correct ref.

Two related fixes in the same block:

  • The head-branch existence check queried the head repo with pull.BaseBranch instead of pull.HeadBranch. A fork without a branch named like the base branch got a bogus "cannot reopen" refusal, while a deleted head branch slipped through into a 500.
  • LoadHeadRepo deliberately swallows ErrRepoNotExist, leaving HeadRepo nil when the fork was deleted. Since the block now runs on the common reopen path, that is guarded and treated like a missing head branch.

The refusal path sets a flash and suppresses the reopen instead of returning without a body, which the form-fetch-action caller cannot handle.

The force-push now reuses pull_service.PushToBaseRepo, still behind the commit-ID comparison so nothing is pushed when the ref is already in sync.

Reported as #38718. The security claim in that report does not hold: NewComment is only reachable via the web /comments route, which enables neither AllowBasic nor AllowOAuth2, so a public-only token cannot authenticate it and the missing TokenIsPublicOnly check there is not exploitable. The reopen regression above is the real defect.

TestPullReopenSyncsHeadRef covers it and fails without the router change.


Generated by Codet

The GitHub-flow head-ref consistency check in NewComment was gated on
branchOtherUnmergedPR != nil, which is exactly when the reopen is refused
and ReopenIssue is never called. So a genuine reopen never refreshed
refs/pull/<index>/head and could reopen a PR against a stale ref, while a
refused reopen force-pushed into the base repo for a PR that stays closed.

Also fix the head-branch existence check, which queried the head repo with
pull.BaseBranch, and guard the nil HeadRepo left behind by LoadHeadRepo when
the fork was deleted.

Assisted-by: Codet:claude-opus-4-6
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. type/bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants