Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 13 additions & 0 deletions docs/sandboxing.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ mise x --deny-all --allow-read=. --allow-write=./dist --allow-net=registry.npmjs

These flags work with both `mise exec` (`mise x`) and `mise run`.

## Default Restrictions

Sandbox deny rules can be enabled for every `mise exec` and `mise run` invocation with settings:

```toml
[settings.sandbox]
deny_all = true
```

The available settings mirror the deny flags: `deny_all`, `deny_read`, `deny_write`, `deny_net`,
and `deny_env`. Tasks and CLI flags can still add `allow_read`, `allow_write`, `allow_net`, or
`allow_env` exceptions as needed.

## Task Sandboxing

Tasks defined in `mise.toml` can declare sandbox permissions:
Expand Down
19 changes: 19 additions & 0 deletions e2e/cli/test_sandbox_settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

export SANDBOX_SETTING_SECRET=hidden

cat <<'EOF' >mise.toml
[settings.sandbox]
deny_env = true

[tasks.hidden]
run = 'printf "%s" "${SANDBOX_SETTING_SECRET-unset}"'

[tasks.allowed]
run = 'printf "%s" "$SANDBOX_SETTING_SECRET"'
allow_env = ["SANDBOX_SETTING_SECRET"]
EOF

assert "mise exec -- sh -c 'printf \"%s\" \"\${SANDBOX_SETTING_SECRET-unset}\"'" "unset"
assert "mise run hidden" "unset"
assert "mise run allowed" "hidden"
Comment thread
risu729 marked this conversation as resolved.
Resolved
31 changes: 31 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,37 @@
}
}
},
"sandbox": {
"type": "object",
"unevaluatedProperties": false,
"properties": {
"deny_all": {
"default": false,
"description": "Deny filesystem reads and writes, network access, and environment variable inheritance by default for `mise run` and `mise exec`.",
"type": "boolean"
},
"deny_env": {
"default": false,
"description": "Deny environment variable inheritance by default for `mise run` and `mise exec`.",
"type": "boolean"
},
"deny_net": {
"default": false,
"description": "Deny network access by default for `mise run` and `mise exec`.",
"type": "boolean"
},
"deny_read": {
"default": false,
"description": "Deny filesystem reads by default for `mise run` and `mise exec`.",
"type": "boolean"
},
"deny_write": {
"default": false,
"description": "Deny filesystem writes by default for `mise run` and `mise exec`.",
"type": "boolean"
}
}
},
"shared_install_dirs": {
"description": "Additional read-only directories to search for installed tool versions.",
"type": "array",
Expand Down
30 changes: 30 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2180,6 +2180,36 @@ env = "MISE_RUSTUP_HOME"
optional = true
type = "Path"

[sandbox.deny_all]
default = false
description = "Deny filesystem reads and writes, network access, and environment variable inheritance by default for `mise run` and `mise exec`."
env = "MISE_SANDBOX_DENY_ALL"
type = "Bool"

[sandbox.deny_env]
default = false
description = "Deny environment variable inheritance by default for `mise run` and `mise exec`."
env = "MISE_SANDBOX_DENY_ENV"
type = "Bool"

[sandbox.deny_net]
default = false
description = "Deny network access by default for `mise run` and `mise exec`."
env = "MISE_SANDBOX_DENY_NET"
type = "Bool"

[sandbox.deny_read]
default = false
description = "Deny filesystem reads by default for `mise run` and `mise exec`."
env = "MISE_SANDBOX_DENY_READ"
type = "Bool"

[sandbox.deny_write]
default = false
description = "Deny filesystem writes by default for `mise run` and `mise exec`."
env = "MISE_SANDBOX_DENY_WRITE"
type = "Bool"

[shared_install_dirs]
description = "Additional read-only directories to search for installed tool versions."
docs = """
Expand Down
23 changes: 18 additions & 5 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,25 @@ impl Exec {
args.insert(0, "-C".into());
}

// Build sandbox config from CLI flags.
// Build sandbox config from settings and CLI flags.
let sandbox_settings = &Settings::get().sandbox;
let mut sandbox = SandboxConfig {
deny_read: self.deny_all || self.deny_read,
deny_write: self.deny_all || self.deny_write,
deny_net: self.deny_all || self.deny_net,
deny_env: self.deny_all || self.deny_env,
deny_read: sandbox_settings.deny_all
|| sandbox_settings.deny_read
|| self.deny_all
|| self.deny_read,
deny_write: sandbox_settings.deny_all
|| sandbox_settings.deny_write
|| self.deny_all
|| self.deny_write,
deny_net: sandbox_settings.deny_all
|| sandbox_settings.deny_net
|| self.deny_all
|| self.deny_net,
deny_env: sandbox_settings.deny_all
|| sandbox_settings.deny_env
|| self.deny_all
|| self.deny_env,
allow_read: self.allow_read,
allow_write: self.allow_write,
allow_net: self.allow_net,
Expand Down
22 changes: 18 additions & 4 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,8 @@ impl Run {

/// Create TaskExecutor after tool installation to ensure caches are populated
fn setup_executor(&mut self) -> Result<()> {
let settings = Settings::get();
let sandbox_settings = &settings.sandbox;
let executor_config = crate::task::task_executor::TaskExecutorConfig {
force: self.force,
cd: self.cd.clone(),
Expand All @@ -723,10 +725,22 @@ impl Run {
dry_run: self.dry_run,
skip_deps: self.skip_deps,
sandbox: crate::sandbox::SandboxConfig {
deny_read: self.deny_all || self.deny_read,
deny_write: self.deny_all || self.deny_write,
deny_net: self.deny_all || self.deny_net,
deny_env: self.deny_all || self.deny_env,
deny_read: sandbox_settings.deny_all
|| sandbox_settings.deny_read
|| self.deny_all
|| self.deny_read,
deny_write: sandbox_settings.deny_all
|| sandbox_settings.deny_write
|| self.deny_all
|| self.deny_write,
deny_net: sandbox_settings.deny_all
|| sandbox_settings.deny_net
|| self.deny_all
|| self.deny_net,
deny_env: sandbox_settings.deny_all
|| sandbox_settings.deny_env
|| self.deny_all
|| self.deny_env,
allow_read: self.allow_read.clone(),
allow_write: self.allow_write.clone(),
allow_net: self.allow_net.clone(),
Expand Down
Loading