Skip to content

Detect pull requests against upstream repositories#3907

Open
jakeleventhal wants to merge 1 commit into
pingdotgg:mainfrom
jakeleventhal:t3code/detect-upstream-fork-prs
Open

Detect pull requests against upstream repositories#3907
jakeleventhal wants to merge 1 commit into
pingdotgg:mainfrom
jakeleventhal:t3code/detect-upstream-fork-prs

Conversation

@jakeleventhal

@jakeleventhal jakeleventhal commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • detect pull requests opened from a fork against the conventional upstream GitHub remote
  • qualify fork branch lookups as owner:branch and target GitHub CLI operations at the upstream repository
  • keep unrelated remotes named upstream from overriding a valid GitHub origin

Root cause

PR discovery derived the fork-qualified head selector, but GitHub CLI still resolved the repository from the local checkout's origin. In a fork checkout, that queried the fork rather than the upstream repository where the pull request exists.

Impact

Branches pushed to a fork now show their upstream pull request metadata in T3 Code. Related PR operations consistently use the upstream repository context.

Validation

  • focused Git manager fork/upstream regression test
  • GitHub CLI, GitHub source-control provider, and provider registry suites
  • vp check
  • vp run typecheck

Note

Medium Risk
Changes core PR status and GitHub CLI routing for fork workflows; behavior is scoped to upstream context and covered by new tests, but mistakes could mis-associate PRs or hit the wrong repo.

Overview
Fork checkouts can now surface pull requests opened against the upstream repo instead of only querying the fork via origin.

GitHub CLI gains an optional repository argument on PR/repo commands; when set, gh gets --repo owner/name so lookups run against the correct repository.

Provider registry prefers a conventional GitHub upstream remote (with GitHub origin) over origin alone, and the GitHub provider threads that repo into list/get/create/checkout/default-branch calls when the active context is upstream.

Git manager treats cross-repo PR detection relative to the upstream remote’s repo when it exists (not only origin), keeping owner:branch head selectors aligned with fork workflows.

Regression tests cover fork/upstream status, CLI args, provider listing, and registry resolution; unrelated upstream remotes (e.g. Azure DevOps) still do not override GitHub origin.

Reviewed by Cursor Bugbot for commit 5e512ba. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Detect pull requests against upstream repositories in conventional GitHub fork setups

  • GitHubSourceControlProvider now detects when the Git context references an upstream remote with a GitHub URL, and passes --repo <owner/name> to all gh commands (list, view, create, checkout, default branch).
  • selectProviderContext in SourceControlProviderRegistry.ts prefers the upstream remote over origin when both are GitHub remotes.
  • GitManager resolves the upstream repository context and uses it for cross-repository (fork) detection when available.
  • GitHubCli method signatures are extended with an optional repository parameter, inserted as --repo or a positional arg where appropriate.
  • Behavioral Change: PRs in conventional fork setups (contributor origin, canonical upstream) will now be listed and created against the upstream repository rather than origin.
📊 Macroscope summarized 5e512ba. 4 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b323032d-1e01-4bfc-a263-c4b3476f1377

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 12, 2026
@jakeleventhal jakeleventhal marked this pull request as ready for review July 12, 2026 03:44
}

const origin = candidates.find((candidate) => candidate.remoteName === "origin");
const conventionalGitHubUpstream = candidates.find(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium sourceControl/SourceControlProviderRegistry.ts:145

conventionalGitHubUpstream overrides origin whenever an upstream remote and origin are both GitHub repositories, even when upstream is an unrelated GitHub repo (e.g. origin=acme/app, upstream=acme/shared-template). The returned context points at upstream, so list/create/checkout/resolve operations target acme/shared-template instead of the checked-out origin repository. This heuristic only verifies the remote name and provider kind, not that upstream is actually the fork parent of origin. If this convention is intentional, consider documenting the rationale; otherwise the upstream heuristic should only apply when upstream is demonstrably the parent of origin (or at minimum not preempt origin).

Also found in 1 other location(s)

apps/server/src/git/GitManager.ts:874

targetRepository always prefers any parseable remote named upstream, without checking that it is related to origin. If a checkout tracks origin and also has an unrelated GitHub upstream remote, remoteRepository (the origin) is compared against that unrelated repository, so isCrossRepository becomes true. This changes PR lookup to fork-qualified/cross-repository matching (and, with the accompanying provider targeting, queries the unrelated repository), causing valid same-repository PR metadata from origin to be missed. This directly contradicts the PR's stated requirement to keep unrelated upstream remotes from overriding a valid GitHub origin.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/sourceControl/SourceControlProviderRegistry.ts around line 145:

`conventionalGitHubUpstream` overrides `origin` whenever an `upstream` remote and `origin` are both GitHub repositories, even when `upstream` is an unrelated GitHub repo (e.g. `origin=acme/app`, `upstream=acme/shared-template`). The returned context points at `upstream`, so list/create/checkout/resolve operations target `acme/shared-template` instead of the checked-out `origin` repository. This heuristic only verifies the remote name and provider kind, not that `upstream` is actually the fork parent of `origin`. If this convention is intentional, consider documenting the rationale; otherwise the `upstream` heuristic should only apply when `upstream` is demonstrably the parent of `origin` (or at minimum not preempt `origin`).

Also found in 1 other location(s):
- apps/server/src/git/GitManager.ts:874 -- `targetRepository` always prefers any parseable remote named `upstream`, without checking that it is related to `origin`. If a checkout tracks `origin` and also has an unrelated GitHub `upstream` remote, `remoteRepository` (the origin) is compared against that unrelated repository, so `isCrossRepository` becomes true. This changes PR lookup to fork-qualified/cross-repository matching (and, with the accompanying provider targeting, queries the unrelated repository), causing valid same-repository PR metadata from `origin` to be missed. This directly contradicts the PR's stated requirement to keep unrelated `upstream` remotes from overriding a valid GitHub `origin`.

@macroscopeapp

macroscopeapp Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. This PR changes runtime behavior by preferring 'upstream' over 'origin' remotes for PR operations. An unresolved review comment identifies that the heuristic doesn't verify upstream is actually the fork parent, which could cause operations to target unrelated repositories.

You can customize Macroscope's approvability policy. Learn more.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e512ba2d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +145 to +149
const conventionalGitHubUpstream = candidates.find(
(candidate) =>
candidate.remoteName === "upstream" &&
candidate.provider.kind === "github" &&
origin?.provider.kind === "github",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate upstream before overriding origin

When a checkout has a valid GitHub origin plus a stale/reference upstream that is also GitHub but not the fork base, this condition still selects upstream solely by provider kind. bindProviderContext then sends that context into GitHub operations, and GitHubSourceControlProvider.repositoryFromContext turns it into --repo <upstream>, so status/default-branch/PR create/checkout are run against the wrong repo even though origin was valid. The guard needs to prove the upstream is the conventional base, or fall back to origin, rather than just matching kind === "github".

Useful? React with 👍 / 👎.

Comment on lines +103 to +104
context?.remoteName === "upstream"
? (parseGitHubRepositoryNameWithOwnerFromRemoteUrl(context.remoteUrl) ?? undefined)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve hosts for self-hosted upstream repos

For a GitHub Enterprise fork where the remotes are on a host like github.example.test, the registry still binds the provider to the upstream context, but this parser returns undefined because the shared helper only recognizes github.com URL forms. The new withRepositoryFromContext path then omits repository, so the gh pr ... calls fall back to the local checkout’s origin and continue querying/creating PRs in the fork instead of the upstream repo; build a host-qualified [HOST/]OWNER/REPO value from the context for self-hosted GitHub (the gh manual documents that --repo form: https://cli.github.com/manual/gh_pr).

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant