Skip to content

fix(github,gitlab): find gh/glab config on Windows - #11508

Merged
jdx merged 1 commit into
jdx:mainfrom
JamBalaya56562:fix/gh-glab-windows-config-path
Jul 30, 2026
Merged

jdx merged 1 commit into
jdx:mainfrom
JamBalaya56562:fix/gh-glab-windows-config-path

Conversation

@JamBalaya56562

@JamBalaya56562 JamBalaya56562 commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

The bug

mise reads forge tokens from the gh and glab CLI config files as a fallback. On Windows it only ever looked under ~/.config, which is not where either CLI puts them by default — so a logged-in user can still go out unauthenticated and hit GitHub's 60/hour anonymous rate limit.

env::XDG_CONFIG_HOME has no #[cfg(windows)] arm (unlike its XDG_CACHE_HOME / XDG_DATA_HOME neighbours), so on Windows it resolves to %USERPROFILE%\.config, and neither gh_hosts_path nor glab_config_path had a Windows branch — only a macOS one.

Measured, same file, only GH_CONFIG_DIR differs:

# file at %APPDATA%\GitHub CLI\hosts.yml, no GH_CONFIG_DIR
$ mise token github
github.com: (none)

# identical file, GH_CONFIG_DIR pointed at it
$ mise token github
github.com: gho_…6789 (source: gh CLI (hosts.yml))

The two CLIs disagree about the Windows root

This is why both had to be checked separately rather than sharing one %APPDATA% constant.

gh — go-gh ConfigDir() checks AppData explicitly:

if a := os.Getenv(ghConfigDir); a != "" {            // GH_CONFIG_DIR
} else if b := os.Getenv(xdgConfigHome); b != "" {   // XDG_CONFIG_HOME/gh   (only when SET)
} else if c := os.Getenv(appData); runtime.GOOS == "windows" && c != "" {
    path = filepath.Join(c, "GitHub CLI")            // %APPDATA%\GitHub CLI
} else {
    path = filepath.Join(d, ".config", "gh")
}

glab — ConfigDir() is GLAB_CONFIG_DIR → legacy ~/.config/glab-cli (when its config.yml exists) → xdg.ConfigHome/glab-cli, and adrg/xdg on Windows sets configHome = EnvPath(envConfigHome, kf.localAppData) — %LOCALAPPDATA%, not %APPDATA%.

CLI Windows default before after
gh %APPDATA%\GitHub CLI\hosts.yml not checked checked
glab %LOCALAPPDATA%\glab-cli\config.yml not checked checked
fj %LOCALAPPDATA%\forgejo-cli\ already reached via XDG_DATA_HOME's Windows arm unchanged

Note .config is not simply wrong on Windows — it is gh's last branch and glab's legacy location, so both are kept as candidates.

Also in this PR

  • gh now follows go-gh's order: XDG_CONFIG_HOME is consulted only when actually set (mise's defaulting static cannot express that), and ~/.config/gh becomes the explicit final fallback, matching gh itself. Unix behaviour is unchanged — unset XDG_CONFIG_HOME produces the same path the static did.
  • tokens::first_existing_path: the "first candidate that exists, else the conventional location" rule is now one implementation with unit tests instead of a copy per forge. The copies are precisely how the Windows location came to be missing from both.
  • Docs: the real Windows locations are listed, and the keyring note is rewritten (see below).

Scope — what this does not fix

Current gh stores its token in Windows Credential Manager, so on many setups hosts.yml exists but has no oauth_token key at all, and no amount of path-fixing helps. Verified here: the real hosts.yml on this machine holds only git_protocol / users / user.

Those users need github.use_git_credentials or github.credential_command, both measured working:

$ mise settings github.use_git_credentials=true
$ mise token github
github.com: gho_…LAp4 (source: git credential fill)

$ mise settings github.credential_command="gh auth token"
$ mise token github
github.com: gho_…LAp4 (source: credential_command)

The docs previously lumped macOS and Windows together as "stores tokens in the system keyring rather than hosts.yml", which does not tell a Windows user how to find out which case they are in. That note now points at mise token github and both settings.

Tests

Three unit tests for first_existing_path in src/tokens.rs — earliest existing candidate wins, a missing earlier candidate is skipped, and the fallback is returned when none exist. Platform-neutral, so they run on windows-unit too.

Deliberately not attempted: driving gh_hosts_path() end-to-end. GH_HOSTS, XDG_CONFIG_HOME and the new statics are all LazyLock, env::HOME is pinned to $CARGO_MANIFEST_DIR/test under cfg(test), and EnvVarGuard is #[cfg(unix)] so it cannot run on windows-unit. The extracted helper is the part that can be pinned without that machinery.

Note for review

mise's macOS candidate for gh (~/Library/Application Support/gh/hosts.yml) does not correspond to any go-gh branch — gh uses ~/.config/gh on macOS as well. It is .exists()-gated and therefore harmless, so I kept it rather than change behaviour in a PR about Windows; happy to drop it if you'd prefer.

Summary by CodeRabbit

  • Bug Fixes
    • Improved discovery of GitHub/GitLab CLI token/config files by checking multiple standard locations in a consistent, ordered way across macOS, Windows, and Linux.
    • XDG-based paths are now used only when the related environment variable is explicitly set and non-empty.
    • Added a Windows %LOCALAPPDATA%-based fallback to improve token resolution reliability.
  • Documentation
    • Refined GitHub hosts.yml lookup guidance and expanded OS-specific credential helper/keyring scenarios.
    • Updated GitLab fallback documentation to reflect the full ordered search behavior and legacy location precedence.
  • Tests
    • Added unit tests covering ordered selection of the first existing config file, including empty and decoy scenarios.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

GitHub and GitLab CLI token configuration lookup now follows ordered, platform-aware candidate paths. Shared path selection and Windows environment fallbacks were added, with documentation covering XDG, native, keyring, and Windows locations.

Changes

CLI token resolution

Layer / File(s) Summary
Shared candidate selection
src/env.rs, src/tokens.rs
Adds Windows local application data resolution and a tested helper for selecting the first existing file or a fallback.
GitHub hosts.yml resolution
src/github.rs, docs/dev-tools/github-tokens.md
Updates GitHub config lookup precedence and documents XDG, native Windows, keyring, and credential-command behavior.
GitLab config resolution
src/gitlab.rs, docs/dev-tools/backends/gitlab.md
Adds platform-native config candidates and documents the Windows fallback path.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: jdx, marukome0743

Sequence Diagram(s)

sequenceDiagram
  participant gh_hosts_path
  participant gh_native_hosts_paths
  participant first_existing_file
  gh_hosts_path->>gh_native_hosts_paths: Build native platform candidates
  gh_hosts_path->>first_existing_file: Pass ordered hosts.yml candidates
  first_existing_file-->>gh_hosts_path: Return first existing file or platform default
Loading

Poem

A rabbit hops through paths in line,
XDG and Windows paths align.
The first found file earns the crown,
Keyring secrets stay safely bound.
GitHub and GitLab configs glow,
As tested fallbacks help them grow.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing GitHub and GitLab CLI config discovery on Windows.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JamBalaya56562
JamBalaya56562 marked this pull request as ready for review July 30, 2026 18:08
Comment thread src/gitlab.rs Outdated
@greptile-apps

greptile-apps Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR expands GitHub and GitLab CLI config discovery to match their Windows and legacy locations.

  • Adds %APPDATA%\GitHub CLI\hosts.yml discovery for GitHub CLI authentication.
  • Restores glab’s platform-independent ~/.config/glab-cli/config.yml legacy candidate ahead of XDG and native paths.
  • Centralizes ordered existing-file selection and documents the supported token locations and credential fallbacks.

Confidence Score: 5/5

The PR appears safe to merge.

The previously reported glab legacy-path issue is fixed because the current candidate list always checks the home-based legacy config before XDG and platform-native locations, and no blocking failure remains.

Important Files Changed

Filename Overview
src/gitlab.rs The legacy glab config is now an unconditional first candidate, so the previously reported XDG-related omission is fixed.
src/github.rs GitHub CLI config discovery now follows explicit environment overrides and Windows APPDATA fallback behavior.
src/tokens.rs Introduces a shared helper that selects the first existing regular file and otherwise returns the designated fallback.
src/env.rs Adds the Windows local-app-data path and treats empty path environment variables as unset.
docs/dev-tools/backends/gitlab.md Documents glab’s legacy, XDG, macOS, and Windows config lookup order.
docs/dev-tools/github-tokens.md Documents GitHub CLI’s Windows config location and credential-manager alternatives.

Reviews (7): Last reviewed commit: "fix(github,gitlab): find gh/glab config ..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/dev-tools/github-tokens.md`:
- Around line 198-202: Update the `gh auth token` example in the
credential-command guidance to pass `"$MISE_CREDENTIAL_HOST"` via `--hostname`,
ensuring the token matches mise’s requested host, or explicitly scope the
example to github.com. Keep the surrounding macOS/Windows and `mise token
github` guidance unchanged.

In `@src/gitlab.rs`:
- Around line 365-381: Restore glab_config_path resolution order by adding the
distinct legacy ~/.config/glab-cli/config.yml candidate before the XDG/native
candidates, while retaining GLAB_CONFIG_DIR as highest priority and the existing
fallback behavior. Update the corresponding configuration-resolution list in
docs/dev-tools/backends/gitlab.md to document the same legacy-before-XDG order.

In `@src/tokens.rs`:
- Around line 320-330: Update first_existing_path to select only candidates
where is_file() is true, preserving fallback behavior when no regular file
exists. Add a regression test covering an earlier directory-named candidate
shadowing a later valid hosts.yml or config.yml file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: fe1f876a-35d8-496e-9c46-f9ffe18a6add

📥 Commits

Reviewing files that changed from the base of the PR and between fef33d5 and 9c1b554.

📒 Files selected for processing (6)
  • docs/dev-tools/backends/gitlab.md
  • docs/dev-tools/github-tokens.md
  • src/env.rs
  • src/github.rs
  • src/gitlab.rs
  • src/tokens.rs

Comment thread docs/dev-tools/github-tokens.md Outdated
Comment thread src/gitlab.rs Outdated
Comment thread src/tokens.rs Outdated
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from 9c1b554 to 2a8c2ee Compare July 30, 2026 18:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/github.rs`:
- Around line 834-854: Update gh_default_hosts_path and gh_native_hosts_paths on
Windows to distinguish an explicitly available APPDATA value from the
synthesized ROAMING_APPDATA path. Only add the native GitHub CLI AppData
candidate when APPDATA exists; when it is unset, preserve the
~/.config/gh/hosts.yml fallback and avoid returning the synthesized AppData path
as the default.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e7950a97-0a5f-48b8-b445-e76d7fa1d6dc

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1b554 and 2a8c2ee.

📒 Files selected for processing (6)
  • docs/dev-tools/backends/gitlab.md
  • docs/dev-tools/github-tokens.md
  • src/env.rs
  • src/github.rs
  • src/gitlab.rs
  • src/tokens.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/dev-tools/backends/gitlab.md

Comment thread src/github.rs
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from 2a8c2ee to 4b6ac43 Compare July 30, 2026 18:31
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from 4b6ac43 to f5b75ff Compare July 30, 2026 19:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/env.rs`:
- Around line 93-94: Treat empty environment variables as unset in both
src/env.rs lines 93-94 and src/github.rs lines 825-826: update the LOCALAPPDATA
lookup to filter empty values before falling back to HOME/AppData/Local, and
update the XDG_CONFIG_HOME lookup to filter empty values before constructing
gh/hosts.yml; preserve the existing non-empty path behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e6f8300b-8759-40a6-ac58-0d22dba99d51

📥 Commits

Reviewing files that changed from the base of the PR and between 2a8c2ee and f5b75ff.

📒 Files selected for processing (6)
  • docs/dev-tools/backends/gitlab.md
  • docs/dev-tools/github-tokens.md
  • src/env.rs
  • src/github.rs
  • src/gitlab.rs
  • src/tokens.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/dev-tools/backends/gitlab.md

Comment thread src/env.rs
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from f5b75ff to 86dbd03 Compare July 30, 2026 19:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/dev-tools/github-tokens.md`:
- Around line 210-217: Update the TOML example in the documentation so it never
declares the [settings.github] table twice in one snippet. Keep the macOS/Linux
and Windows credential_command examples, but separate the Windows variant into
its own code block or otherwise present it as an alternative configuration.

In `@src/github.rs`:
- Around line 819-820: Update the GH_CONFIG_DIR branch in the GitHub
configuration discovery function and the GLAB_CONFIG_DIR branch in the GitLab
configuration discovery function to ignore empty environment-variable values
before constructing and returning the direct hosts.yml/config.yml candidate.
Preserve direct-path handling for non-empty values and allow empty overrides to
continue into gh/glab fallback discovery.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 3322e5ee-63c4-416d-8e95-4c3f50a92b38

📥 Commits

Reviewing files that changed from the base of the PR and between f5b75ff and 86dbd03.

📒 Files selected for processing (6)
  • docs/dev-tools/backends/gitlab.md
  • docs/dev-tools/github-tokens.md
  • src/env.rs
  • src/github.rs
  • src/gitlab.rs
  • src/tokens.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/dev-tools/backends/gitlab.md

Comment thread docs/dev-tools/github-tokens.md
Comment thread src/github.rs Outdated
@JamBalaya56562
JamBalaya56562 marked this pull request as draft July 30, 2026 19:32
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from 86dbd03 to 0decdd1 Compare July 30, 2026 19:33
mise reads forge tokens from the `gh` and `glab` CLI config files as a fallback, but on
Windows it only ever looked under `~/.config`, so a logged-in user could still go out
unauthenticated and hit the 60/hour anonymous GitHub rate limit.

`env::XDG_CONFIG_HOME` has no `#[cfg(windows)]` arm (unlike its `XDG_CACHE_HOME` /
`XDG_DATA_HOME` neighbours), so on Windows it resolves to `%USERPROFILE%\.config`, and
neither `gh_hosts_path` nor `glab_config_path` had a Windows branch -- only a macOS one.

The two CLIs do not even agree on the Windows root, so both had to be checked separately:

- go-gh's `ConfigDir()` checks `AppData` explicitly, giving
  `%APPDATA%\GitHub CLI\hosts.yml`
- glab goes through `adrg/xdg`, whose Windows `ConfigHome` is `%LOCALAPPDATA%`, giving
  `%LOCALAPPDATA%\glab-cli\config.yml`

`fj` is unaffected: it resolves through `XDG_DATA_HOME`, which already has a Windows arm.

Also:

- follow go-gh's order for `gh`: `XDG_CONFIG_HOME` is consulted only when actually set, and
  `~/.config/gh` becomes the explicit final fallback, as in gh itself
- extract `tokens::first_existing_path` so the "first candidate that exists, else the
  conventional location" rule is one implementation with tests, rather than a copy per forge
  -- the copies are how the Windows location came to be missing from both
- document the real Windows locations, and rewrite the keyring note so a Windows user whose
  `hosts.yml` has no `oauth_token` is pointed at `mise token github` and
  `use_git_credentials` / `credential_command` instead

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JamBalaya56562
JamBalaya56562 force-pushed the fix/gh-glab-windows-config-path branch from 0decdd1 to be823b9 Compare July 30, 2026 19:38
@JamBalaya56562
JamBalaya56562 marked this pull request as ready for review July 30, 2026 19:38
@JamBalaya56562

Copy link
Copy Markdown
Contributor Author

Three review rounds here all found the same defect at a different call site — an environment variable set to the empty string being treated as set. Rather than wait for the fourth, I went looking for the root, and it is one function.

env::var_path returned Some("") for an empty value. Every caller joins onto the result, so an empty variable produced a relative path resolved against the current working directory:

  • XDG_CONFIG_HOME= made MISE_CONFIG_DIR the relative mise
  • the forge lookups this PR adds read gh/hosts.yml / glab-cli/config.yml out of whatever directory mise happened to be run from

That is 37 call sites sharing one bug, so var_path now treats empty as unset, and the local guards I had added at three individual sites are gone again. It also matches what the tools being mirrored do — go-gh's os.Getenv(x) != "" and adrg/xdg's dir != "" && filepath.IsAbs(dir) both fall through on empty.

GH_CONFIG_DIR, GLAB_CONFIG_DIR and APPDATA keep their own guards because they are read with var_os rather than var_path (deliberately: std::env::var drops non-UTF-8 values, which would silently ignore a perfectly valid config directory).

Pinned by a unit test in src/env.rs, next to the existing test_var_path.

One case I deliberately did not mirror: adrg/xdg also rejects a relative value. None of mise's XDG_* statics check that today, and making one of them an exception for a pathological case seemed worse than leaving it consistent. Happy to add it if you'd rather.

@jdx
jdx merged commit 5a6a206 into jdx:main Jul 30, 2026
36 checks passed
@JamBalaya56562
JamBalaya56562 deleted the fix/gh-glab-windows-config-path branch July 30, 2026 20:04
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.

2 participants