Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions e2e/lockfile/test_lockfile_locked_mode
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,23 @@ EOF

assert_contains "mise install --dry-run 2>&1" "would install"

# --- Test 7: mise lock refuses to run in --locked mode ---
export MISE_LOCKFILE=1

cat <<'EOF' >mise.toml
[tools]
jq = "1.7.1"
EOF

cat <<EOF >mise.lock
[[tools.jq]]
version = "1.7.1"
backend = "aqua:jqlang/jq"
"platforms.$PLATFORM" = { url = "https://example.com/jq-1.7.1.tar.gz" }
EOF

assert_fail_contains "mise lock --locked 2>&1" "mise lock is disabled in --locked mode"
MISE_LOCKED=1 assert_fail_contains "mise lock 2>&1" "mise lock is disabled in --locked mode"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

E2E test doesn't propagate MISE_LOCKED to subprocess

Medium Severity

MISE_LOCKED=1 assert_fail_contains "..." sets MISE_LOCKED as a shell variable via prefix assignment to a function call, but does NOT export it. Inside quiet_assert_fail, the command runs via bash -c "$1 2>&1" — a new process that only inherits exported environment variables. Since MISE_LOCKED is never exported, mise lock won't see it, won't enter locked mode, and won't produce the expected error message. The test will fail for the wrong reason or unexpectedly pass/fail.

Fix in Cursor Fix in Web


# Restore for any subsequent tests
export MISE_LOCKFILE=1
7 changes: 6 additions & 1 deletion src/cli/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::toolset::Toolset;
use crate::ui::multi_progress_report::MultiProgressReport;
use crate::{cli::args::ToolArg, config::Settings};
use console::style;
use eyre::Result;
use eyre::{Result, bail};
use tokio::sync::Semaphore;
use tokio::task::JoinSet;

Expand Down Expand Up @@ -52,6 +52,11 @@ pub struct Lock {
impl Lock {
pub async fn run(self) -> Result<()> {
let settings = Settings::get();
if settings.locked {
bail!(
"mise lock is disabled in --locked mode\nhint: Remove --locked or unset MISE_LOCKED=1"
);
}
let config = Config::get().await?;

let ts = config.get_toolset().await?;
Expand Down
2 changes: 1 addition & 1 deletion src/cli/use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl Use {
.cloned()
.map(|t| match t.tvr {
Some(tvr) => {
if tvr.version() == "latest" {
if tvr.version() == "latest" && !Settings::get().locked {
// user specified `@latest` so we should resolve the latest version
// TODO: this should only happen on this tool, not all of them
resolve_options.latest_versions = true;
Expand Down
15 changes: 14 additions & 1 deletion src/toolset/tool_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::lockfile::{CondaPackageInfo, LockfileTool, PlatformInfo};
use crate::toolset::{ToolRequest, ToolVersionOptions, tool_request};
use console::style;
use dashmap::DashMap;
use eyre::Result;
use eyre::{Result, bail};
use jiff::Timestamp;
#[cfg(windows)]
use path_absolutize::Absolutize;
Expand Down Expand Up @@ -210,6 +210,19 @@ impl ToolVersion {
{
return Ok(Self::from_lockfile(request.clone(), lt));
}
let settings = Settings::get();
if settings.locked
&& opts.use_locked_version
&& settings.lockfile_enabled()
&& !has_linked_version(request.ba())
&& request.source().path().is_some()
{
bail!(
"{}@{} is not in the lockfile\nhint: Run `mise install` without --locked to update the lockfile",
request.ba().short,
request.version()
);
}
Comment thread
cursor[bot] marked this conversation as resolved.

match v.split_once(':') {
Some((ref_type @ ("ref" | "tag" | "branch" | "rev"), r)) => {
Expand Down
Loading