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
25 changes: 13 additions & 12 deletions docs/cli/trust.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@
Marks a config file as trusted

This means mise is allowed to parse the file when it needs to read config
that may execute code or affect the environment. mise checks trust before
parsing `mise.toml`. Without trust, mise may prompt, skip the config in some
discovery paths, fail with an untrusted-config error when it cannot prompt,
or assume trust in detected CI unless paranoid mode is enabled.

Safe config files do not require trust: files that only contain
`min_version`, `[tools]` entries with plain version strings (or arrays
of them), and `[tasks]` (no templates and no tool options) are loaded
without prompting, since nothing in them executes code at load time —
tools install and tasks run only on explicit commands like `mise install`
or `mise run`.
that may execute code or affect the environment. Without trust, mise may
prompt, skip the config in some discovery paths, or fail with an
untrusted-config error when it cannot prompt.

In normal mode, commands that execute project-defined behavior (`mise run`,
naked task invocations such as `mise <TASK>`, `mise install`, `mise exec`,
and `mise watch`) automatically trust their active config. Paranoid mode
requires explicit, content-bound trust for every non-global config.

In normal mode, safe config files do not require trust: files that only contain
`min_version`, `[tools]` entries with plain version strings (or arrays of
them), and `[tasks]` without templates or tool options.

Trust is shared across git worktrees: a config file inside a linked
worktree is trusted when the equivalent path in the repository's main
Expand Down Expand Up @@ -51,7 +52,7 @@ Does not trust or untrust any files.

### `--untrust`

No longer trust this config, will prompt in the future
Remove explicit trust for this config

Examples:

Expand Down
2 changes: 1 addition & 1 deletion docs/cli/untrust.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- **Effect**: modifies state
- **Source code**: [`src/cli/untrust.rs`](https://github.com/jdx/mise/blob/main/src/cli/untrust.rs)

No longer trust a config, will prompt in the future
Remove explicit trust for a config

## Arguments

Expand Down
24 changes: 13 additions & 11 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,12 @@ mise upgrade --bump node
## My config file is being ignored / `mise trust` issues

mise requires you to trust config files that were not created by you. Safe config files —
those that only contain `min_version`, `[tools]` entries with plain version strings (or
arrays of them), and `[tasks]` (no templates and no tool options) — are loaded without trust, since nothing in
them executes code at load time: tools install and tasks run only on explicit commands like
`mise install` or `mise run`. Everything else (env vars, hooks, settings, aliases, templates,
tool options) requires trust. Common issues:
those that only contain `min_version`, `[tools]` entries whose values are plain version
strings or arrays of strings, and `[tasks]` without templates — load without trust. Tool-option
tables and other top-level settings require trust. In normal mode, `mise run`, naked task
invocations such as `mise <TASK>`, `mise install`, `mise exec`, and `mise watch` automatically
trust the active config because they explicitly execute project-defined behavior. Other unsafe
config requires trust. Common issues:

- **Accidentally denied trust**: If mise prompted you to trust a file and you said no, it gets
added to the ignore list. Check the `ignored-configs` directory in your
Expand All @@ -259,17 +260,18 @@ tool options) requires trust. Common issues:
- **Symlinked configs**: If your config is symlinked (e.g., via GNU Stow), mise may track the
symlink target path. Try `mise trust` pointing to the actual file path.
- **CI**: In detected CI, mise assumes configs are trusted unless paranoid mode is enabled.
- **Non-interactive mode**: In non-interactive shells outside detected CI, such as IDE extensions or
scripts without a TTY, mise cannot prompt you to trust a config. Commands that directly load an
untrusted `mise.toml` can fail with an untrusted-config error. Commands that discover previously
tracked configs may skip untrusted entries instead. Either run `mise trust` beforehand or set
- **Non-interactive mode**: In a non-interactive shell, such as an IDE extension or script without
a TTY, mise cannot prompt you to trust a config. Outside normal-mode `mise run`, `mise <TASK>`,
`mise install`, `mise exec`, and `mise watch`, commands that directly load an untrusted
`mise.toml` can fail with an untrusted-config error. Commands that discover previously tracked
configs may skip untrusted entries instead. Either run `mise trust` beforehand or set
[`trusted_config_paths`](/configuration/settings.html#trusted_config_paths) in your global settings
for configs you trust.
- **Global config** (`~/.config/mise/config.toml`) should be auto-trusted. If it's not, run
`mise trust ~/.config/mise/config.toml` explicitly.

Run `mise doctor` (`mise dr`) to see if any config files are untrusted — it will list them
under "problems".
Run `mise doctor` (`mise dr`) to see if any config files are untrusted — it will
list them under "problems".

## How do idiomatic version files (`.python-version`, `.node-version`, etc.) work?

Expand Down
13 changes: 9 additions & 4 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ See [Backends](/dev-tools/backends/) for more ecosystems and details.

## Trusting config files {#trust}

When you or a teammate adds a `mise.toml` to a project, mise will prompt you to trust it before it runs any env directives or hooks:
When you or a teammate adds a `mise.toml` to a project, mise may prompt you to trust it before it runs env directives or hooks:

```
mise ~/my-project/mise.toml is not trusted. Trust it? [y/n]
Expand All @@ -324,9 +324,12 @@ This is a security measure — config files can execute arbitrary code via `[env
mise trust
```

This only needs to be done once per file. See [`mise trust`](/cli/trust) for more details.
In normal mode, `mise run`, naked task invocations such as `mise <TASK>`, `mise install`,
`mise exec`, and `mise watch` automatically trust the active config because those commands
explicitly execute project-defined behavior. Paranoid mode requires `mise trust` for all
non-global configs, including configs that are safe in normal mode.

To disable trust prompts entirely, trust the root path:
To disable trust prompts for a path, configure:

```sh
mise settings trusted_config_paths=["/"]
Expand All @@ -335,9 +338,11 @@ mise settings trusted_config_paths=["/"]
Or set the environment variable `MISE_TRUSTED_CONFIG_PATHS=/`.

::: tip
`mise use` automatically trusts the file it creates, so you'll only see this prompt when pulling a config someone else wrote or when editing `mise.toml` by hand.
`mise use` automatically trusts the file it creates.
:::

See [`mise trust`](/cli/trust) for more details.

## 5. Setting environment variables {#environment-variables}

Define environment variables in `mise.toml` — they'll be loaded whenever mise is activated or when using `mise exec`:
Expand Down
31 changes: 17 additions & 14 deletions docs/paranoid.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,29 @@ mise settings paranoid=1
## Config files

Normally `mise` will make sure some config files are "trusted" before loading
them. This will prompt you to confirm that you want to load the file, e.g.:
them. This can prompt you to confirm that you want to load the file, e.g.:

```sh
$ mise install
mise ~/src/mise/.tool-versions is not trusted. Trust it [y/n]?
$ mise env
mise ~/src/mise/mise.toml is not trusted. Trust it [y/n]?
```

In normal mode, mise checks trust before parsing `mise.toml` files because they
can contain behavior that executes code or affects the environment. Some
discovery paths that look at previously tracked configs may skip untrusted files
instead of prompting. Commands that directly need an untrusted config, such as
`mise lock`, can fail with an untrusted-config error when mise cannot prompt.
When mise detects that it is running in CI, configs are assumed to be trusted
unless paranoid mode is enabled.
In normal mode, `mise run`, naked task invocations such as `mise <TASK>`,
`mise install`, `mise exec`, and `mise watch` automatically trust their active
config because they explicitly execute project-defined behavior. Automatic shell
activation through `hook-env` does not.

Under paranoid, all config files must be trusted first, including formats that
normally do not require trust.
Other commands check trust before parsing `mise.toml` files because they can
contain behavior that executes code or affects the environment. Some discovery
paths that look at previously tracked configs may skip untrusted files instead
of prompting. Commands that directly need an untrusted config can fail with an
untrusted-config error when mise cannot prompt. When mise detects that it is
running in CI, configs are assumed to be trusted unless paranoid mode is enabled.

Also, in normal mode, a config file only needs to be trusted a single time.
In paranoid, the contents of the file are hashed to check if the file changes.
Under paranoid, all config files must be trusted first, including formats that
normally do not require trust. Automatic trust for execution commands is disabled.
In normal mode, a config file only needs to be trusted a single time. In paranoid,
the contents of the file are hashed to check if it changes.
If you change your config file, you'll need to trust it again.

Note that global and system config files (e.g., `~/.config/mise/config.toml`) are implicitly trusted and exempt from this check. This allows paranoid mode to be enabled in a global config without requiring a trust prompt for that file itself.
Expand Down
2 changes: 1 addition & 1 deletion docs/public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@
- [mise trust](https://mise.jdx.dev/cli/trust.html): Marks a config file as trusted
- [mise uninstall](https://mise.jdx.dev/cli/uninstall.html): Removes installed tool versions
- [mise unset](https://mise.jdx.dev/cli/unset.html): Remove environment variable(s) from the config file.
- [mise untrust](https://mise.jdx.dev/cli/untrust.html): No longer trust a config, will prompt in the future
- [mise untrust](https://mise.jdx.dev/cli/untrust.html): Remove explicit trust for a config
- [mise unuse](https://mise.jdx.dev/cli/unuse.html): Removes installed tool versions from mise.toml
- [mise upgrade](https://mise.jdx.dev/cli/upgrade.html): Upgrades outdated tools
- [mise use](https://mise.jdx.dev/cli/use.html): Installs a tool and adds the version to mise.toml.
Expand Down
11 changes: 6 additions & 5 deletions e2e/cli/test_hook_env_untrusted_once_per_dir
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,13 @@ if ! contains_trust_warning "$quiet_stderr"; then
fi
cd ../project

MISE_YES=0 mise run make 2>"$explicit_stderr" >/dev/null && {
echo "expected mise run to fail on untrusted config"
if ! MISE_YES=0 mise run make 2>"$explicit_stderr" >/dev/null; then
echo "expected explicit mise run to trust the active config"
cat "$explicit_stderr"
exit 1
}
if ! contains_trust_warning "$explicit_stderr"; then
echo "expected explicit mise run to keep reporting untrusted config"
fi
if contains_trust_warning "$explicit_stderr"; then
echo "expected explicit mise run not to report an untrusted config"
cat "$explicit_stderr"
exit 1
fi
3 changes: 2 additions & 1 deletion e2e/cli/test_prune_tracked_config_trust
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ mise -C tool-versions install
# Track a plain .tool-versions file, then make it require trust. Tracked-config
# loading must skip it without rendering the template.
echo "dummy 3.0.0" >templated/.tool-versions
mise -C templated install
mise install dummy@3.0.0
mise -C templated ls
cat <<EOF >templated/.tool-versions
dummy {{ exec(command="touch $marker") }}3.0.0
EOF
Expand Down
70 changes: 70 additions & 0 deletions e2e/config/test_non_paranoid_implicit_trust
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash

# Commands that execute project-defined behavior implicitly trust their active
# config in normal mode. hook-env does not, and paranoid mode always requires
# an explicit, content-bound trust decision.

export MISE_TRUSTED_CONFIG_PATHS=""
unset CI GITHUB_ACTIONS GITHUB_ACTION 2>/dev/null || true

mkdir -p install run exec ignored ci paranoid

cat <<'EOF' >install/mise.toml
[env]
IMPLICIT_TRUST = "install"
EOF

assert_not_contains "cd install && MISE_YES=0 mise hook-env -s bash 2>&1 || true" "IMPLICIT_TRUST=install"
assert "cd install && MISE_YES=0 mise install"
assert_contains "cd install && MISE_YES=0 mise hook-env -s bash" "IMPLICIT_TRUST"

cat <<'EOF' >run/mise.toml
[env]
IMPLICIT_TRUST = "run"

[tasks.hi]
run = "echo $IMPLICIT_TRUST"
EOF

assert_contains "cd run && MISE_YES=0 mise run hi" "run"
assert_contains "cd run && MISE_YES=0 mise trust --show" "trusted"
assert "cd run && mise untrust"

cat <<'EOF' >exec/mise.toml
[env]
IMPLICIT_TRUST = "exec"
EOF

assert_contains "cd exec && MISE_YES=0 mise exec -- sh -c 'echo \$IMPLICIT_TRUST'" "exec"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
assert_contains "cd exec && MISE_YES=0 mise trust --show" "trusted"
assert "cd exec && mise untrust"

cat <<'EOF' >ignored/mise.toml
[tools]
dummy = "1.0.0"
EOF

assert "mise -C ignored trust --ignore mise.toml"
assert "mise -C ignored install"
assert_contains "mise -C ignored trust --show mise.toml" "ignored"

cat <<'EOF' >ci/mise.toml
[env]
IMPLICIT_TRUST = "ci"
EOF

ci_state="$PWD/ci-state"
assert "CI=1 MISE_STATE_DIR='$ci_state' mise -C ci install"
assert_fail "find '$ci_state/trusted-configs' -mindepth 1 \( -type f -o -type l \) 2>/dev/null | grep -q ."

cat <<'EOF' >paranoid/mise.toml
[env]
IMPLICIT_TRUST = "paranoid"
EOF

set +e
output=$(cd paranoid && MISE_PARANOID=1 MISE_YES=0 mise install 2>&1)
status=$?
set -e
[[ $status -ne 0 ]] || fail "paranoid install unexpectedly trusted the config"
echo "$output" | grep -qi "trust" || fail "expected paranoid install to report an untrusted config, got: $output"
20 changes: 14 additions & 6 deletions e2e/config/test_trust_safe_config
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ run = "echo task-ran-without-trust"
EOF

# loads without prompting and without creating a trust marker
MISE_YES=0 mise install tiny
assert_contains "MISE_YES=0 mise ls tiny" "3.1.0"
assert_contains "MISE_YES=0 mise ls" "3.1.0"
assert_no_trust_marker "safe config should not be silently trusted"

# safe config tool pins still prompt before installing non-registry plugin URLs
Expand All @@ -46,9 +45,13 @@ set -e
[[ $status -ne 0 ]] || fail "expected community plugin install to abort without confirmation"
echo "$output" | grep -q "community-developed plugin" || fail "expected community plugin prompt, got: $output"
echo "$output" | grep -q "github.com/attacker/evil" || fail "expected attacker plugin URL, got: $output"
assert_no_trust_marker "community plugin prompt should not trust config"
# `mise install` trusts the active config independently of the later plugin
# confirmation. Remove that trust so the remaining checks start untrusted.
assert_contains "mise trust --show" "trusted"
mise untrust
assert_no_trust_marker "mise untrust should remove install's implicit trust"

# config tasks only execute on explicit `mise run`, so they don't need trust
# config tasks execute on explicit `mise run`, which now trusts active config
cat <<'EOF' >mise.toml
min_version = "2024.1.1"

Expand All @@ -59,8 +62,11 @@ tiny = "3.1.0"
run = "echo task-ran-without-trust"
EOF
assert_contains "MISE_YES=0 mise run hi" "task-ran-without-trust"
assert_contains "mise trust --show" "trusted"
mise untrust

# template-free file tasks are inert at load time and runnable without trust
# template-free file tasks are inert at load time; explicit `mise run` trusts
# the active config before running them
mkdir -p mise-tasks
cat <<'EOF' >mise-tasks/filetask
#!/usr/bin/env bash
Expand All @@ -69,7 +75,9 @@ echo file-task-ran-without-trust
EOF
chmod +x mise-tasks/filetask
assert_contains "MISE_YES=0 mise run filetask" "file-task-ran-without-trust"
assert_no_trust_marker "file task should not require or create trust"
assert_contains "mise trust --show" "trusted"
mise untrust
assert_no_trust_marker "mise untrust should remove run's implicit trust"

# a template in a file task header renders at load time, so it requires trust
cat <<'EOF' >mise-tasks/evil
Expand Down
4 changes: 2 additions & 2 deletions e2e/config/test_trust_safe_config_tracked
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ cat <<'EOF' >proj/mise.toml
tiny = "3.1.0"
EOF

# install from the safe config (loads + tracks it, no trust prompt/marker)
(cd proj && MISE_YES=0 mise install tiny)
# load the safe config so it is tracked, without creating a trust marker
(cd proj && MISE_YES=0 mise ls)

# from an unrelated directory, the tracked safe config's pin is still listed
cd other || exit 1
Expand Down
6 changes: 3 additions & 3 deletions e2e/tasks/test_task_untrusted_config_error
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ EOF

assert_contains "MISE_YES=0 mise run make" "hello from task"

# Unsafe configs (here: [env]) still require trust. Running a task from one
# should give a helpful error message:
# Paranoid mode requires trust for unsafe configs (here: [env]). Running a task
# from one should give a helpful error message:
# 1. Prompt the user to trust the config (when interactive), or
# 2. Show a clear "config not trusted" error (not "no tasks defined")
cat <<EOF >mise.toml
Expand All @@ -29,7 +29,7 @@ run = "echo 'hello from task'"
EOF

# This test verifies we don't get the misleading "no tasks defined" error
output=$(MISE_YES=0 mise run make 2>&1 || true)
output=$(MISE_PARANOID=1 MISE_YES=0 mise run make 2>&1 || true)

# The error should mention "trust" or "untrusted", not just "no tasks defined"
if echo "$output" | grep -q "no tasks defined.*Are you in a project directory"; then
Expand Down
Loading
Loading