Conversation
…github token` command Adds three new features to improve GitHub token management: 1. **github_tokens.toml**: A mise-specific token file at $MISE_CONFIG_DIR/github_tokens.toml for per-host tokens that don't interfere with gh CLI's hosts.yml. Useful for Coder environments where tokens have restricted scope. 2. **git credential fill**: Enabled by default, uses git's credential helpers as a last-resort fallback. Covers system keyrings (macOS Keychain, Windows Credential Manager), Coder external auth, and any other configured git credential helper. Runs with GIT_TERMINAL_PROMPT=0 to prevent interactive prompts. 3. **mise github token**: New CLI command to display which token mise would use for a given host and where it came from. Supports --unmask to show the full token. Useful for debugging auth issues. Token priority (updated): 1. MISE_GITHUB_ENTERPRISE_TOKEN (non-github.com only) 2. MISE_GITHUB_TOKEN / GITHUB_API_TOKEN / GITHUB_TOKEN env vars 3. github_tokens.toml (per-host) — NEW 4. gh CLI hosts.yml 5. git credential fill — NEW Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request significantly enhances GitHub token management by introducing new token sources like github_tokens.toml and git credential fill, updating the token resolution priority, and adding a mise github token command for debugging. The documentation has been thoroughly updated to reflect these changes, and a new end-to-end test verifies the functionality. Feedback indicates two areas for improvement: the token resolution logic for standard environment variables needs to be refined to correctly handle empty values and ensure proper precedence, and the token masking logic requires adjustment to prevent full token exposure for certain token lengths (5-8 characters) to maintain security.
src/github.rs
Outdated
| "MISE_GITHUB_TOKEN" | ||
| } else if std::env::var("GITHUB_API_TOKEN").is_ok() { | ||
| "GITHUB_API_TOKEN" | ||
| } else { | ||
| "GITHUB_TOKEN" | ||
| }; | ||
| return Some((token.to_string(), TokenSource::EnvVar(source))); | ||
| } | ||
|
|
||
| // 3. github_tokens.toml |
There was a problem hiding this comment.
The logic for resolving the token from standard environment variables and determining its source is incorrect. It uses env::GITHUB_TOKEN, which may have incorrect behavior with empty environment variables, and then separately tries to identify the source variable using std::env::var(...).is_ok(). This can lead to incorrect token resolution (e.g., not picking up a valid token if a higher-precedence one is empty) and reporting the wrong source.
To ensure correct behavior and precedence, I suggest replacing this block with explicit, ordered checks for each environment variable.
if let Some(token) = std::env::var("MISE_GITHUB_TOKEN").ok().filter(|t| !t.is_empty()) {
return Some((token, TokenSource::EnvVar("MISE_GITHUB_TOKEN")));
}
if let Some(token) = std::env::var("GITHUB_API_TOKEN").ok().filter(|t| !t.is_empty()) {
return Some((token, TokenSource::EnvVar("GITHUB_API_TOKEN")));
}
if let Some(token) = std::env::var("GITHUB_TOKEN").ok().filter(|t| !t.is_empty()) {
return Some((token, TokenSource::EnvVar("GITHUB_TOKEN")));
}| fn mask_token(token: &str) -> String { | ||
| let len = token.len(); | ||
| if len <= 4 { | ||
| "*".repeat(len) | ||
| } else { | ||
| format!("{}…{}", &token[..4], &token[len - 4..]) | ||
| } | ||
| } |
There was a problem hiding this comment.
The current token masking logic can reveal the entire token for tokens with a length between 5 and 8 characters. For example, an 8-character token 12345678 would be displayed as 1234…5678, which is not masked at all. This could unintentionally expose sensitive information.
I recommend adjusting the logic to handle short tokens more securely.
fn mask_token(token: &str) -> String {
let len = token.len();
if len <= 4 {
"*".repeat(len)
} else if len <= 8 {
format!("{}...", &token[..4])
} else {
format!("{}…{}", &token[..4], &token[len - 4..])
}
}
Greptile SummaryThis PR adds three related features to mise's GitHub authentication system: a per-host Key changes:
Issues found:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[HTTP request] --> B{Standard GitHub host?\ngithub.com / api.github.com\n*.githubusercontent.com}
B -- Yes --> D[resolve_token lookup_host]
B -- No --> C{is_gh_host check:\nin github_tokens.toml\nor gh CLI hosts.yml?}
C -- No --> Z[No auth headers - gap exists\nfor GHE with git credentials only]
C -- Yes --> D
D --> E{Enterprise token set\nand host is not github.com?}
E -- Yes --> OUT[Return token + source]
E -- No --> F{Standard env vars set?\nMISE_GITHUB_TOKEN etc.}
F -- Yes --> OUT
F -- No --> G{Host in\ngithub_tokens.toml?}
G -- Yes --> OUT
G -- No --> H{gh_cli_tokens enabled\nand host in hosts.yml?}
H -- Yes --> OUT
H -- No --> I{use_git_credentials\nenabled?}
I -- Yes --> J[Spawn: git credential fill\ncached per host per session]
J --> K{Password found?}
K -- Yes --> OUT
K -- No --> L[None - no auth]
I -- No --> L
OUT --> M[Attach Bearer token header]
style Z fill:#f99,stroke:#c00
style J fill:#ffe,stroke:#cc0
|
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.13 x -- echo |
24.4 ± 0.7 | 23.6 | 31.2 | 1.00 |
mise x -- echo |
25.3 ± 0.8 | 23.9 | 31.0 | 1.04 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.13 env |
24.4 ± 0.8 | 23.1 | 30.0 | 1.00 |
mise env |
24.7 ± 1.4 | 23.3 | 50.9 | 1.01 ± 0.07 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.13 hook-env |
24.8 ± 0.4 | 23.8 | 26.7 | 1.00 |
mise hook-env |
25.3 ± 0.7 | 24.1 | 29.8 | 1.02 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.13 ls |
24.8 ± 1.1 | 23.5 | 39.5 | 1.00 |
mise ls |
25.2 ± 0.6 | 23.7 | 27.2 | 1.01 ± 0.05 |
xtasks/test/perf
| Command | mise-2026.3.13 | mise | Variance |
|---|---|---|---|
| install (cached) | 164ms | 161ms | +1% |
| ls (cached) | 85ms | 85ms | +0% |
| bin-paths (cached) | 89ms | 88ms | +1% |
| task-ls (cached) | 856ms | 835ms | +2% |
…ution, masking, e2e test - Move github.use_git_credentials after github.slsa in settings.toml (alphabetical sort order required by test_settings_toml_is_sorted) - Fix env var resolution to check each var individually with empty filtering, instead of relying on env::GITHUB_TOKEN lazy static - Improve token masking for tokens with 5-8 characters - Fix e2e test to use a credential helper script file instead of git config --global (which didn't work in CI's isolated HOME) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…credential test - Remove gh_cli_tokens gate from http.rs github_headers() around is_gh_host() — github_tokens.toml and git credential hosts should be recognized regardless of the gh CLI setting - Use GIT_CONFIG_GLOBAL env var in e2e test to ensure git reads the test credential helper config in CI's isolated environment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… token lookups *.githubusercontent.com hosts (e.g. raw.githubusercontent.com, objects.githubusercontent.com) are used for GitHub downloads but tokens are stored under "github.com". Without normalization, only env var tokens worked for these hosts — github_tokens.toml, gh CLI, and git credential lookups all failed to match. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use a standalone shell script as credential helper instead of inline function syntax, and set GIT_CONFIG_NOSYSTEM=1 to avoid interference from system-level credential helpers in CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e HOME/.gitconfig The credential helper script needs to output both username and password for git credential fill to succeed. Also use $HOME/.gitconfig instead of GIT_CONFIG_GLOBAL/GIT_CONFIG_COUNT for more reliable config discovery, and set GIT_CONFIG_NOSYSTEM=1 to avoid system credential helpers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add .trim() to env var token values to reject whitespace-only tokens, matching the behavior of the original get_token() in env.rs - Release the GIT_CREDENTIAL_CACHE mutex before spawning the git credential fill subprocess to avoid blocking the async runtime thread during subprocess I/O Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hold the cache mutex through the git credential fill subprocess call to prevent duplicate spawns for the same host. The lock is only held for a meaningful duration once per host per session (cache hit on subsequent calls). Added TODO to async-ify the chain in the future. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…etting Only consult gh CLI's hosts.yml in is_gh_host() when gh_cli_tokens is enabled. Previously, hosts known only through gh CLI config would still trigger resolve_token (and potentially git credential fill) even when the user set gh_cli_tokens = false to opt out of gh CLI integration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Default git credential fill to opt-in to avoid potential issues with credential helpers that might hang or loop. Users can enable it with `github.use_git_credentials = true`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
### 🚀 Features - **(github)** add github_tokens.toml, git credential fill, and `mise github token` command by @jdx in [#8742](#8742) - **(registry)** add tart by @mnm364 in [#8727](#8727) ### 🐛 Bug Fixes - **(python)** respect precompiled flavor when excluding freethreaded builds by @risu729 in [#8745](#8745) - **(shim)** revert shims directory check that caused hangs on macOS by @jdx in [e1b8ca4](e1b8ca4) ### 📚 Documentation - **(python)** swap docs for python.precompiled_arch and python.precompiled_os by @risu729 in [#8744](#8744) ### 🧪 Testing - **(test_tool)** redirect stderr to stdout and strip ansi codes by @risu729 in [#8738](#8738) ### New Contributors - @rtharston made their first contribution in [#8731](#8731)

Summary
github_tokens.toml($MISE_CONFIG_DIR/github_tokens.toml) for per-host GitHub tokens that don't interfere with gh CLI'shosts.yml. Useful when gh CLI tokens have restricted scope or you want mise-specific tokens.git credential fillintegration (opt-in) as a last-resort fallback. Uses git's credential helpers (macOS Keychain, Windows Credential Manager, etc.) withGIT_TERMINAL_PROMPT=0to prevent interactive prompts. Results are cached per host per session.mise github token [host]command to display which token mise would use and where it came from. Supports--unmaskto show the full token.github.use_git_credentials(default:false, env:MISE_GITHUB_USE_GIT_CREDENTIALS)Updated token priority:
MISE_GITHUB_ENTERPRISE_TOKENenv var (non-github.com only)MISE_GITHUB_TOKEN/GITHUB_API_TOKEN/GITHUB_TOKENenv varsgithub_tokens.toml(per-host)hosts.yml)git credential fillKey implementation details:
*.githubusercontent.comandapi.github.comhosts are normalized togithub.comfor token lookupsis_gh_host()respectsgh_cli_tokenssetting — disabling gh CLI integration won't cause GHE hosts fromhosts.ymlto triggergit credential fillget_token()behavior inenv.rs)ghp_…instead of full value)Test plan
github_tokens.tomlparser (cargo test -- github::tests)mise github token --unmaskgit credential fillworks with system credential helperse2e/cli/test_github_tokencovering all sources, priority, masking, and settingstest_settings_toml_is_sortedpasses (setting in correct alphabetical position)🤖 Generated with Claude Code
Note
Medium Risk
Touches GitHub authentication header/token resolution logic and introduces an opt-in subprocess call to
git credential fill, which could affect how API requests are authenticated across hosts.Overview
Adds a new
mise github token [--unmask] [HOST]command to display which GitHub token would be used (with masking by default), and wires it into the CLI/help/manpage/docs.Refactors GitHub auth to centralize token lookup in
github::resolve_token, expanding priority to include a per-host$MISE_CONFIG_DIR/github_tokens.tomlfile and an optional last-resortgit credential fillfallback (cached per host), and updates HTTP header attachment logic accordingly. Also documents the new token sources and adds e2e + unit tests plus a newgithub.use_git_credentialssetting/schema entry.Written by Cursor Bugbot for commit e06d29b. This will update automatically on new commits. Configure here.