diff --git a/server/src/shell.rs b/server/src/shell.rs index 27aa9725..7309eda3 100644 --- a/server/src/shell.rs +++ b/server/src/shell.rs @@ -8,9 +8,9 @@ pub struct ShellConfig { } impl ShellConfig { - /// Build from the environment. Shell running is enabled only when - /// `SB_SHELL_BACKEND` is unset AND the space is not read-only; - /// `SB_SHELL_WHITELIST` is a space-separated allow-list. + /// Build from the environment. `SB_SHELL_BACKEND` defaults to `local` + /// (enabled); any other value disables shell running. `SB_SHELL_WHITELIST` + /// is a space-separated allow-list. pub fn from_env(read_only: bool) -> Self { let backend = std::env::var("SB_SHELL_BACKEND") .ok() @@ -19,9 +19,15 @@ impl ShellConfig { Self::parse(backend.as_deref(), whitelist.as_deref(), read_only) } - /// Pure parser used by `from_env` and tests. + /// Pure parser used by `from_env` and tests. Shell running is enabled only + /// for the `local` backend (the default when unset, matched + /// case-insensitively); any other value fails safe to disabled, and + /// read-only always disables. pub fn parse(backend: Option<&str>, whitelist: Option<&str>, read_only: bool) -> Self { - let enabled = backend.is_none() && !read_only; + let backend_enables = backend + .map(|b| b.trim().eq_ignore_ascii_case("local")) + .unwrap_or(true); + let enabled = !read_only && backend_enables; let whitelist = whitelist .map(|w| w.split_whitespace().map(|s| s.to_string()).collect()) .unwrap_or_default(); @@ -67,10 +73,19 @@ mod tests { } #[test] - fn from_env_parse_disabled_when_backend_set() { - // SB_SHELL_BACKEND set (to anything) ⇒ disabled. - let c = ShellConfig::parse(Some("off"), Some("git npm"), false); - assert!(!c.enabled); + fn from_env_parse_disabled_for_non_local_backend() { + // Anything other than `local` fails safe to disabled. + assert!(!ShellConfig::parse(Some("off"), Some("git npm"), false).enabled); + assert!(!ShellConfig::parse(Some("noop"), None, false).enabled); + assert!(!ShellConfig::parse(Some("disabled"), None, false).enabled); + } + + #[test] + fn from_env_parse_enabled_for_local_backend() { + // Regression for #2058: `SB_SHELL_BACKEND=local` must enable the shell; + // matching is case-insensitive and trimmed. + assert!(ShellConfig::parse(Some("local"), None, false).enabled); + assert!(ShellConfig::parse(Some(" LOCAL "), None, false).enabled); } #[test]