Skip to content

fix(github): resolve "latest" version correctly via GitHub API#8532

Merged
jdx merged 5 commits intomainfrom
fix/github-latest-version-resolution
Mar 9, 2026
Merged

fix(github): resolve "latest" version correctly via GitHub API#8532
jdx merged 5 commits intomainfrom
fix/github-latest-version-resolution

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Mar 9, 2026

Summary

  • Fix GitHub API URL for "latest" releases: use /releases/latest instead of /releases/tags/latest (which looks for a tag literally named "latest")
  • Fully revert the prefer-offline guard on latest_version_with_opts from fix(env): skip remote version fetching for "latest" in prefer-offline mode #8500 — the npm hang it aimed to fix was properly addressed in bdaf470 by making subprocess calls async with kill_on_drop, making the guard redundant
  • Add e2e test for github: backend with @latest version

Context

Regression in v2026.3.5 where github: backend tools configured with @latest fail with a 404 error during install/exec. Two issues combined:

  1. get_release_() in github.rs always constructed /releases/tags/{tag}, but "latest" isn't a tag — GitHub's API uses /releases/latest for the latest release endpoint
  2. The prefer-offline guard in fix(env): skip remote version fetching for "latest" in prefer-offline mode #8500 prevented "latest" from being resolved to a concrete version number during exec/env/hook-env, causing the literal string "latest" to propagate into the install path. This guard was added to prevent npm hangs with private registries, but that issue was already properly fixed in bdaf470 by using async subprocess calls with kill_on_drop

Fixes #8530

Test plan

  • New e2e test test_github_latest verifies install and exec with @latest
  • Existing e2e tests pass

🤖 Generated with Claude Code


Note

Medium Risk
Touches version-resolution logic and GitHub API calling behavior, which can affect installs/execs across environments; changes are small and covered by a targeted e2e regression test.

Overview
Fixes github: tool installs/execs using version = "latest" by routing GitHub release lookups to /releases/latest (instead of treating latest as a tag via /releases/tags/latest).

Adjusts ToolVersion::resolve_version so latest continues to resolve to a concrete remote version even under prefer-offline flows (while still respecting true offline mode), and adds an e2e regression test (test_github_latest) that asserts mise ls reports a real semver rather than the literal latest.

Updates the pipx extras e2e test to use a newer harlequin version and tweaks the python selection comment for consistency.

Written by Cursor Bugbot for commit ded8093. This will update automatically on new commits. Configure here.

The GitHub API endpoint for the latest release is `/releases/latest`,
not `/releases/tags/latest` (which looks for a tag literally named
"latest"). This fixes a regression in v2026.3.5 where `github:` backend
tools with `@latest` would fail with a 404 during install/exec.

Two fixes:
1. `get_release_` in github.rs now uses `/releases/latest` when tag is
   "latest"
2. Revert the prefer-offline guard on `latest_version_with_opts` from
   #8500 — "latest" must always resolve to a concrete version via
   remote lookup when no installed version is found, otherwise it
   propagates as the literal string "latest" into the install path

Fixes #8530

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 addresses a regression where github: backend tools configured with @latest failed to install or execute due to incorrect GitHub API calls and an overly aggressive prefer-offline guard. The changes ensure that the "latest" version is correctly resolved via the GitHub API and always performs a remote lookup when necessary, preventing literal "latest" strings from propagating into install paths. A new e2e test has been added to validate this fix.

Highlights

  • GitHub API "latest" release URL: Corrected the GitHub API endpoint for "latest" releases from "/releases/tags/latest" to "/releases/latest" to resolve 404 errors.
  • prefer-offline guard: Reverted the prefer-offline guard on latest_version_with_opts to ensure that "latest" versions are always resolved via a remote lookup when no installed version is found.
  • End-to-end testing: Added a new end-to-end test to verify the correct installation and execution of tools using the github: backend with the @latest version specifier.
Changelog
  • e2e/backend/test_github_latest
    • Added a new end-to-end test for GitHub backend's 'latest' version resolution.
  • src/github.rs
    • Modified the get_release_ function to use the correct GitHub API endpoint for 'latest' releases.
    • Implemented conditional logic to differentiate between 'latest' and specific tag lookups.
  • src/toolset/tool_version.rs
    • Removed the prefer_offline condition from the ToolVersion's latest_version_with_opts call, ensuring remote lookup for 'latest' versions.
Activity
  • Identified and fixed an issue where the GitHub API URL for "latest" releases was incorrect, leading to 404 errors.
  • Reverted a prefer-offline guard that was preventing "latest" versions from being resolved remotely.
  • Added a new end-to-end test (test_github_latest) to validate the fix for GitHub backend @latest version resolution.
  • Confirmed that existing end-to-end tests continue to pass after these changes.
  • Addressed a regression introduced in v2026.3.5, as detailed in the linked GitHub discussion.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

jdx and others added 2 commits March 9, 2026 08:37
Two fixes for the regression in v2026.3.5 where `github:` backend tools
with `@latest` fail with a 404 during install/exec (#8530):

1. `get_release_()` in github.rs now uses `/releases/latest` when tag
   is "latest", instead of `/releases/tags/latest` (which looks for a
   tag literally named "latest")

2. In prefer-offline mode, when "latest" can't be resolved locally,
   return early with "latest" so the backend's install path can handle
   it via the correct API endpoint — rather than falling through to
   general version matching which fails to find it. This preserves the
   prefer-offline guard from #8500 that prevents hangs with private
   registries.

Fixes #8530

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The prefer-offline guard was added in #8500 to prevent npm hangs, but
that was properly fixed in bdaf470 by making subprocess calls async
with kill_on_drop. The guard is now redundant and was causing "latest"
to not resolve to a concrete version in prefer-offline mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 9, 2026

Greptile Summary

Fixes a regression where github: backend tools configured with @latest fail with 404 errors during install/exec.

Key changes:

  • src/github.rs: Routes get_release_() to /repos/{repo}/releases/latest when tag is "latest" (instead of the incorrect /repos/{repo}/releases/tags/latest which treats "latest" as a literal tag name)
  • src/toolset/tool_version.rs: Removes the prefer_offline guard from the "latest" version resolution path, allowing "latest" to resolve to a concrete semver even in prefer-offline mode (while respecting true offline mode). The installed-version fast-path is preserved to avoid unnecessary network calls.
  • e2e/backend/test_github_latest: New regression test that verifies @latest resolves to a concrete semver (not the literal "latest" string) and executes correctly
  • e2e/backend/test_pipx_extras: Updates harlequin from 1.24.0 to 2.5.1

Both code fixes are minimal, well-scoped, and directly address the reported regression. The e2e test provides solid coverage of the primary scenario with explicit assertions for both negative (reject literal "latest") and positive (require semver pattern) cases.

Confidence Score: 4/5

  • Low risk — targeted fixes to a specific regression with comprehensive e2e test coverage.
  • Changes are minimal and well-justified. The GitHub API URL fix is unambiguously correct (route "latest" to the correct endpoint). The prefer-offline guard removal is safe because: (1) it only applies when not in true offline mode, (2) the installed-version fast-path prevents unnecessary calls, and (3) it restores proper behavior that was broken in the prior regression. The e2e test now includes both strong negative assertions (verify "latest" string doesn't appear) and positive semver pattern matching, providing solid verification of the fix.
  • No files require special attention.

Important Files Changed

Filename Overview
src/github.rs Core bug fix: Routes get_release_() to /releases/latest when tag == "latest" instead of the incorrect /releases/tags/latest. Change is minimal and correct — GitHub's API uses the /releases/latest endpoint specifically for retrieving the latest release.
src/toolset/tool_version.rs Removes the prefer_offline guard from the "latest" version resolution path. Uninstalled tools with version = "latest" will now make a remote call even in prefer-offline mode, which is a deliberate improvement: it ensures "latest" resolves to a concrete semver instead of propagating the literal "latest" string as an install path. True offline mode is still respected.
e2e/backend/test_github_latest Regression test verifying @latest resolves correctly. Uses two complementary assertions: (1) negative check ensures the literal string "latest" does not appear in the version column, (2) positive check ensures a semver-like pattern (e.g., "1.0.0") is present. Test covers both install and exec paths.
e2e/backend/test_pipx_extras Updates harlequin from 1.24.0 to 2.5.1 and softens the python3.12 selection comment for consistency. No logic changes.

Last reviewed commit: ded8093

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly fixes an issue with resolving the latest version for GitHub-backend tools by using the correct API endpoint and addresses a regression that prevented latest from being resolved in prefer-offline mode. However, a high-severity credential leakage vulnerability was identified in src/github.rs. The get_release_ function uses an untrusted api_url (from mise.toml) to construct requests, and the get_headers function incorrectly attaches the user's GITHUB_TOKEN to these requests even for non-GitHub hosts. This allows a malicious project to steal a user's GitHub credentials, and this PR increases exposure to this vulnerability by making remote lookups for latest more frequent. Additionally, while a new end-to-end test has been added, there is a suggestion to improve its long-term maintainability.

Comment on lines +276 to +280
let url = if tag == "latest" {
format!("{api_url}/repos/{repo}/releases/latest")
} else {
format!("{api_url}/repos/{repo}/releases/tags/{tag}")
};
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.

security-high high

The get_release_ function constructs a URL using the api_url parameter, which can be provided by an untrusted mise.toml configuration file. This URL is then passed to get_headers, which incorrectly attaches the user's GITHUB_TOKEN (or MISE_GITHUB_ENTERPRISE_TOKEN) to the request even if the host is not api.github.com.

A malicious project can specify a custom api_url in its mise.toml (e.g., api_url = "https://attacker.com") to steal the user's GitHub credentials when mise attempts to resolve tool versions.

This vulnerability is exacerbated by the changes in src/toolset/tool_version.rs which remove the prefer_offline guard, causing mise to perform remote lookups for latest versions more frequently, even in modes where it previously avoided network requests.

Comment on lines +7 to +10
cat <<EOF >mise.toml
[tools]
"github:jdx/mise-test-fixtures" = { version = "latest", asset_pattern = "hello-world-1.0.0.tar.gz", bin_path = "hello-world-1.0.0/bin", postinstall = "chmod +x \$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world" }
EOF
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.

medium

The test configuration hardcodes the version "1.0.0" in asset_pattern, bin_path, and postinstall. This makes the test brittle and dependent on the jdx/mise-test-fixtures repository's "latest" release always pointing to version 1.0.0.

If the test fixture is updated with a new release, this test will likely fail, which could cause confusion during unrelated development.

For better long-term maintainability, consider one of these approaches:

  • Modify the test fixture to provide version-agnostic asset names (e.g., hello-world.tar.gz).
  • Create a new test fixture that uses {{version}} templating in its asset names, and update this test to use it.

While the current implementation correctly tests the regression, improving its robustness will benefit the project in the long run.

Check that the version column contains a semver-like string and does not
contain the literal "latest", rather than just checking for the absence
of "latest (missing)".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx enabled auto-merge (squash) March 9, 2026 13:13
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 9, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.5 x -- echo 23.0 ± 0.3 22.4 27.7 1.00
mise x -- echo 23.3 ± 0.4 22.6 26.4 1.01 ± 0.02

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.5 env 22.8 ± 0.7 22.0 27.8 1.00
mise env 22.9 ± 0.4 22.4 25.1 1.00 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.5 hook-env 23.2 ± 0.3 22.4 24.9 1.00
mise hook-env 23.5 ± 0.3 22.9 24.9 1.01 ± 0.02

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.5 ls 22.6 ± 0.5 22.0 29.5 1.00
mise ls 22.9 ± 0.3 22.3 26.5 1.01 ± 0.03

xtasks/test/perf

Command mise-2026.3.5 mise Variance
install (cached) 150ms 151ms +0%
ls (cached) 82ms 82ms +0%
bin-paths (cached) 84ms 84ms +0%
task-ls (cached) 839ms ⚠️ 2747ms -69%

⚠️ Warning: task-ls cached performance variance is -69%

harlequin 1.24.0 is incompatible with duckdb 1.5.0 (released today),
causing an UnboundLocalError in plugin loading. Bump to 2.5.1 which
works with the latest duckdb.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx merged commit b71c870 into main Mar 9, 2026
36 checks passed
@jdx jdx deleted the fix/github-latest-version-resolution branch March 9, 2026 13:35
jdx pushed a commit that referenced this pull request Mar 9, 2026
### 🐛 Bug Fixes

- **(activate)** reorder shims to front of PATH on re-source in fish by
@jdx in [#8534](#8534)
- **(backend)** strip mise shims from dependency_env PATH to prevent
fork bomb by @pose in [#8475](#8475)
- **(github)** resolve "latest" version correctly via GitHub API by @jdx
in [#8532](#8532)
- **(lock)** set env tags and clarify lockfile docs by @jdx in
[#8519](#8519)
- **(lock)** use separate mise.<env>.lock files instead of env tags by
@jdx in [#8523](#8523)
- **(task)** include args in task output prefix and truncate long
prefixes by @jdx in [#8533](#8533)
- **(task)** only include args in task prefix when disambiguating
duplicates by @jdx in [#8536](#8536)
- **(test)** pin goreleaser version in attestation e2e test by @jdx in
[#8518](#8518)
- **(windows)** env._.source needs to run bash.exe on Windows (fix
#6513) by @pjeby in [#8520](#8520)
- handle locked .exe shims on Windows during reshim by @davireis in
[#8517](#8517)

### 🚜 Refactor

- **(prepare)** remove touch_outputs and update docs to reflect blake3
hashing by @jdx in [#8535](#8535)

### 📚 Documentation

- **(docker)** replace jdxcode/mise image with curl install, update to
debian:13-slim by @jdx in [#8526](#8526)
- fix "gzip: stdin is encrypted" error in shell tricks cookbook by
@pjeby in [#8512](#8512)

### 📦 Registry

- add tigerbeetle
([github:tigerbeetle/tigerbeetle](https://github.com/tigerbeetle/tigerbeetle))
by @risu729 in [#8514](#8514)

### New Contributors

- @pjeby made their first contribution in
[#8520](#8520)
- @davireis made their first contribution in
[#8517](#8517)
- @Aurorxa made their first contribution in
[#8511](#8511)

## 📦 Aqua Registry Updates

#### New Packages (6)

-
[`betterleaks/betterleaks`](https://github.com/betterleaks/betterleaks)
- [`majorcontext/moat`](https://github.com/majorcontext/moat)
- [`princjef/gomarkdoc`](https://github.com/princjef/gomarkdoc)
- [`remko/age-plugin-se`](https://github.com/remko/age-plugin-se)
- [`sudorandom/fauxrpc`](https://github.com/sudorandom/fauxrpc)
- [`swanysimon/mdlint`](https://github.com/swanysimon/mdlint)

#### Updated Packages (1)

- [`moonrepo/moon`](https://github.com/moonrepo/moon)
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