diff --git a/e2e/config/test_local_settings_trust_controls b/e2e/config/test_local_settings_trust_controls new file mode 100644 index 0000000000..c221a8072a --- /dev/null +++ b/e2e/config/test_local_settings_trust_controls @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +export MISE_TRUSTED_CONFIG_PATHS="" + +marker="$MISE_TMP_DIR/local-settings-trust-controls" + +cat >poc.sh < "$marker" +EOF + +cat >.mise.toml <&1) +status=$? +set -e + +if [[ $status -eq 0 ]]; then + echo "FAIL: expected hook-env to reject untrusted local config" + echo "Output: $output" + exit 1 +fi + +if [[ -f $marker ]]; then + echo "FAIL: local trust-control settings allowed untrusted env source execution" + echo "Output: $output" + exit 1 +fi + +if ! echo "$output" | grep -qi "not trusted"; then + echo "FAIL: expected untrusted config error, got: $output" + exit 1 +fi diff --git a/settings.toml b/settings.toml index e1066c9bf0..a0c73b0f8a 100644 --- a/settings.toml +++ b/settings.toml @@ -351,6 +351,7 @@ default = "false" description = "Set to true if running in a CI environment" deserialize_with = "bool_string" env = "CI" +global_only = true hide = true type = "Bool" @@ -1781,6 +1782,7 @@ docs = """ Enables extra-secure behavior. See [Paranoid](/paranoid.html). """ env = "MISE_PARANOID" +global_only = true type = "Bool" [pin] @@ -2629,6 +2631,7 @@ Set to `["/"]` to trust all config files, effectively disabling the trust mechan Paths are separated by the OS path separator when using the environment variable \ (`:` on Unix, `;` on Windows).""" env = "MISE_TRUSTED_CONFIG_PATHS" +global_only = true parse_env = "list_by_os_path_separator" rust_type = "BTreeSet" type = "ListPath" @@ -2753,6 +2756,7 @@ type = "String" [yes] description = "This will automatically answer yes or no to prompts. This is useful for scripting." env = "MISE_YES" +global_only = true type = "Bool" [zig.use_community_mirrors] diff --git a/src/config/settings.rs b/src/config/settings.rs index d9133faebd..163867b086 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1098,6 +1098,57 @@ mod tests { ); } + #[test] + fn test_parse_settings_file_strips_non_global_trust_controls() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join(".mise.toml"); + std::fs::write( + &path, + r#" + [settings] + ci = "true" + paranoid = true + trusted_config_paths = ["/"] + yes = true + "#, + ) + .unwrap(); + + let partial = Settings::parse_settings_file(&path).unwrap(); + + assert_eq!(partial.ci, None); + assert_eq!(partial.paranoid, None); + assert_eq!(partial.trusted_config_paths, None); + assert_eq!(partial.yes, None); + } + + #[test] + fn test_global_config_preserves_trust_controls() { + let path = Path::new("/tmp/global-config.toml"); + let mut settings = toml::from_str::( + r#" + ci = "true" + paranoid = true + trusted_config_paths = ["/"] + yes = true + "#, + ) + .unwrap() + .as_table() + .unwrap() + .clone(); + strip_local_only_settings(&mut settings, path, true); + let partial = settings_partial_from_table(settings); + + assert_eq!(partial.ci, Some(true)); + assert_eq!(partial.paranoid, Some(true)); + assert_eq!( + partial.trusted_config_paths, + Some([PathBuf::from("/")].into_iter().collect()) + ); + assert_eq!(partial.yes, Some(true)); + } + #[test] fn test_set_by_comma_empty_string() { let result: Result, _> = set_by_comma("");