fix(auth): skip OAuth2 refresh in helper for PAT hosts
Description
After re-running glab auth login for the v1.111.0 keyring migration and choosing Token, every registry pull broke with this error:
$ docker pull registry.gitlab.com/gitlab-org/.../gitlab-gdk-in-a-box:main
error getting credentials - err: exit status 1, out: ``
$ echo registry.gitlab.com | docker-credential-glab get # the real error
Failed to get OAuth2 token source to potentially refresh token: parsing time "" as
"02 Jan 06 15:04 -0700": cannot parse "" as "02"But glab auth status reported the host as healthy throughout. I asked Claude to investigate, turns out the docker credential helper refreshed the token unconditionally: unmarshal parses oauth2_expiry_date before it reads the token, and a PAT host has no such key, so getContainerRegistryToken failed on the empty string before ever reaching the user and token reads.
That function is documented as reading "the stored user/token for the associated host directly, without minting anything new" – the unconditional refresh contradicts its own contract.
How to reproduce
- Run
glab auth login --hostname gitlab.comand choose Token (not Web or Device). - Run
glab auth configure-docker. - Run
docker pullon any image fromregistry.gitlab.com— it fails with the error above. - Workaround: log in again with Web or Device, which writes the
oauth2_*keys the helper was assuming.
Fix
To fix this, we gate the refresh on is_oauth2, as api.NewClientFromConfig already does for every API call. Only an OAuth2 access token expires, a PAT has nothing to refresh. We use GetWithSource(..., false) so GLAB_IS_OAUTH2 cannot force the OAuth2 path onto a PAT host.
The new guard covers the h.cfg.Reload() call as well as the refresh. That reload exists only to pick up a token ts.Token() just rotated, and a PAT host has none. On the other hand, cfg stays declared above the guard, because the user and token below still use it – a PAT host falls through with the original h.cfg.
Not a regression from keyring migration, the unconditional refresh dates to the helper's introduction. The keyring migration only made it visible.
Related Issues
N/A
How has this been tested?
I added a new table case in helper_test.go for a PAT-only host.
It fails on main with the exact error above and passes with the fix.
Also checked with GLAB_IS_OAUTH2=true set.
Run tests to confirm:
go test ./internal/commands/auth/docker/... \
./internal/oauth2/... \
./internal/config/...