glab --repo ignores an authenticated host with a port and no dot, such as localhost:3000

Checklist

  • I'm using the latest version of the extension (Run glab --version)
    • Extension version: glab 1.124.0 (a6fd50cec), built from main at a6fd50ce. internal/glrepo/repo.go, where the cause is, is the same in the v1.124.0 release.
  • Operating system and version: Linux 6.1.0 x86_64
  • Gitlab.com or self-managed instance? Self-managed: any instance whose host has a port and no dot, such as a local development instance on localhost:3000
  • GitLab version (if self-managed): not applicable. glab picks the wrong host before it sends any request, so I reproduced it against a local stub rather than an instance.
  • I have performed glab auth status to check for authentication issues: not applicable, the host is authenticated in the configuration and glab never asks it.
  • Run the command in debug mode (like GLAB_DEBUG=true glab mr list) and attach any useful output: GLAB_DEBUG=true adds nothing to the output below.

Summary

When the --repo (-R) flag or GITLAB_REPO names an authenticated host that has a port but no dot, such as localhost:3000, glab does not recognize the host. It reads the whole value as a project path on the default host, so after glab auth login --hostname localhost:3000, glab issue list -R localhost:3000/OWNER/REPO asks gitlab.com for a project named localhost:3000/OWNER/REPO instead of asking localhost:3000 for OWNER/REPO. A host with a dot, such as example.org, works.

Environment

  • OS: Linux 6.1.0-53-amd64 x86_64
  • SHELL: /bin/bash (GNU bash 5.2.15)
  • TERM: xterm
  • GLAB: glab 1.124.0 (a6fd50ce)

Other: glab ran in an empty directory with a cleared environment (PATH, HOME, GLAB_CONFIG_DIR, GLAB_SEND_TELEMETRY=false, GLAB_CHECK_UPDATE=false, NO_COLOR=1 and the proxy variables below), so no GITLAB_* variable was set. Its configuration held one host, localhost:3123, with a token, api_protocol: http and api_host: localhost:3123. A small stub on localhost:3123 stood in for the instance, and HTTPS_PROXY pointed at a second stub that logs every CONNECT and refuses it, so no request left the machine.

Steps to reproduce

  1. Authenticate glab to an instance whose host has a port and no dot, for example glab auth login --hostname localhost:3000, so the configuration has a localhost:3000 entry under hosts.
  2. Outside any Git repository, run glab issue list -R localhost:3000/OWNER/REPO, or set GITLAB_REPO=localhost:3000/OWNER/REPO and run glab issue list.

What is the current bug behavior?

glab sends the request to gitlab.com, for the project localhost:3000/OWNER/REPO. With the host localhost:3123 of my reproduction, glab prints (its line wrapping removed):

ERROR

Get "https://gitlab.com/api/v4/projects/localhost:3123%2FOWNER%2FREPO/issues?in=title%2Cdescription&order_by=created_at&page=1&per_page=30&sort=desc&state=opened": Forbidden.

Forbidden is the proxy stub's answer. Its log has one line, CONNECT gitlab.com:443, and the stub on localhost:3123 saw no request. GITLAB_REPO=localhost:3123/OWNER/REPO glab issue list does the same.

What is the expected correct behavior?

glab asks localhost:3123 for the project OWNER/REPO, the same way example.org/OWNER/REPO goes to example.org when example.org is authenticated.

Relevant logs and/or screenshots

glrepo.FromFullName("localhost:3000/OWNER/REPO", "gitlab.com", cfg), with localhost:3000 in the configured hosts, returns host gitlab.com, group localhost:3000 and project localhost:3000/OWNER/REPO. A case added to TestFromFullName for it fails on main with:

expected host "localhost:3000", got "gitlab.com"

Setting GITLAB_HOST=localhost:3123 works around it: the first segment then matches the default host, which FromFullName checks first, and the request reaches the stub on localhost:3123.

Possible fixes

FromFullName compares the first segment with the authenticated hosts only when it contains a dot, because dots are also allowed in group paths: https://gitlab.com/gitlab-org/cli/-/blob/a6fd50cecb4bbe630dfb03a621cbe2cedfef4aef/internal/glrepo/repo.go#L148-166

Running the same check when the segment contains a colon would fix it without changing how any group name is read, since a colon cannot appear in a GitLab group or project path (PATH_REGEX_STR in https://gitlab.com/gitlab-org/gitlab/-/blob/c421511b7a8c7df247695fc1e79c01e82033524c/lib/gitlab/path_regex.rb#L133-134). A segment with a colon that is not an authenticated host would keep its current meaning. I have a merge request ready for it.