Skip to content

fix(server): self-hosted GitLab merge requests sync when the SSH host differs from the web host - #35009

Open
juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-16463-a1794473343
Open

juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-16463-a1794473343

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Two gaps caused the bug. (1) refineUnknownGitLabRemote only accepted a glab login on the remote's own host and remoteRefinementArgs always asked glab about that host, ignoring context.requestedHost. GitLab discovery now asks glab auth status --hostname <requestedHost> when a requested host is set, accepts a login on that host, and claims the remote with baseUrl https://. Without a requested host, behaviour is unchanged. (2) GitLab has no resolveRemoteWebHost, so PullRequestService.resolveRemoteHosts resolved the discovered GitLab context with host null and requireProject found no project on the MR host (PullRequestUnavailableError provider-unsupported). For a discovered context that carries a requestedHost (only set for SSH remotes), resolveCandidate now uses the host of discovery's base URL when the provider has no resolveRemoteWebHost. In practice only GitLab reaches this: GitHub and Forgejo implement resolveRemoteWebHost, and GitCafe and Origin never claim unknown remotes. HTTP remotes and remotes without a requested host keep their current host. No new regex or parser. No visible UI change beyond the linked MR's state loading.

Fixes #16463

Reproduction on main

Commit b68aedf (origin/main). Started T3CODE_DEV_SEED=0 vp run dev in a fresh worktree; glab on the VM is signed in to gitlab.com only. Added two projects via t3 project add: 'split' with remote git@git.example.com:gitlab-org/cli.git (unknown SSH host, as in the report) and 'control' with remote git@gitlab.com:gitlab-org/cli.git, and started a devReplay thread in each via t3 thread start. Called the MCP tool link_pull_request (the reporter's step) through a scratch MCP client. Linking https://gitlab.com/gitlab-org/cli/-/merge_requests/2000 gave state 'merged' on both threads, because gitlab.com is a public host read without a checkout. Linking https://gitlab.example.com/gitlab-org/cli/-/merge_requests/123 (a self-hosted web host that differs from the SSH host) on the split thread left list_thread_pull_requests showing state null and title null. In the server trace (.t3/userdata/logs/server.trace.ndjson), PullRequestService.canonicalRef and PullRequestSyncReactor.syncGroup exit with Failure 'PullRequestUnavailableError: Change requests cannot be browsed for this project's host yet', matching the reporter's corrected trace. The existing branch factory/repro-16463 (ee4b37a) holds two tests; both fail on b68aedf: gitLabDiscovery.test.ts 'claims an SSH remote whose web host is the one glab is signed in to' and PullRequestService.test.ts 'reads a GitLab merge request on the web host of a checkout cloned over SSH'.

Evidence

Being captured: before and after in the real app. This section is filled in before the pull request can merge.

Tests

Bug reproduced through the two repro tests failing on the repro branch, not in a running app. packages/source-control-gitlab: vp test run src/server 248/248 pass (includes 'claims an SSH remote whose web host is the one glab is signed in to', failing before). apps/server: vp test run src/pullRequest/PullRequestService.test.ts src/sourceControl 180/180 pass (includes 'reads a GitLab merge request on the web host of a checkout cloned over SSH', failing before). vp run check:changed: format, lint, knip, graphql, typecheck (11 packages) and tests (5 files, 141) all pass.

Not in this change

  • Like Forgejo's existing requestedHost matching, an unrelated unknown SSH project may be claimed as GitLab for a link host glab is signed in to; requireProject still prefers a project whose repository name matches.
  • GitLab still has no resolveRemoteWebHost of its own; adding one would also need the repro test's provider mock changed.

AI-assisted; verified with the tests and tools listed above.

Failing tests for #16463: an unknown SSH remote whose web host is the
one glab is signed in to is not identified as GitLab, and a linked merge
request on that web host is routed to the SSH host and reported as
provider-unsupported.

AI-assisted; verified with the tests and tools listed above.
… differs from the web host

GitLab's unknown-remote refinement now asks glab about the host a linked
merge request names and claims the remote on that web host, and a remote
discovery placed for a requested host is served from discovery's base URL
when its provider names no web host of its own.

Fixes #16463

AI-assisted; verified with the tests and tools listed above.
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Nov 12, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e0d8d07

Macroscope's review found this PR approvable — Restores self-hosted GitLab merge-request syncing when SSH and web hosts differ, using a matching authenticated CLI host. The change is narrowly scoped to requested-host discovery and leaves ordinary remote resolution unchanged.

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

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: b68aedf · PR result: e0d8d07 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

GitLab discovery now checks authentication against a requested web host and uses that host in the refined provider. Pull-request summary resolution can use the refined provider’s base URL host when remote web-host resolution is unavailable.

Changes: GitLab host resolution

Layer / File(s) Summary
Requested-host GitLab discovery
packages/source-control-gitlab/src/server/GitLabSourceControlProvider.ts, packages/source-control-gitlab/src/server/gitLabDiscovery.test.ts
GitLab refinement uses the requested host for glab auth status --hostname and sets the refined provider’s base URL to that host. A test covers an SSH remote whose host differs from the authenticated web host.
Summary lookup host propagation
apps/server/src/pullRequest/PullRequestService.ts, apps/server/src/pullRequest/PullRequestService.test.ts
When resolveRemoteWebHost is unavailable, the service uses the lowercased host from the provider’s base URL if the request specified a host. A test checks that summary lookup receives the requested host.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Possibly related issues

  • Issue 17209: The requested-host path now scopes glab auth status to that host. The no-requested-host path remains unchanged, so the reported offline-host timeout may still occur there.

Suggested reviewers: maria-rcks, mwolson, tonybynmp4

Merge Risk: Minimal · up to e0d8d

This change lets linked self-hosted GitLab merge requests sync when the SSH host differs from the web host. Existing behavior is preserved when no specific host is requested. No merge-blocking risk was identified.

Pre-merge checks: Passed 3 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Linked Issues check Inconclusive [#16463, SSH/web host mismatch] Met in code. GitLab discovery now runs glab auth status --hostname <requestedHost> when a requested host is set. It claims the remote with baseUrl `https://<requested… Confirm with the issue owner whether the Forgejo/Gitea CLI non-abort item remains an active requirement. If it does, add a code path or test that shows GitLab detection and PR sync continue when tea is absent. Also show that merged GitLab…
Passed Passed checks: 3 passed

Check name Status Explanation
Title check Passed The title names the actual change: self-hosted GitLab merge requests failed to sync when the SSH host differed from the web host, and the fix targets that. It follows the conventional commit form. The…
Description check Passed The description follows the template. It states the problem with the reproduction steps and environment. It explains the change in two parts, and it states the scope with a linked issue (#16463). It g…
Out of Scope Changes check Passed All changed areas connect to the linked bug. The changes are in GitLab remote discovery (refineUnknownGitLabRemote, remoteRefinementArgs), host resolution in PullRequestService.resolveCandidate,…
Full details: Title check

Explanation

The title names the actual change: self-hosted GitLab merge requests failed to sync when the SSH host differed from the web host, and the fix targets that. It follows the conventional commit form. The title is specific and matches the changeset and the linked issue. It is long (95 characters), but it stays on the main change.

Full details: Description check

Explanation

The description follows the template. It states the problem with the reproduction steps and environment. It explains the change in two parts, and it states the scope with a linked issue (#16463). It gives verification with specific test names, pass counts, and a repro branch. The Evidence section says before/after capture is still pending and that it must be filled before merge. The template asks for before/after evidence for UI changes. This PR says it has no visible UI change beyond the linked MR state loading, so the pending evidence is a minor gap. The template's end-of-section note asks for the model and harness used, and the description says only 'AI-assisted' without naming the model and harness. The description is mostly complete with minor gaps.

Resolution

Optional: fill in the Evidence section or state why no before/after capture is needed, and name the model and harness used, as the template asks.

Full details: Out of Scope Changes check

Explanation

All changed areas connect to the linked bug. The changes are in GitLab remote discovery (refineUnknownGitLabRemote, remoteRefinementArgs), host resolution in PullRequestService.resolveCandidate, and matching tests in gitLabDiscovery.test.ts and PullRequestService.test.ts. The resolveCandidate fallback applies only to discovered contexts with a requestedHost and a provider without resolveRemoteWebHost. The PR description states that only GitLab reaches this path. HTTP remotes and remotes without a requested host keep their current behavior. No unrelated files are in the summary.

Full details: Linked Issues check

Explanation

[#16463, SSH/web host mismatch] Met in code. GitLab discovery now runs glab auth status --hostname &lt;requestedHost&gt; when a requested host is set. It claims the remote with baseUrl https://&lt;requestedHost&gt;. resolveCandidate uses the discovery base URL host when the provider has no resolveRemoteWebHost. The repro test 'claims an SSH remote whose web host is the one glab is signed in to' and the PullRequestService test 'reads a GitLab merge request on the web host of a checkout cloned over SSH' are reported to fail on main and pass at head. The author reports both pass. Tests were not rerun in this review. [#16463, Forgejo/Gitea CLI] The issue Expected behavior still says an unavailable optional Forgejo/Gitea CLI must not abort GitLab detection or PR sync. The PR does not change Forgejo CLI error handling. The issue correction says the missing tea error is recovered and is not the verified problem. The requirement status is therefore unclear. [#16463, settlement] The issue expects the eligible idle thread to settle after merge. No test in the PR covers settlement. Settlement may follow from the state load fix, but this is not shown.

Resolution

Confirm with the issue owner whether the Forgejo/Gitea CLI non-abort item remains an active requirement. If it does, add a code path or test that shows GitLab detection and PR sync continue when tea is absent. Also show that merged GitLab MR state settles an eligible idle thread, or confirm that settlement is out of scope.

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between b68aedf and e0d8d07.

Files selected for processing: 4

  • apps/server/src/pullRequest/PullRequestService.test.ts
  • apps/server/src/pullRequest/PullRequestService.ts
  • packages/source-control-gitlab/src/server/GitLabSourceControlProvider.ts
  • packages/source-control-gitlab/src/server/gitLabDiscovery.test.ts

Limit details: You’ve used all 10 included reviews currently available.

@juliusmarminge

Copy link
Copy Markdown
Member Author

The automated pipeline stopped on this pull request and will not merge it:

the fix is written and reviewed, but proving it needs something no worker has:

  • Permanent blocker: proving this fix requires a reachable self-hosted GitLab instance, an authenticated glab account for its web hostname, and an accessible merge request whose checkout uses a different SSH hostname. The VM provides only gitlab.com authentication; the supplied self-hosted example hostname does not resolve and is unauthenticated.
  • Linked merge request status synchronization and automatic thread settlement remain unverified on both commits.

It stays open for a person to finish or close.

This branch has not been deployed

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

Labels

size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Split SSH/API hostnames leave self-hosted GitLab MR links unsynced

1 participant