fix(lockfile): prevent lockfile writes when --locked is set#8308
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary of ChangesHello @jdx, 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 introduces a crucial safeguard to prevent unintended modifications to the Highlights
Changelog
Activity
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. 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
|
There was a problem hiding this comment.
Code Review
This pull request correctly prevents lockfile modifications when the --locked flag is used by adding checks in update_lockfiles and auto_lock_new_versions. The changes are straightforward and align with the intended behavior. The suggestions to refactor the code by fetching the settings object once per function have been kept as they improve readability and avoid redundant calls to Settings::get().
|
|
||
| pub fn update_lockfiles(config: &Config, ts: &Toolset, new_versions: &[ToolVersion]) -> Result<()> { | ||
| if !Settings::get().lockfile { | ||
| if !Settings::get().lockfile || Settings::get().locked { |
There was a problem hiding this comment.
To improve readability and avoid multiple calls to Settings::get(), consider fetching the settings once at the beginning of the function and using the variable in the if condition.
For example:
pub fn update_lockfiles(config: &Config, ts: &Toolset, new_versions: &[ToolVersion]) -> Result<()> {
let settings = Settings::get();
if !settings.lockfile || settings.locked {
return Ok(());
}
// ...
}| /// platforms run `mise install`. | ||
| pub async fn auto_lock_new_versions(_config: &Config, new_versions: &[ToolVersion]) -> Result<()> { | ||
| if !Settings::get().lockfile || new_versions.is_empty() { | ||
| if !Settings::get().lockfile || Settings::get().locked || new_versions.is_empty() { |
There was a problem hiding this comment.
To improve readability and avoid multiple calls to Settings::get(), consider fetching the settings once at the beginning of the function. This also allows you to remove the redundant Settings::get() call on line 699.
For example:
pub async fn auto_lock_new_versions(_config: &Config, new_versions: &[ToolVersion]) -> Result<()> {
let settings = Settings::get();
if !settings.lockfile || settings.locked || new_versions.is_empty() {
return Ok(());
}
// ...
let jobs = settings.jobs;
// ...
}There was a problem hiding this comment.
Pull request overview
This PR updates lockfile behavior so that running mise install --locked will not modify mise.lock, aligning with the intent that locked mode should treat existing lockfile content as authoritative during installation.
Changes:
- Skip
update_lockfiles()whenSettings::get().lockedis enabled. - Skip
auto_lock_new_versions()whenSettings::get().lockedis enabled (in addition to existing guards).
Comments suppressed due to low confidence (1)
src/lockfile.rs:701
- The guard calls
Settings::get()multiple times and then fetcheslet settings = Settings::get();again a few lines later (forjobs). Consider hoistinglet settings = Settings::get();before the guard and reusing it forlockfile,locked, andjobsto avoid redundant lookups.
pub async fn auto_lock_new_versions(_config: &Config, new_versions: &[ToolVersion]) -> Result<()> {
if !Settings::get().lockfile || Settings::get().locked || new_versions.is_empty() {
return Ok(());
}
// Group new_versions by lockfile path (only mise.toml sources, matching update_lockfiles)
let mut versions_by_lockfile: HashMap<PathBuf, Vec<&ToolVersion>> = HashMap::new();
for tv in new_versions {
if !tv.request.source().is_mise_toml() {
continue;
}
if let Some(source_path) = tv.request.source().path() {
let (lockfile_path, _) = lockfile_path_for_config(source_path);
versions_by_lockfile
.entry(lockfile_path)
.or_default()
.push(tv);
}
}
let settings = Settings::get();
let jobs = settings.jobs;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| pub fn update_lockfiles(config: &Config, ts: &Toolset, new_versions: &[ToolVersion]) -> Result<()> { | ||
| if !Settings::get().lockfile { | ||
| if !Settings::get().lockfile || Settings::get().locked { |
There was a problem hiding this comment.
Settings::get() is called twice in the guard, which means two Arc clones and two RwLock reads. Consider storing let settings = Settings::get(); and using settings.lockfile/settings.locked for the early-return to keep this consistent with other code and avoid repeated lookups.
| if !Settings::get().lockfile || Settings::get().locked { | |
| let settings = Settings::get(); | |
| if !settings.lockfile || settings.locked { |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 x -- echo |
17.4 ± 0.4 | 16.6 | 18.6 | 1.00 |
mise x -- echo |
17.7 ± 0.4 | 16.7 | 21.5 | 1.02 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 env |
16.8 ± 0.4 | 15.9 | 20.7 | 1.00 |
mise env |
16.9 ± 0.3 | 16.1 | 18.0 | 1.01 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 hook-env |
17.1 ± 0.3 | 16.2 | 19.1 | 1.00 |
mise hook-env |
17.4 ± 0.3 | 16.5 | 18.8 | 1.01 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 ls |
15.9 ± 0.4 | 15.0 | 18.2 | 1.00 |
mise ls |
16.2 ± 0.3 | 15.3 | 17.6 | 1.02 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.2.19 | mise | Variance |
|---|---|---|---|
| install (cached) | 89ms | 89ms | +0% |
| ls (cached) | 59ms | 59ms | +0% |
| bin-paths (cached) | 61ms | 61ms | +0% |
| task-ls (cached) | 680ms | 675ms | +0% |
|
I think this PR did break output
|
### 🚀 Features - **(conda)** replace custom backend with rattler crates by @jdx in [#8325](#8325) - **(task)** enforce per-task timeout configuration by @tvararu in [#8250](#8250) - **(vsix)** added vsix archives to http backend by @sosumappu in [#8306](#8306) - add core dotnet plugin for .NET SDK management by @jdx in [#8326](#8326) ### 🐛 Bug Fixes - **(conda)** preserve conda_packages on locked install and fix temp file race by @jdx in [#8335](#8335) - **(conda)** deduplicate repodata records to fix solver error on Linux by @jdx in [#8337](#8337) - **(env)** include watch_files in fast-path early exit check by @jdx in [#8317](#8317) - **(env)** clear fish completions when setting/unsetting shell aliases by @jdx in [#8324](#8324) - **(lockfile)** prevent lockfile writes when --locked is set by @jdx in [#8308](#8308) - **(lockfile)** prune orphan tool entries on mise lock by @mackwic in [#8265](#8265) - **(lockfile)** error on contradictory locked=true + lockfile=false config by @jdx in [#8329](#8329) - **(regal)** Update package location by @charlieegan3 in [#8315](#8315) - **(release)** strip markdown heading prefix from communique release title by @jdx in [#8303](#8303) - **(schema)** enforce additionalProperties constraint for env by @adamliang0 in [#8328](#8328) ### 📚 Documentation - Remove incorrect oh-my-zsh plugin ordering comment by @bvosk in [#8323](#8323) - require AI disclosure on GitHub comments by @jdx in [#8330](#8330) ### 📦 Registry - add `oxfmt` by @taoufik07 in [#8316](#8316) ### New Contributors - @adamliang0 made their first contribution in [#8328](#8328) - @tvararu made their first contribution in [#8250](#8250) - @bvosk made their first contribution in [#8323](#8323) - @taoufik07 made their first contribution in [#8316](#8316) - @charlieegan3 made their first contribution in [#8315](#8315) - @sosumappu made their first contribution in [#8306](#8306) ## 📦 Aqua Registry Updates #### New Packages (3) - [`Tyrrrz/FFmpegBin`](https://github.com/Tyrrrz/FFmpegBin) - [`elixir-lang/expert`](https://github.com/elixir-lang/expert) - [`erikjuhani/basalt`](https://github.com/erikjuhani/basalt) #### Updated Packages (5) - [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`jackchuka/mdschema`](https://github.com/jackchuka/mdschema) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`peco/peco`](https://github.com/peco/peco)
## Summary - When `mise install --locked` is run, the `mise.lock` file should not be modified - Adds early returns in `update_lockfiles` and `auto_lock_new_versions` when `Settings::get().locked` is true - Consistent with how `cargo install --locked` and `uv pip install --locked` behave: the lock file is treated as authoritative and must not be updated ## Changes Made - `update_lockfiles()`: guard changed from `if !Settings::get().lockfile` to `if !Settings::get().lockfile || Settings::get().locked` - `auto_lock_new_versions()`: guard changed from `if !Settings::get().lockfile || new_versions.is_empty()` to `if !Settings::get().lockfile || Settings::get().locked || new_versions.is_empty()` ## Testing - Existing lockfile tests continue to pass - The `--locked` flag now prevents any writes to `mise.lock` during install ## Related - Spec: `/home/jdx/src/mise/src/lockfile.rs` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small conditional-guard change that only disables lockfile writes in locked mode; minimal behavioral surface area and no security/data-handling impact. > > **Overview** > When `Settings::get().locked` (e.g. `mise install --locked`) is enabled, lockfile update paths now short-circuit to avoid modifying `mise.lock`. > > Specifically, `update_lockfiles` and `auto_lock_new_versions` add an early return when locked mode is active, preventing post-install lockfile refresh/auto-lock behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fdccfd2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
### 🚀 Features - **(conda)** replace custom backend with rattler crates by @jdx in [jdx#8325](jdx#8325) - **(task)** enforce per-task timeout configuration by @tvararu in [jdx#8250](jdx#8250) - **(vsix)** added vsix archives to http backend by @sosumappu in [jdx#8306](jdx#8306) - add core dotnet plugin for .NET SDK management by @jdx in [jdx#8326](jdx#8326) ### 🐛 Bug Fixes - **(conda)** preserve conda_packages on locked install and fix temp file race by @jdx in [jdx#8335](jdx#8335) - **(conda)** deduplicate repodata records to fix solver error on Linux by @jdx in [jdx#8337](jdx#8337) - **(env)** include watch_files in fast-path early exit check by @jdx in [jdx#8317](jdx#8317) - **(env)** clear fish completions when setting/unsetting shell aliases by @jdx in [jdx#8324](jdx#8324) - **(lockfile)** prevent lockfile writes when --locked is set by @jdx in [jdx#8308](jdx#8308) - **(lockfile)** prune orphan tool entries on mise lock by @mackwic in [jdx#8265](jdx#8265) - **(lockfile)** error on contradictory locked=true + lockfile=false config by @jdx in [jdx#8329](jdx#8329) - **(regal)** Update package location by @charlieegan3 in [jdx#8315](jdx#8315) - **(release)** strip markdown heading prefix from communique release title by @jdx in [jdx#8303](jdx#8303) - **(schema)** enforce additionalProperties constraint for env by @adamliang0 in [jdx#8328](jdx#8328) ### 📚 Documentation - Remove incorrect oh-my-zsh plugin ordering comment by @bvosk in [jdx#8323](jdx#8323) - require AI disclosure on GitHub comments by @jdx in [jdx#8330](jdx#8330) ### 📦 Registry - add `oxfmt` by @taoufik07 in [jdx#8316](jdx#8316) ### New Contributors - @adamliang0 made their first contribution in [jdx#8328](jdx#8328) - @tvararu made their first contribution in [jdx#8250](jdx#8250) - @bvosk made their first contribution in [jdx#8323](jdx#8323) - @taoufik07 made their first contribution in [jdx#8316](jdx#8316) - @charlieegan3 made their first contribution in [jdx#8315](jdx#8315) - @sosumappu made their first contribution in [jdx#8306](jdx#8306) ## 📦 Aqua Registry Updates #### New Packages (3) - [`Tyrrrz/FFmpegBin`](https://github.com/Tyrrrz/FFmpegBin) - [`elixir-lang/expert`](https://github.com/elixir-lang/expert) - [`erikjuhani/basalt`](https://github.com/erikjuhani/basalt) #### Updated Packages (5) - [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`jackchuka/mdschema`](https://github.com/jackchuka/mdschema) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`peco/peco`](https://github.com/peco/peco)
Summary
mise install --lockedis run, themise.lockfile should not be modifiedupdate_lockfilesandauto_lock_new_versionswhenSettings::get().lockedis truecargo install --lockedanduv pip install --lockedbehave: the lock file is treated as authoritative and must not be updatedChanges Made
update_lockfiles(): guard changed fromif !Settings::get().lockfiletoif !Settings::get().lockfile || Settings::get().lockedauto_lock_new_versions(): guard changed fromif !Settings::get().lockfile || new_versions.is_empty()toif !Settings::get().lockfile || Settings::get().locked || new_versions.is_empty()Testing
--lockedflag now prevents any writes tomise.lockduring installRelated
/home/jdx/src/mise/src/lockfile.rsNote
Low Risk
Small conditional-guard change that only disables lockfile writes in locked mode; minimal behavioral surface area and no security/data-handling impact.
Overview
When
Settings::get().locked(e.g.mise install --locked) is enabled, lockfile update paths now short-circuit to avoid modifyingmise.lock.Specifically,
update_lockfilesandauto_lock_new_versionsadd an early return when locked mode is active, preventing post-install lockfile refresh/auto-lock behavior.Written by Cursor Bugbot for commit fdccfd2. This will update automatically on new commits. Configure here.