From 9f19ab80c46c455ab7f24d49f287320c57189f0d Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 18 Aug 2026 13:36:35 +0900 Subject: [PATCH] git: verify that the fetched pull request ref matches the tip declared in the signed event, and force-update it so rebased updates work. --- git.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/git.go b/git.go index de6df05..bd6fbbf 100644 --- a/git.go +++ b/git.go @@ -2605,10 +2605,22 @@ func gitFetchPullRequestIntoRef(ctx context.Context, repo nip34.Repository, prEv // first try fetching the server ref that send/update pushed the tip to, // which works even on servers that don't serve arbitrary commit hashes log("fetching %s from %s...\n", color.CyanString(serverRef), color.BlueString(url)) - fetchRefCmd := exec.Command("git", "fetch", url, fmt.Sprintf("%s:%s", serverRef, refName)) + fetchRefCmd := exec.Command("git", "fetch", url, fmt.Sprintf("+%s:%s", serverRef, refName)) fetchRefCmd.Stderr = os.Stderr if err := fetchRefCmd.Run(); err == nil { - return refName, commit, nil + if !gitHashRe.MatchString(commit) { + return refName, commit, nil + } + + // make sure the server actually served the tip declared in the signed event + // (the declared tip may be abbreviated, so compare by prefix) + if output, err := exec.Command("git", "rev-parse", refName).Output(); err == nil && + strings.HasPrefix(strings.TrimSpace(string(output)), commit) { + return refName, commit, nil + } + + // it points elsewhere, refuse it and try the declared commit directly below + lastErr = fmt.Errorf("ref %s from %s doesn't match the declared tip %s", serverRef, url, shortCommitID(commit, 8)) } else { lastErr = err }