Skip to content

fix(gitops): repository identity and complete repository listing - #104

Merged
atbagan merged 2 commits into
mainfrom
fix/git-provider-authority
Aug 31, 2026
Merged

atbagan merged 2 commits into
mainfrom
fix/git-provider-authority

Conversation

@atbagan

@atbagan atbagan commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Three Git provider correctness defects, all in the same area.

Recorded repository URL was hardcoded to github.com

EnableGitOps and EnableManagementGitOps stored https://github.com/<owner>/<repo> for the cluster regardless of the configured provider, so a GitLab install recorded GitHub URLs for every cluster it bootstrapped. GetStatus prefers that stored field over the live Flux GitRepository, so the console showed the wrong Git host.

ProviderWebBaseURL and RepositoryWebURL derive the URL from the configured provider, handling that the GitHub API URL is not the web host (https://api.github.com, and /api/v3 for Enterprise) while the GitLab URL is the instance itself.

Export truncated nested group paths and could cross hosts

The addon and release export paths parsed the stored URL by taking its last two path segments, rewriting group/subgroup/service/repo into subgroup/repo. On GitLab the project ID is the full path, so export addressed a project that usually does not exist.

Export also combined a stored repository URL with the globally configured provider client without checking the two agreed. ResolveRepoForProvider preserves the full path and returns a typed ProviderHostMismatchError when the stored repository is hosted somewhere other than the configured provider. Butler refuses rather than addressing the same path on the configured host: that path is either absent or belongs to somebody else. This matters while a platform moves between providers and some clusters are still backed by the old host.

parseGitHubURL is removed.

Repository listing stopped at 200

Listing walked pages correctly but returned early once it had collected 200 entries, mid page. A caller could not distinguish that from a complete list, so a group with more than 200 projects appeared to contain 200 and the rest looked absent.

The cap is removed for both providers. The walk continues until the provider reports no next page. A page bound remains as a guard, but exceeding it returns RepositoryListTooLargeError rather than a partial list.

Scope

No change to cluster lifecycle or Flux reconciliation; neither reads this configuration. No change to the single provider per install model, and no change to how EnableGitOps bootstraps Flux.

Tests

Provider URL handling across public GitHub, GitHub Enterprise, GitLab SaaS, self hosted GitLab, nested groups, scp style remotes, malformed and unsupported providers. Pagination against a fake GitLab serving real pagination headers: empty, single, sub page, exact page size, one over, 200, 201, 272, 1000, and a mid walk failure that must not yield a truncated result. Full suite passes.

…gured provider

Butler holds one Git provider per install, but two code paths ignored it.

Enabling GitOps on a cluster recorded the repository as
https://github.com/<owner>/<repo> regardless of which provider was
configured, so a GitLab install stored GitHub URLs for every cluster it
bootstrapped. The console reads that field in preference to the live Flux
source, so operators were shown the wrong Git host. The URL is now derived
from the configured provider, covering public GitHub, GitHub Enterprise
(whose API URL carries an /api/v3 suffix), GitLab SaaS and self-hosted
GitLab.

The addon and release export paths parsed the stored URL by taking its last
two path segments. That silently rewrote a nested GitLab group path such as
group/subgroup/service/repo into subgroup/repo, addressing a project that
usually does not exist. Resolution now preserves the full path, which is the
project ID the GitLab API expects.

Export also used the stored repository URL together with the globally
configured provider client, with no check that the two agreed. When a
repository is hosted somewhere other than the configured provider, Butler
now refuses instead of addressing the same path on the configured host: that
path is either absent or belongs to somebody else. This matters while a
platform is moving between providers, when some clusters are still backed by
the old host.

Cluster lifecycle and Flux reconciliation are untouched; neither reads this
configuration.
@atbagan
atbagan force-pushed the fix/git-provider-authority branch from e60ec78 to 75e09b3 Compare August 31, 2026 13:59
Repository listing walked pages correctly but returned early once it had
collected 200 entries, mid page. A caller could not tell that short list from a
complete one, so an operator configuring a group with more than 200 projects
was shown a silently truncated set and the repositories missing from it simply
looked absent. On a group with 272 projects the listing returned 200.

The cap is removed for both providers. The walk now continues until the
provider reports no next page. A page bound remains as a guard against a
looping or pathological response, but exceeding it returns
RepositoryListTooLargeError rather than a partial list, on the same principle:
a short answer that looks complete is worse than a clear failure. An error on
any page already aborted the whole listing and still does.

Page size and the bound move to shared constants, since both providers page the
same way.

Tests drive a fake GitLab that serves the real pagination headers, covering
empty, single, sub page, exact page size, one over, the old cap, one over the
old cap, the 272 case this was found on, and a thousand, plus a mid walk
failure that must not yield a truncated result.
@atbagan atbagan changed the title fix(gitops): record and resolve repository identity against the configured provider fix(gitops): repository identity and complete repository listing Aug 31, 2026
@atbagan
atbagan merged commit 8ba169f into main Aug 31, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant