Skip to content

Send GitLab the right auth on the right host - #2125

Merged
ppXD merged 1 commit into
mainfrom
fix/send-gitlab-the-right-auth-on-the-right-host
Oct 18, 2026
Merged

ppXD merged 1 commit into
mainfrom
fix/send-gitlab-the-right-auth-on-the-right-host

Conversation

@ppXD

@ppXD ppXD commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Send each GitLab call the one credential header its type names (PRIVATE-TOKEN for personal, project and group access tokens, Authorization: Bearer for OAuth, never both), through NGitLab (GitLabRequestOptions) and every raw call (GitLabHttp). Behind a redirecting base URL a PAT used to work and an OAuth token read 401, and GitLab 13.0 to 17.7 refused a 41+ character access token sent as a Bearer.
  • Follow a redirect only inside one origin, with the credential attached again. A redirect to another scheme, host or port, and the next page of a list whose Link: rel="next" names another origin, are refused before any credential is attached and fail with the typed provider_base_url_redirects, naming the URL. NGitLab never re-sends a write; a raw write is repeated only by a 307 or 308, and a 301, 302 or 303 that would turn it into a GET is refused instead of being read as the write's answer (OriginScopedRedirectHandler.RepeatsWritesOnly, opt-in).
  • A tokened git clone, ls-remote or push whose remote sends git to another origin now fails naming that redirect (same code, with the origin git was sent to) instead of git's could not read Username prompt. It remains a WorkspaceException, so existing catch sites behave as before.
  • Adding a provider or moving its API address probes GET /api/v4/version once, with no credential, and refuses an address that redirects to another origin. An edit that leaves the address as stored asks nothing; no stored base URL is ever rewritten.
  • An edit that only upgrades http to https on the same host (80 to 443, or one explicit port) is no longer a move past connected tokens, so a redirecting base URL can be fixed without disconnecting every member. While tokens are connected the new address must also answer HTTP (any status); otherwise the edit is refused with provider_endpoint_unreachable and the stored address stays, because undoing a mistaken upgrade would itself be a refused move. With no token connected nothing is asked.
  • Resolving a credentialed GitLab clone logs a Warning when the clone URL's origin differs from the base URL's. Nothing is rewritten.

Behaviour to review: an instance whose GitLab emits Link headers naming a different origin than its stored base URL (a misconfigured external_url or proxy) previously had paged NGitLab reads follow that link with the token. Those reads now fail with provider_base_url_redirects naming the origin; editing the base URL to it (an http to https upgrade is allowed while tokens are connected) fixes it.

Test plan

  • Unit: header selector, redirect handler origin and write rules, paging link and raw-write matrices (http to https, host alias, other port) for PAT and OAuth, git redirect parsing and WorkspaceException mapping, probe answer check (any status, redirect, TLS to a plain port, down, silent, cancel), failure code pins (full unit suite 14094 passed)
  • Integration: real git clone, push and integrate through a remote that redirects to another authority name the redirect and send no credential; same-authority redirect still works; carve-out accepted only where the new address answers, not asked with no token bound
  • E2E: provider add refused when its address redirects; an https upgrade past a connected token is refused with provider_endpoint_unreachable while the token keeps working at the stored address (full E2E project green)
  • Staging: edit a redirecting GitLab base URL from http to https with a connected token and confirm repository reads and a clone succeed
  • Staging: confirm no existing instance logs provider_base_url_redirects on paged reads after deploy

@ppXD
ppXD force-pushed the fix/send-gitlab-the-right-auth-on-the-right-host branch from a4eb9c4 to c7d5fba Compare October 18, 2026 07:00
@ppXD
ppXD force-pushed the fix/resolve-the-git-credential-at-each-push branch from 79cdf48 to 707475b Compare October 18, 2026 11:20
@ppXD
ppXD force-pushed the fix/send-gitlab-the-right-auth-on-the-right-host branch from c7d5fba to 0afe394 Compare October 18, 2026 11:20
@ppXD
ppXD force-pushed the fix/resolve-the-git-credential-at-each-push branch from 707475b to 420f458 Compare October 18, 2026 12:08
A GitLab credential stopped working, without the token being wrong, in two
ways. The typed client (NGitLab, on HttpWebRequest) sent only
Authorization: Bearer and dropped it on a 301; the raw HTTP calls sent
Bearer and PRIVATE-TOKEN together and kept PRIVATE-TOKEN across a redirect
to any host. Behind a redirecting base URL a PAT worked, an OAuth token
read 401, and the PAT went wherever the redirect pointed. GitLab 13.0 to
17.7 also reads a Bearer of 41 or more characters as an OAuth token alone,
so a long access token was refused as a Bearer.

- Every call now sends the one header its credential type names:
  PRIVATE-TOKEN for personal, project and group access tokens, Bearer for
  OAuth. NGitLab's two construction sites share a RequestOptions that
  rewrites the header and follows a GET or HEAD redirect inside one origin
  itself; the raw calls share one client behind OriginScopedRedirectHandler,
  which gains opt-in FollowsCrossOrigin = false and RepeatsWritesOnly = true.
- A redirect to another scheme, host or port is not followed and fails with
  the typed provider_base_url_redirects, naming the URL GitLab pointed at.
  So does the next page of a list when its Link header names another
  origin: NGitLab builds that request itself, and the options now refuse it
  before the credential is attached. NGitLab never re-sends a write, and a
  raw write is repeated only by a 307 or 308; a 301, 302 or 303 that would
  turn it into a GET is refused rather than read as the write's answer.
- A tokened git command that its remote sends to another origin fails
  naming the redirect (the same code and the origin git was sent to) instead
  of git's own prompt for a username. It stays a WorkspaceException, so the
  push retry, the per-repo push isolation and the workflow nodes that catch
  one keep treating it as a git failure.
- Adding a provider, or moving its API address, asks GET /api/v4/version
  once, with no credential, and refuses an address that redirects to
  another origin. An edit that leaves the address as stored asks nothing,
  so an existing connection is never rewritten or blocked.
- An edit that only upgrades http to https on the same host (80 to 443, or
  one explicit port) is no longer a move past connected tokens, so the
  self-service fix for a redirecting base URL does not require
  disconnecting every member; the edit form mirrors the rule. While tokens
  are connected the new address must also answer HTTP, any status: a
  mistaken upgrade cannot be edited back (that is a move) and would break
  every token, so it is refused with provider_endpoint_unreachable and the
  stored address stays. With no token connected nothing is asked.
- Resolving a credentialed GitLab clone logs a Warning when the clone URL's
  origin is not the base URL's. Nothing is rewritten.
@ppXD
ppXD changed the base branch from fix/resolve-the-git-credential-at-each-push to main October 18, 2026 12:09
@ppXD
ppXD force-pushed the fix/send-gitlab-the-right-auth-on-the-right-host branch from 0afe394 to cd25e9d Compare October 18, 2026 12:09
@ppXD
ppXD merged commit e5d47c6 into main Oct 18, 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