Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a global libc configuration setting to mise, enabling explicit control over glibc and musl detection across various backends including Aqua, Bun, Node, Python, and vfox. The changes update asset matching, platform identification, and cache key generation to respect this new setting. Review feedback highlights opportunities to make libc detection more robust in the Node and Python plugins by utilizing runtime platform detection instead of compile-time constants. Furthermore, performance improvements were identified in the Aqua backend to minimize redundant string allocations and tokenization during asset selection.
| let flavor = settings.node.flavor.as_deref().or_else(|| { | ||
| if target.is_current() && target.os_name() == "linux" && settings.libc() == Some("musl") | ||
| { | ||
| Some("musl") | ||
| } else { | ||
| None | ||
| } | ||
| }); |
There was a problem hiding this comment.
The current logic for selecting the musl flavor is too restrictive. By checking target.is_current() and settings.libc(), it breaks flavor selection during cross-platform locking and fails to automatically select the musl flavor on native musl systems. Using target.libc() is more robust as it handles both the global setting and runtime detection for any target platform, aligning with the principle of using specific parameters over general context.
let flavor = settings.node.flavor.as_deref().or(target.libc().filter(|&l| l == "musl"));References
- When overriding a method or working within a specific context, use the provided parameters (like target) instead of re-deriving values from a more general context (like settings) to ensure configurations are correctly applied.
| let flavor = settings.node.flavor.as_deref().or_else(|| { | ||
| if settings.os() == "linux" && settings.libc() == Some("musl") { | ||
| Some("musl") | ||
| } else { | ||
| None | ||
| } | ||
| }); |
There was a problem hiding this comment.
Similar to the issue in build_platform_slug, this logic should respect the detected libc of the current platform rather than just the explicit setting. This ensures native musl systems get the correct flavor automatically.
let flavor = settings.node.flavor.as_deref().or(crate::platform::Platform::current().libc().filter(|&l| l == "musl"));| let libc = settings.libc().unwrap_or_else(|| { | ||
| if built_info::CFG_ENV == "musl" { | ||
| "musl" | ||
| } else { | ||
| "gnu" | ||
| } | ||
| }); |
There was a problem hiding this comment.
Using built_info::CFG_ENV for libc detection is unreliable as it reflects the environment where mise was compiled, not the environment where it is running. This will fail to detect musl on a native musl system if mise was built for glibc. It should use the runtime detection logic, ideally via Platform::current().libc().
let libc = settings.libc().or(crate::platform::Platform::current().libc()).unwrap_or("gnu");| asset_strs.iter().find_map(|expected| { | ||
| let exact = assets | ||
| .iter() | ||
| .find(|a| a.name == *expected || a.name.to_lowercase() == expected.to_lowercase()); | ||
|
|
||
| if prefer_musl | ||
| && let Some(musl_asset) = assets | ||
| .iter() | ||
| .find(|a| is_musl_variant_of_expected_asset(&a.name, expected)) | ||
| { | ||
| return Some(musl_asset); | ||
| } | ||
|
|
||
| exact | ||
| }) |
| && without_libc_variant_tokens(&asset_tokens) | ||
| == without_libc_variant_tokens(&expected_tokens) |
There was a problem hiding this comment.
This comparison allocates two new Vec on every call, which is inefficient in a nested loop. Using itertools::equal with filtered iterators avoids these allocations.
&& itertools::equal(
asset_tokens.iter().filter(|&t| !matches!(t.as_str(), "musl" | "gnu" | "glibc")),
expected_tokens.iter().filter(|&t| !matches!(t.as_str(), "musl" | "gnu" | "glibc"))
)| fn without_libc_variant_tokens(tokens: &[String]) -> Vec<String> { | ||
| tokens | ||
| .iter() | ||
| .filter(|token| !matches!(token.as_str(), "musl" | "gnu" | "glibc")) | ||
| .cloned() | ||
| .collect() | ||
| } |
06c15fe to
bc808e4
Compare
Greptile SummaryThis PR introduces a global Confidence Score: 5/5Safe to merge; no P1/P0 issues found. The two P2 observations are a documented behavior improvement and a minor assumption in the fuzzy matcher. No correctness bugs or security issues were identified. The logic threading libc preference through platform detection, cache keys, and backends is internally consistent and well-tested. The python_os change is a behavior improvement (more correct) that is a minor migration concern for existing users. src/plugins/core/python.rs — behavior change for musl-compiled mise binaries on glibc hosts worth documenting in a migration/changelog note. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Tool Install / Lock Request"] --> B{"settings.libc() set?"}
B -- "musl / glibc / gnu" --> C["Normalize: musl → musl\nglibc / gnu → gnu"]
B -- "unset" --> D["Platform::current()\nRuntime linker detection\n(ld-linux-* / ld-musl-*)"]
D -- "no linker found" --> E["Compile-time fallback\ncfg!(target_env = musl)"]
C --> F["Platform::current() qualifier"]
D --> F
E --> F
F -- "qualifier = Some(musl)" --> G["libc = musl"]
F -- "qualifier = None" --> H["libc = glibc (default)"]
G --> I{"Backend"}
H --> I
I -- "aqua" --> J["apply_aqua_libc_replacement\n+ musl-variant fuzzy matching"]
I -- "Node" --> K["append -musl flavor when musl"]
I -- "Python" --> L["unknown-linux-{musl|gnu}"]
I -- "Bun" --> M["is_musl() → musl slug"]
I -- "vfox" --> N["Vfox.runtime_env_type\n→ RUNTIME.envType"]
F --> O["CacheManagerBuilder\nkey += libc qualifier"]
Reviews (3): Last reviewed commit: "feat(backend): add global libc preferenc..." | Re-trigger Greptile |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.22 x -- echo |
23.9 ± 0.4 | 23.2 | 28.8 | 1.00 |
mise x -- echo |
24.4 ± 0.7 | 23.8 | 32.3 | 1.02 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.22 env |
23.3 ± 0.5 | 22.5 | 27.6 | 1.00 |
mise env |
23.8 ± 0.5 | 23.1 | 32.3 | 1.02 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.22 hook-env |
24.3 ± 0.7 | 23.3 | 26.6 | 1.00 |
mise hook-env |
25.1 ± 0.6 | 23.9 | 27.6 | 1.03 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.22 ls |
24.2 ± 0.3 | 23.5 | 25.9 | 1.00 |
mise ls |
25.5 ± 0.6 | 24.4 | 27.8 | 1.05 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.4.22 | mise | Variance |
|---|---|---|---|
| install (cached) | 171ms | 179ms | -4% |
| ls (cached) | 82ms | 85ms | -3% |
| bin-paths (cached) | 83ms | 86ms | -3% |
| task-ls (cached) | 795ms | 790ms | +0% |
bc808e4 to
a5b17eb
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a5b17eb. Configure here.
a5b17eb to
16a6a2a
Compare
## Summary [PR #9404](#9404) (`feat(backend): add global libc preference`) taught Node's slug builder to append `-musl` for musl targets but kept routing through `nodejs.org/dist/`, which does not host musl tarballs (they live at `unofficial-builds.nodejs.org`). The visible symptom was in [PR #9396](#9396 `mise.lock` diff: the URL gained a `-musl` suffix while the checksum stayed pinned to the original glibc tarball. ```toml [tools.node."platforms.linux-x64-musl"] checksum = "sha256:dbf5b8665..." # ← still the glibc checksum url = ".../v24.14.0/node-v24.14.0-linux-x64-musl.tar.gz" # ← 404, wrong host ``` Mechanically: `resolve_lock_info` builds a 404'ing URL on `nodejs.org/dist`, fetches the wrong `SHASUMS256.txt` (which doesn't list `-musl.tar.gz`), gets `None` back, and the lockfile merge preserves the **stale glibc checksum** alongside the new URL. Anyone running `mise install` against that lockfile on a musl system would either 404 or hit a checksum mismatch. The aqua/github-backed tools in the same release diff updated cleanly because their checksum source rotates with the artifact. Node is unique in fetching checksums from a separate `SHASUMS256.txt`. ## Changes ### `src/plugins/core/node.rs` Add `mirror_url_for(&SettingsNode, filename)` that swaps to `https://unofficial-builds.nodejs.org/download/release/` when a filename references a musl artifact and the user has not set a custom `node.mirror_url`. Wire it into `resolve_lock_info`, `get_tarball_url`, `BuildOpts::new`, and `shasums_url` so the tarball URL and the matching `SHASUMS256.txt` always come from the same host. Three unit tests cover routing (default → glibc, musl → unofficial-builds, custom mirror passes through unchanged). ### `src/lockfile.rs` Defense in depth: when merging `PlatformInfo` (both in `set_platform_info` and `merge_with`), drop the other side's `checksum`/`size`/`url_api` if URLs disagree — those fields describe a specific artifact and become stale once the URL changes. The pre-existing `test_platform_info_merge_prefers_sha256` was asserting that sha256 should win even across mismatched URLs, which is exactly the latent bug; updated it to use a shared URL and added `test_platform_info_merge_drops_stale_checksum_on_url_change`. ### `mise.lock` Re-ran `mise lock node` to fix the three corrupted node musl entries. Checksums verified against upstream: ```sh $ curl -fsSL https://unofficial-builds.nodejs.org/download/release/v24.14.0/SHASUMS256.txt | grep -E "linux-(arm64|x64)-musl\.tar\.gz" 8f81d47b7f... node-v24.14.0-linux-arm64-musl.tar.gz bae0f23204... node-v24.14.0-linux-x64-musl.tar.gz ``` Both match what mise now writes. ## Test plan - [x] `cargo test` — 778 passed, 0 failed (includes 3 new node tests + 1 new lockfile test, plus an updated test that previously asserted the latent bug). - [x] `cargo clippy --all-features --tests` — clean. - [x] `cargo fmt` — clean. - [x] `mise lock node` against this branch produces correct URLs + checksums for all three node musl platform variants. - [ ] Install on Alpine / musl host: `MISE_LIBC=musl mise install node@24.14.0` should download from `unofficial-builds.nodejs.org` and run. - [ ] Glibc regression: same flow without `MISE_LIBC=musl` should still hit `nodejs.org/dist`. *This PR was generated by an AI coding assistant.* <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes Node.js download/checksum URL selection and lockfile merge behavior, which can affect installs and lockfile correctness across platforms; scope is contained with added tests. > > **Overview** > Fixes Node.js *musl* installs/lock resolution by routing musl tarball URLs (and their matching `SHASUMS256.txt`/signature URLs) to `unofficial-builds.nodejs.org` when using the default mirror, while still respecting user-configured `node.mirror_url`. > > Hardens lockfile merging so when a platform artifact `url` changes, stale artifact-bound fields (`checksum`, `size`, `url_api`) from the other side are dropped instead of preserved, preventing mismatched URL+checksum pairs. > > Regenerates `mise.lock` Node musl entries to use the unofficial-builds URLs with updated sha256 checksums, and adds/updates unit tests covering the new mirror routing and merge semantics. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit dd68707. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
### 🚀 Features - **(backend)** add global libc preference by @jdx in [#9404](#9404) - opt-in to pre-release versions for github and aqua backends by @jakedgy in [#9329](#9329) ### 🐛 Bug Fixes - **(backend)** allow unresolved latest opt-in by @jdx in [#9401](#9401) - **(install)** stop rewriting healthy runtime symlinks by @jdx in [#9410](#9410) - **(node)** route musl tarball URLs to unofficial-builds by @jdx in [#9409](#9409) - **(prune)** skip remote version resolution for tracked configs by @jdx in [#9406](#9406) - **(schema)** allow array values in tool additionalProperties by @JP-Ellis in [#9400](#9400) ### 📦️ Dependency Updates - bump communique to 1.1.2 by @jdx in [#9402](#9402) ### 📦 Registry - use aqua for rumdl by @scop in [#9397](#9397) ### Chore - **(ci)** improve pr-closer workflow by @jdx in [#9403](#9403) - **(release)** stop appending sponsor blurb when communique succeeds by @jdx in [#9395](#9395) ### New Contributors - @JP-Ellis made their first contribution in [#9400](#9400)

Summary
Adds a global
libcsetting (MISE_LIBC) for selecting Linux precompiled binary variants across backends that can safely honor a libc preference.Details
musl,glibc, andgnu.Platform::current()andPlatformTargetso generic GitHub asset matching can prefer musl or glibc variants consistently.unknown-linux-gnu/unknown-linux-muslaccording to the target/global libc preference;musltoken when aqua cannot express the variant yet.envType.Backend Audit
Conda, Go, Zig, Deno, Ruby, Java, Erlang, and Rust do not currently expose a safe global libc selection path here because their upstream artifact naming is either not libc-specific, hard-coded by upstream, or already controlled by backend-specific settings.
Validation
cargo test libccargo test backend::aqua::lock_candidate_testscargo test -p vfox config::tests::test_env_typecargo fmt --checkgit diff --checkcargo check --all-features, schema validation, markdownlint, shellcheck, shfmt, taplo, prettier, actionlint, lua checksThis PR was generated by an AI coding assistant.
Note
Medium Risk
Adds a new global
libcsetting that changes how Linux artifacts are selected across multiple backends and influences cache keys, so mis-detection or incorrect preference could cause wrong binaries/lock entries to be chosen.Overview
Adds a global
libcsetting (schema +settings.toml, envMISE_LIBC, acceptingglibc/gnu/musl) and uses it to influence Linux platform qualification and libc detection.Updates platform/target handling to expose libc (including compound qualifiers) and adjusts caching and GitHub asset matching so musl variants can be preferred when requested.
Extends backend/tool integrations to honor the preference:
aquanow rewrites Linux replacements and prefers musl release assets for musl lock targets, Node/Python/Bun select musl/glibc variants accordingly, andvfoxpasses an optional runtimeenvTypeinto plugin hooks. Docs are updated to describe the new setting and Docker override behavior.Reviewed by Cursor Bugbot for commit 16a6a2a. Bugbot is set up for automated code reviews on this repo. Configure here.