Repository navigation
fix(forge): honor project forge_override for self-hosted forges - #14620
Conversation
|
I'm the reporter of #14319. Built this branch on Windows ( One remaining issue that looks related to URL construction, in case it's in scope here: The "View MR" button on the virtual branch (in the side column) opens GitLab at a truncated host — just The "Open MR in browser" button in the merge column opens the correct full URL ( So the two buttons seem to build the MR URL via different paths: the merge-column one resolves the self-hosted host correctly, but the virtual-branch "View MR" one keeps only the first host label and drops the rest of the domain. Happy to grab logs or test a follow-up change if useful. (Host redacted — my real instance is an internal |
|
Update / root-cause find, reporter of #14319 here. I tracked down what actually triggered this on my setup: my git That seems to explain the original error: in 0.20.1 forge resolution became host-based, and my short origin host matched neither the built-in So the PR still looks valuable as a robustness fallback (honor the override when the origin host can't be matched — mirrors, SSH host aliases, etc.), even though my specific breakage came down to a misconfigured origin. One related note on the two MR buttons: "View MR" (virtual branch, side column) appears to build its URL from the raw origin host, while "Open MR in browser" (merge column) uses the resolved forge instance URL. That's why they differed for me — with origin fixed to the FQDN, both work now. Might still be worth having "View MR" use the resolved forge URL for consistency, but it's no longer broken on my end. |
|
Thanks for building it and confirming — glad the GitLab section and forge detection are back on your self-hosted instance. And thanks for chasing the root cause. It lines up with the fix: when the origin host doesn't match a built-in pattern or a configured account host — as a short or aliased host won't — 0.20.1 resolved to no forge and never consulted the saved override. This PR restores that fallback, so a saved forge preference still resolves in those cases (mirrors, SSH host aliases, short internal hostnames). The "View MR" host truncation looks like a separate area from this PR (which changes forge resolution, not MR-URL construction) — probably best as its own issue. I'd want to trace both buttons' URL paths before proposing a fix, so it targets the right spot. |
|
Thanks @ameyypawar for the fix, and @PetrAltman for taking a look. Something I'd feel uncomfortable with is that support for the forge override now is explicitly needed in |
|
Bump on this PR if possible. I believe I'm running into this when attempting to run against a hosted GitHub Enterprise account. |
|
@alec-chernicki Could you try this PR locally and see if it solves your problem? And even if not, maybe it's not far from actually working. With that incentive, it should be easier to find a reviewer. |
|
@Byron, I ran this branch against the same GitHub Enterprise account, and I now see all the PR features in the app. This fix looks like it works. |
1753641 to
4262607
Compare
GitButler 0.20.1 collapsed the frontend forge plumbing into Rust (547b873), but the Rust resolver `derive_forge_repo_info` never consumed the project's `forge_override`. A self-hosted forge whose host isn't a recognized keyword (e.g. GitLab on a private host), with no configured account, therefore resolves to no forge - the backend reports "No forge could be determined" and the settings UI hides the GitLab configuration, which is gated on `forgeInfo?.name === "gitlab"`. Resolve the forge type in one place, `resolve_forge_name`: the URL host first, then a configured account's custom host, and finally the project's saved override as a last resort - mirroring pre-0.20.1's `if forgeType === "default" && forgeOverride`. A recognized host or a matching account always wins, so a stale override can't mislabel a repo whose forge is already known. Owner/repo still come from the URL, so the override path produces the same repository info the account path would. Thread the override from `legacy_project.forge_override` through `forge_info`, `compare_branch_url`, and the forge API paths in but-api and the CLI. Pure-URL identity comparison (`remote_urls_match`) passes `None`.
573acb0 to
802f3b6
Compare
ReviewI started with a project whose remote URL was set to From there I could set the override in the Tauri app (but not in Lite):
Without that, reviews could already not be retrieved, with it, that error would disappear (but I didn't check if the disappearance isn't some sort of caching effect).
The key change in is The security fixIt appears that there was a latent issue with the user account matching, that was now exposed with forge overrides. It could lead to enterprise account tokens being sent to public hosts, as the URL for the remote was rebuilt based on the overridden forge, while the account may have been matched based on the actual host. Notes for the (additional) Reviewer
Addressed Codex Review Comments
|
Mostly rubber-stamped the additional tests, but looked at the refactoring in detail. <!-- agent --> Retain the repository host and port in ForgeRepoInfo and resolve stored accounts against that server before live API calls. This prevents overrides and first-account fallback from sending private review data to another forge instance; a mismatched preferred account no longer falls back. Preserve override-only display and templates, cache-only reads, and unsupported-forge behavior. Check that review base and push repositories share a server, including known API ports and public SSH aliases. Assisted-by: GPT 6.1 Sol
99229e4 to
7d15d92
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7d15d92. Configure here.
7d15d92 to
176c725
Compare
<!-- agent --> Reuse self-hosted review remotes across SSH and HTTPS through the existing repository compatibility check. Remove PartialEq so callers must choose repository compatibility explicitly instead of relying on strict API-port equality. Assisted-by: GPT 6.1 Sol
This makes source files more readable and less imposing. It's also now clear that unit-tests are only for non-public APIs. Assisted-by: GPT 6.1 Sol
<!-- agent --> The forge override now affects cached forge identity and URLs. Saving or clearing it must invalidate those queries, along with review, repository, and CI data, so integration recovers without reopening the project. Assisted-by: GPT 6.1 Sol
Looked at all production code changes and they made sense, rubber-stamped tests. <!-- agent --> Send partial project updates so unrelated settings no longer carry saved forge overrides into cache invalidation. Ignore null overrides while preserving refreshes for explicit set/clear operations. The description-input regression reproduces the extra fetches; targeted desktop tests, Svelte checks, ESLint, and Prettier validate the fix. Assisted-by: GPT 6.1 Sol
<!-- agent --> An override-resolved forge looked automatically detected after reopening project settings, hiding the selector needed to correct or clear it. Keep the selector available for saved overrides and describe that state without claiming the provider was automatically detected. Assisted-by: GPT 6.1 Sol
176c725 to
0073388
Compare



Fixes #14319. Opening as a draft for review — the direction was confirmed by the maintainer investigation in the issue and by the reporter, so I'd welcome a self-hosted test and any steer on the shape before marking it ready.
Bug
0.20.1 regressed self-hosted GitLab: a project with
forge_override = gitlabshows "No forge could be determined" and the GitLab settings section disappears.Cause
547b873 moved forge resolution into Rust, but
but_forge::derive_forge_repo_info(url)never consumed the project'sforge_override. For a self-hosted host that isn't a recognized keyword (gitlab.com/gitlab.*) and before an account is configured, it returnsNone— soforge_info()returnsNoneandForgeForm.sveltehides the GitLab config (gated onforgeInfo?.name === "gitlab").Fix
Resolve the forge type in one place,
resolve_forge_name, in priority order:github.com,gitlab.*, …),forge_override— last resort, mirroring pre-0.20.1'sif forgeType === "default" && forgeOverride.A recognized host or a matching account always wins, so a stale override can't mislabel a repo whose forge is already known. Owner/repo still come from the URL's
GenericProviderregardless of how the type is resolved, so the override path produces the sameForgeRepoInfothe account path would.The override (
legacy_project.forge_override) is threaded throughforge_info,compare_branch_url, and the forge API paths in but-api and the CLI auth path. The pure-URL identity comparison (remote_urls_match) passesNone.Tests
resolve_forge_nameprecedence — the override resolves a self-hosted host; a recognized host and a matching account each win over the override; none →Nonederive_forge_repo_infoon a self-hosted URL (owner/repo parsed correctly)build_base_urlbuilds the self-hosted web URL from the override-derived infofrom_override_stris case/whitespace-insensitivecargo check --workspaceand clippy are clean.Notes / open questions
git.azure.company.com) is still detected as that forge and the override won't correct it — a pre-existing limitation, left out of scope here.Option<ForgeName>parameter throughderive_forge_repo_infoand its callers; happy to switch to a centralizedctx-level helper if that's preferred.The reporter offered to test a build on their self-hosted instance — that would be the strongest confirmation.
Note
High Risk
Changes forge detection, credential selection, and cache invalidation across desktop and core forge/review paths; mis-resolution or auth matching could break integrations or cause wrong-host API use.
Overview
Restores self-hosted forge detection when a project has a saved
forge_overridebut the remote host is not recognizable on its own (#14319). Rust forge resolution now takes an optional override as a last resort after URL host detection and matching integration accounts, and that override is passed through forge info, compare URLs, reviews/CI, and related API paths.The forge layer also tightens repository and credential matching: richer
ForgeRepoInfo(host/port), explicit same-server/same-repository checks, andresolve_accountso live API calls only use accounts that match the repo’s forge and host (with safer remote reuse across protocols).On desktop, project settings send partial
ProjectUpdatepayloads instead of full project objects, and RTK Query invalidates forge caches only when the override actually changes—so editing name/description no longer refetches PRs/checks. Forge settings UI stays available when an override is saved even if auto-detection would hide the picker.Reviewed by Cursor Bugbot for commit 0073388. Bugbot is set up for automated code reviews on this repo. Configure here.