fix(cmdutils): resolve same-host SSH remotes to the right account

Description

When two accounts are configured for the same instance — the second keyed under a synthetic host (for example, gitlab.com-work with api_host: gitlab.com and ssh_host: gitlab.com) whose SSH alias resolves, through ~/.ssh/config, to the shared host — a repository cloned over the SSH alias resolved to the primary account. Repo-scoped commands then acted as the wrong account and returned 404 on the second account's private projects.

The root cause is ordering: the remote resolver ran every SSH remote through ~/.ssh/config translation before matching it against the configured hosts, so an alias was rewritten to the shared host (bound to the primary account) and the second account's entry was never reached. HTTPS remotes were unaffected, because they match literally.

This change establishes the same precedence HTTPS already uses: a remote whose literal SSH host is already a configured host — a config key or an entry's ssh_host — resolves to that account, and only genuinely unknown hosts fall back to ~/.ssh/config translation. The ssh_host lookup map and the remote-host probe are normalized (glinstance.NormalizeHostname); config keys are matched verbatim, since config host lookups are case-sensitive.

Beyond the #8394 (closed) multi-account case, the same precedence fixes two setups that error out on main today:

  • a configured host aliased away in ~/.ssh/config with no ssh_host set — the alias rewrote the host to an unknown one, so no remote matched;
  • gitlab.com aliased to a non-official SSH endpoint such as a corporate proxy — previously only ssh.gitlab.com / altssh.gitlab.com were preserved.

With this precedence in place, the gitlabComSSHAliases allowlist added in 6c7b7d23 is unreachable from its only production caller (knownHosts always contains gitlab.com, so a gitlab.com remote returns before the translator runs), so it, its Translator() branch, and its tests are removed.

Only remotes whose literal host is a configured host change behavior; every other remote resolves exactly as before.

Resolves #8394 (closed)

How has this been tested?

  • Rebased onto main (cherry-picks cleanly); the branch is now one commit ahead.
  • Test_remoteResolverSameHostSSHAlias is now table-driven and covers: the #8394 (closed) second same-host account (verbatim config, including its ssh_host: gitlab.com line), the primary account still resolving over the shared host, a genuine alias for an unknown host still translating (the fallback branch), the two setups that error on main and now work, an ssh_host value matched before translation, and a mixed-case ssh_host value (normalisation of the ssh_host map).
  • The resolver gained a parseSSHConfig func() git.SSHAliasMap seam, defaulted to git.ParseSSHConfig in factory.go; tests inject a fixed alias map, so they no longer mutate HOME / USERPROFILE or read the developer's real ~/.ssh/config.
  • go test ./... — all green (291 packages, 0 failures), including internal/git after removing the altssh translator cases. go vet ./... and gofmt are clean; go build ./cmd/glab succeeds.

Environment: Go 1.26.5 (the version pinned in .tool-versions), Linux.

Edited by tukusejssirs

Merge request reports

Loading
Loading