Dead code cleanup (#4873)

Co-authored-by: Douwe Osinga <douwe@squareup.com>
Co-authored-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
Douwe Osinga
2025-09-29 05:23:30 -04:00
committed by GitHub
parent 4e1195954c
commit 426001e57f
-829
View File
@@ -1,7 +1,4 @@
use std::env;
use std::path::Path;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::state::AppState;
use axum::{extract::State, routing::post, Json, Router};
@@ -312,835 +309,9 @@ async fn remove_extension(
}
}
/// Registers the extension management routes with the Axum router.
pub fn routes(state: Arc<AppState>) -> Router {
Router::new()
.route("/extensions/add", post(add_extension))
.route("/extensions/remove", post(remove_extension))
.with_state(state)
}
/// Structure representing the allowed extensions from the YAML file
#[derive(Deserialize, Debug, Clone)]
struct AllowedExtensions {
#[allow(dead_code)]
extensions: Vec<ExtensionAllowlistEntry>,
}
/// Structure representing an individual extension entry in the allowlist
#[derive(Deserialize, Debug, Clone)]
struct ExtensionAllowlistEntry {
#[allow(dead_code)]
id: String,
#[allow(dead_code)]
command: String,
}
// Global cache for the allowed extensions
#[allow(dead_code)]
static ALLOWED_EXTENSIONS: OnceLock<Option<AllowedExtensions>> = OnceLock::new();
/// Fetches and parses the allowed extensions from the URL specified in GOOSE_ALLOWLIST env var
#[allow(dead_code)]
fn fetch_allowed_extensions() -> Option<AllowedExtensions> {
match env::var("GOOSE_ALLOWLIST") {
Err(_) => {
// Environment variable not set, no allowlist to enforce
None
}
Ok(url) => match reqwest::blocking::get(&url) {
Err(e) => {
eprintln!("Failed to fetch allowlist: {}", e);
None
}
Ok(response) if !response.status().is_success() => {
eprintln!("Failed to fetch allowlist, status: {}", response.status());
None
}
Ok(response) => match response.text() {
Err(e) => {
eprintln!("Failed to read allowlist response: {}", e);
None
}
Ok(text) => match serde_yaml::from_str::<AllowedExtensions>(&text) {
Ok(allowed) => Some(allowed),
Err(e) => {
eprintln!("Failed to parse allowlist YAML: {}", e);
None
}
},
},
},
}
}
/// Gets the cached allowed extensions or fetches them if not yet cached
#[allow(dead_code)]
fn get_allowed_extensions() -> &'static Option<AllowedExtensions> {
ALLOWED_EXTENSIONS.get_or_init(fetch_allowed_extensions)
}
/// Checks if a command is allowed based on the allowlist
#[allow(dead_code)]
fn is_command_allowed(cmd: &str, args: &[String]) -> bool {
// Check if bypass is enabled
if let Ok(bypass_value) = env::var("GOOSE_ALLOWLIST_BYPASS") {
if bypass_value.to_lowercase() == "true" {
// Bypass the allowlist check
println!("Allowlist check bypassed due to GOOSE_ALLOWLIST_BYPASS=true");
return true;
}
}
// Proceed with normal allowlist check
is_command_allowed_with_allowlist(&make_full_cmd(cmd, args), get_allowed_extensions())
}
fn make_full_cmd(cmd: &str, args: &[String]) -> String {
// trim each arg string to remove any leading/trailing whitespace
let args_trimmed = args.iter().map(|arg| arg.trim()).collect::<Vec<&str>>();
format!("{} {}", cmd.trim(), args_trimmed.join(" ").trim())
}
/// Normalizes a command name by removing common executable extensions (.exe, .cmd, .bat)
/// This makes the allowlist more portable across different operating systems
fn normalize_command_name(cmd: &str) -> String {
cmd.replace(".exe", "")
.replace(".cmd", "")
.replace(".bat", "")
.replace(" -y ", " ")
.replace(" -y", "")
.replace("-y ", "")
.to_string()
}
/// Implementation of command allowlist checking that takes an explicit allowlist parameter
/// This makes it easier to test without relying on global state
fn is_command_allowed_with_allowlist(
cmd: &str,
allowed_extensions: &Option<AllowedExtensions>,
) -> bool {
// Extract the first part of the command (before any spaces)
let first_part = cmd.split_whitespace().next().unwrap_or(cmd);
// Extract the base command name (last part of the path)
let cmd_base_with_ext = Path::new(first_part)
.file_name()
.and_then(|name| name.to_str())
.unwrap_or(first_part);
// Normalize the command name by removing extensions like .exe or .cmd
let cmd_base = normalize_command_name(cmd_base_with_ext);
// Special case: Always allow commands ending with "/goosed" or equal to "goosed"
// But still enforce that it's in the same directory as the current executable
if cmd_base == "goosed" {
// Only allow exact matches (no arguments)
if cmd == first_part {
// For absolute paths, check that it's in the same directory as the current executable
if (first_part.contains('/') || first_part.contains('\\'))
&& !first_part.starts_with("./")
{
let current_exe = std::env::current_exe().unwrap();
let current_exe_dir = current_exe.parent().unwrap();
let expected_path = current_exe_dir.join("goosed").to_str().unwrap().to_string();
// Normalize both paths before comparing
let normalized_cmd_path = normalize_command_name(first_part);
let normalized_expected_path = normalize_command_name(&expected_path);
if normalized_cmd_path == normalized_expected_path {
return true;
}
// If the path doesn't match, don't allow it
println!("goosed not in expected directory: {}", cmd);
println!("Expected path: {}", expected_path);
return false;
} else {
// For non-path goosed or relative paths, allow it
return true;
}
}
return false;
}
match allowed_extensions {
// No allowlist configured, allow all commands
None => true,
// Empty allowlist, allow all commands
Some(extensions) if extensions.extensions.is_empty() => true,
// Check against the allowlist
Some(extensions) => {
// Strip out the goose app resources/bin prefix if present (handle both macOS and Windows paths)
let mut cmd_to_check = cmd.to_string();
let mut is_goose_path = false;
// Check for macOS-style goose.app path
if cmd_to_check.contains("goose.app/Contents/Resources/bin/") {
if let Some(idx) = cmd_to_check.find("goose.app/Contents/Resources/bin/") {
cmd_to_check = cmd_to_check
[(idx + "goose.app/Contents/Resources/bin/".len())..]
.to_string();
is_goose_path = true;
}
}
// Check for Windows-style goose path with resources\bin
else if cmd_to_check.to_lowercase().contains("\\resources\\bin\\")
|| cmd_to_check.contains("/resources/bin/")
{
// Also handle forward slashes
if let Some(idx) = cmd_to_check
.to_lowercase()
.rfind("\\resources\\bin\\")
.or_else(|| cmd_to_check.rfind("/resources/bin/"))
{
let path_len = if cmd_to_check.contains("/resources/bin/") {
"/resources/bin/".len()
} else {
"\\resources\\bin\\".len()
};
cmd_to_check = cmd_to_check[(idx + path_len)..].to_string();
is_goose_path = true;
}
}
// Only check current directory for non-goose paths
if !is_goose_path {
// Check that the command exists as a peer command to current executable directory
// Only apply this check if the command includes a path separator
let current_exe = std::env::current_exe().unwrap();
let current_exe_dir = current_exe.parent().unwrap();
let expected_path = current_exe_dir
.join(&cmd_base)
.to_str()
.unwrap()
.to_string();
// Normalize both paths before comparing
let normalized_cmd_path = normalize_command_name(first_part);
if (first_part.contains('/') || first_part.contains('\\'))
&& normalized_cmd_path != expected_path
&& !cmd_to_check.contains("goose.app/Contents/Resources/bin/")
{
println!("Command not in expected directory: {}", cmd);
return false;
}
// Remove current_exe_dir + "/" from the cmd to clean it up
let path_to_trim = format!("{}/", current_exe_dir.to_str().unwrap());
cmd_to_check = cmd_to_check.replace(&path_to_trim, "");
}
println!("Command to check after path trimming: {}", cmd_to_check);
// Remove @version suffix from command parts, but preserve scoped npm packages
let parts: Vec<&str> = cmd_to_check.split_whitespace().collect();
let mut cleaned_parts: Vec<String> = Vec::new();
for part in parts {
if part.contains('@') && !part.starts_with('@') {
// This is likely a package with a version suffix, like "package@1.0.0"
// Keep only the part before the @ symbol
if let Some(base_part) = part.split('@').next() {
cleaned_parts.push(base_part.to_string());
} else {
cleaned_parts.push(part.to_string());
}
} else {
// Either no @ symbol or it's a scoped package (starts with @)
cleaned_parts.push(part.to_string());
}
}
// Reconstruct the command without version suffixes
cmd_to_check = cleaned_parts.join(" ");
println!("Command to check after @version removal: {}", cmd_to_check);
// Normalize the command before comparing with allowlist entries
let normalized_cmd = normalize_command_name(&cmd_to_check);
println!("Final normalized command: {}", normalized_cmd);
extensions.extensions.iter().any(|entry| {
let normalized_entry = normalize_command_name(&entry.command);
normalized_cmd == normalized_entry
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
#[test]
fn test_normalize_command_name() {
// Test removing .exe extension
assert_eq!(normalize_command_name("goosed.exe"), "goosed");
assert_eq!(
normalize_command_name("/path/to/goosed.exe"),
"/path/to/goosed"
);
// Test removing .cmd extension
assert_eq!(normalize_command_name("script.cmd"), "script");
assert_eq!(
normalize_command_name("/path/to/script.cmd"),
"/path/to/script"
);
assert_eq!(normalize_command_name("batch.bat"), "batch");
assert_eq!(normalize_command_name("npx -y thing"), "npx thing");
assert_eq!(
normalize_command_name("/path/to/batch.bat thing"),
"/path/to/batch thing"
);
// Test with no extension
assert_eq!(normalize_command_name("goosed"), "goosed");
assert_eq!(normalize_command_name("/path/to/goosed"), "/path/to/goosed");
}
// Create a test allowlist with the given commands
fn create_test_allowlist(commands: &[&str]) -> Option<AllowedExtensions> {
if commands.is_empty() {
return Some(AllowedExtensions { extensions: vec![] });
}
let entries = commands
.iter()
.enumerate()
.map(|(i, cmd)| ExtensionAllowlistEntry {
id: format!("test-{}", i),
command: cmd.to_string(),
})
.collect();
Some(AllowedExtensions {
extensions: entries,
})
}
#[test]
fn test_make_full() {
assert_eq!(
make_full_cmd("uvx", &["mcp_slack".to_string()]),
"uvx mcp_slack"
);
assert_eq!(
make_full_cmd("uvx", &["mcp_slack ".to_string()]),
"uvx mcp_slack"
);
assert_eq!(
make_full_cmd("uvx", &["mcp_slack".to_string(), "--verbose".to_string()]),
"uvx mcp_slack --verbose"
);
assert_eq!(
make_full_cmd("uvx", &["mcp_slack".to_string(), " --verbose".to_string()]),
"uvx mcp_slack --verbose"
);
}
#[test]
fn test_command_allowed_when_matching() {
let allowlist = create_test_allowlist(&[
"uvx something",
"uvx mcp_slack",
"npx mcp_github",
"npx -y @mic/mcp_mic",
"npx -y @mic/mcp_mic2@latest",
"npx @mic/mcp_mic3",
"npx @mic/mcp_mic4@latest",
"executor thing",
"minecraft",
]);
// Test with exact command matches
assert!(is_command_allowed_with_allowlist(
"uvx something",
&allowlist
));
// Test with exact command matches
assert!(is_command_allowed_with_allowlist("minecraft", &allowlist));
assert!(is_command_allowed_with_allowlist(
"uvx mcp_slack",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx mcp_github",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx -y mcp_github",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"executor thing",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"executor thing2",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"executor2 thing",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx -y @mic/mcp_mic",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx -y @mic/mcp_mic2@latest",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx -y @mic/mcp_mic3",
&allowlist
));
assert!(is_command_allowed_with_allowlist(
"npx -y @mic/mcp_mic4@latest",
&allowlist
));
// Get the current executable directory for reference
let current_exe = std::env::current_exe().unwrap();
let current_exe_dir = current_exe.parent().unwrap();
// Create a full path command that would be in the current executable directory
// For testing purposes, we'll use a direct path to the command in the allowlist
let full_path_cmd = current_exe_dir
.join("uvx my_mcp")
.to_str()
.unwrap()
.to_string();
// Create a test allowlist with the command name (without path)
let path_test_allowlist = create_test_allowlist(&["uvx my_mcp"]);
// This should be allowed because the path is correct and the base command matches
println!(
"Current executable directory: {}",
current_exe_dir.to_str().unwrap()
);
println!("Path test allowlist: {:?}", path_test_allowlist);
assert!(is_command_allowed_with_allowlist(
&full_path_cmd,
&path_test_allowlist
));
// Test with additional arguments - should NOT match because we require exact matches
assert!(!is_command_allowed_with_allowlist(
"uvx mcp_slack --verbose --flag=value",
&allowlist
));
// Test with a path that doesn't match the current directory - should fail
assert!(!is_command_allowed_with_allowlist(
"/Users/username/path/to/uvx mcp_slack",
&allowlist
));
// These should NOT match with exact matching
assert!(!is_command_allowed_with_allowlist(
"uvx other_command",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"prefix_npx mcp_github",
&allowlist
));
}
#[test]
fn test_command_allowed_simple() {
let allowlist = create_test_allowlist(&[
"uvx something",
"uvx mcp_slack",
"npx mcp_github",
"minecraft",
]);
// Test with version, anything @version can be stripped when matching
assert!(is_command_allowed_with_allowlist(
"npx -y mcp_github@latest",
&allowlist
));
}
#[test]
fn test_command_allowed_flexible() {
let allowlist = create_test_allowlist(&[
"uvx something",
"uvx mcp_slack",
"npx -y mcp_github",
"npx -y mcp_hammer start",
"minecraft",
]);
// Test with version, anything @version can be stripped when matching
assert!(is_command_allowed_with_allowlist(
"uvx something@1.0.13",
&allowlist
));
// Test with shim path - 'goose.app/Contents/Resources/bin/' and before can be stripped to get the command to match
assert!(is_command_allowed_with_allowlist(
"/private/var/folders/fq/rd_cb6/T/AppTranslocation/EA0195/d/goose.app/Contents/Resources/bin/uvx something",
&allowlist
));
// Test with shim path & latest version
assert!(is_command_allowed_with_allowlist(
"/private/var/folders/fq/rd_cb6/T/AppTranslocation/EA0195/d/goose.app/Contents/Resources/bin/uvx something@latest",
&allowlist
));
// Test with exact command matches
assert!(is_command_allowed_with_allowlist(
"uvx something",
&allowlist
));
// Test with -y added, it is allowed (ie doesn't matter if we see a -y in there)
assert!(is_command_allowed_with_allowlist(
"npx -y mcp_github@latest",
&allowlist
));
// Test with -y added, and a version and parameter, it is allowed (npx mcp_hammer start is allowed)
assert!(is_command_allowed_with_allowlist(
"npx -y mcp_hammer@latest start",
&allowlist
));
// Test with shim path & latest version
assert!(is_command_allowed_with_allowlist(
"/private/var/folders/fq/rd_cb6/T/AppTranslocation/EA0195/d/goose.app/Contents/Resources/bin/npx -y mcp_hammer@latest start",
&allowlist
));
}
#[test]
fn test_command_not_allowed_when_not_matching() {
let allowlist =
create_test_allowlist(&["uvx something", "uvx mcp_slack", "npx mcp_github"]);
// These should not be allowed
assert!(!is_command_allowed_with_allowlist(
"/Users/username/path/to/uvx_malicious",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"unauthorized_command",
&allowlist
));
assert!(!is_command_allowed_with_allowlist("/bin/bash", &allowlist));
assert!(!is_command_allowed_with_allowlist(
"uvx unauthorized",
&allowlist
));
}
#[test]
fn test_all_commands_allowed_when_no_allowlist() {
// Empty allowlist should allow all commands
let empty_allowlist = create_test_allowlist(&[]);
assert!(is_command_allowed_with_allowlist(
"any_command_should_be_allowed",
&empty_allowlist
));
// No allowlist should allow all commands
assert!(is_command_allowed_with_allowlist(
"any_command_should_be_allowed",
&None
));
}
#[test]
fn test_goosed_special_case() {
// Create a restrictive allowlist that doesn't include goosed
let allowlist = create_test_allowlist(&["uvx mcp_slack"]);
// Get the current executable directory for goosed path testing
let current_exe = std::env::current_exe().unwrap();
let current_exe_dir = current_exe.parent().unwrap();
let goosed_path = current_exe_dir.join("goosed").to_str().unwrap().to_string();
let goosed_exe_path = current_exe_dir
.join("goosed.exe")
.to_str()
.unwrap()
.to_string();
// This should be allowed because it's goosed in the correct directory
assert!(is_command_allowed_with_allowlist(&goosed_path, &allowlist));
// This should also be allowed because it's goosed.exe in the correct directory
assert!(is_command_allowed_with_allowlist(
&goosed_exe_path,
&allowlist
));
// These should NOT be allowed because they're in the wrong directory
assert!(!is_command_allowed_with_allowlist(
"/usr/local/bin/goosed",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"/Users/username/path/to/goosed",
&allowlist
));
// Commands with arguments should NOT be allowed - we require exact matches
assert!(!is_command_allowed_with_allowlist(
"/Users/username/path/to/goosed --flag value",
&allowlist
));
// Simple goosed without path should be allowed
assert!(is_command_allowed_with_allowlist("./goosed", &allowlist));
assert!(is_command_allowed_with_allowlist("goosed", &allowlist));
// These should NOT be allowed because they don't end with "/goosed"
assert!(!is_command_allowed_with_allowlist(
"/usr/local/bin/goosed-extra",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"/usr/local/bin/not-goosed",
&allowlist
));
assert!(!is_command_allowed_with_allowlist(
"goosed-extra",
&allowlist
));
}
#[test]
fn test_windows_paths() {
let allowlist = create_test_allowlist(&["uvx mcp_snowflake", "uvx mcp_test"]);
// Test various Windows path formats
let test_paths = vec![
// Standard Windows path
r"C:\Users\MaxNovich\Downloads\goose-1.0.17\resources\bin\uvx.exe",
// Path with different casing
r"C:\Users\MaxNovich\Downloads\goose-1.0.17\Resources\Bin\uvx.exe",
// Path with forward slashes
r"C:/Users/MaxNovich/Downloads/goose-1.0.17/resources/bin/uvx.exe",
// Path with spaces
r"C:\Program Files\goose 1.0.17\resources\bin\uvx.exe",
// Path with version numbers
r"C:\Users\MaxNovich\Downloads\goose-1.0.17-block.202504072238-76ffe-win32-x64\goose-1.0.17-block.202504072238-76ffe-win32-x64\resources\bin\uvx.exe",
];
for path in test_paths {
// Test with @latest version
let cmd = format!("{} mcp_snowflake@latest", path);
assert!(
is_command_allowed_with_allowlist(&cmd, &allowlist),
"Failed for path: {}",
path
);
// Test with specific version
let cmd_version = format!("{} mcp_test@1.2.3", path);
assert!(
is_command_allowed_with_allowlist(&cmd_version, &allowlist),
"Failed for path with version: {}",
path
);
}
// Test invalid paths that should be rejected
let invalid_paths = vec![
// Path without resources\bin
r"C:\Users\MaxNovich\Downloads\uvx.exe",
// Path with modified resources\bin
r"C:\Users\MaxNovich\Downloads\goose-1.0.17\resources_modified\bin\uvx.exe",
// Path with extra components
r"C:\Users\MaxNovich\Downloads\goose-1.0.17\resources\bin\extra\uvx.exe",
];
for path in invalid_paths {
let cmd = format!("{} mcp_snowflake@latest", path);
assert!(
!is_command_allowed_with_allowlist(&cmd, &allowlist),
"Should have rejected path: {}",
path
);
}
}
#[test]
fn test_windows_uvx_path() {
let allowlist = create_test_allowlist(&["uvx mcp_snowflake"]);
// Test Windows-style path with uvx.exe
let windows_path = r"C:\Users\MaxNovich\Downloads\goose-1.0.17-block.202504072238-76ffe-win32-x64\goose-1.0.17-block.202504072238-76ffe-win32-x64\resources\bin\uvx.exe";
let cmd = format!("{} mcp_snowflake@latest", windows_path);
// This should be allowed because it's a valid uvx command in the goose resources/bin directory
assert!(is_command_allowed_with_allowlist(&cmd, &allowlist));
// Test with different casing and backslashes
let windows_path_alt = r"c:\Users\MaxNovich\Downloads\goose-1.0.17-block.202504072238-76ffe-win32-x64\goose-1.0.17-block.202504072238-76ffe-win32-x64\Resources\Bin\uvx.exe";
let cmd_alt = format!("{} mcp_snowflake@latest", windows_path_alt);
assert!(is_command_allowed_with_allowlist(&cmd_alt, &allowlist));
}
#[test]
fn test_fetch_allowed_extensions_from_url() {
// Start a mock server - we need to use a blocking approach since fetch_allowed_extensions is blocking
let server = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let port = server.local_addr().unwrap().port();
let server_url = format!("http://127.0.0.1:{}", port);
let server_path = "/allowed_extensions.yaml";
// Define the mock response
let yaml_content = r#"extensions:
- id: slack
command: uvx mcp_slack
- id: github
command: uvx mcp_github
"#;
// Spawn a thread to handle the request
let handle = std::thread::spawn(move || {
let (stream, _) = server.accept().unwrap();
let mut buf_reader = std::io::BufReader::new(&stream);
let mut request_line = String::new();
std::io::BufRead::read_line(&mut buf_reader, &mut request_line).unwrap();
// Very simple HTTP response
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\nContent-Type: text/yaml\r\n\r\n{}",
yaml_content.len(),
yaml_content
);
let mut writer = std::io::BufWriter::new(&stream);
std::io::Write::write_all(&mut writer, response.as_bytes()).unwrap();
std::io::Write::flush(&mut writer).unwrap();
});
// Set the environment variable to point to our mock server
env::set_var("GOOSE_ALLOWLIST", format!("{}{}", server_url, server_path));
// Give the server a moment to start
std::thread::sleep(std::time::Duration::from_millis(100));
// Call the function that fetches from the URL
let allowed_extensions = fetch_allowed_extensions();
// Verify the result
assert!(allowed_extensions.is_some());
let extensions = allowed_extensions.unwrap();
assert_eq!(extensions.extensions.len(), 2);
assert_eq!(extensions.extensions[0].id, "slack");
assert_eq!(extensions.extensions[0].command, "uvx mcp_slack");
assert_eq!(extensions.extensions[1].id, "github");
assert_eq!(extensions.extensions[1].command, "uvx mcp_github");
// Clean up
env::remove_var("GOOSE_ALLOWLIST");
// Wait for the server thread to complete
handle.join().unwrap();
}
#[test]
fn test_allowlist_bypass() {
// We need to directly test is_command_allowed_with_allowlist with our test allowlist
// since get_allowed_extensions() might return None in the test environment
// Create a restrictive allowlist
let allowlist = create_test_allowlist(&["uvx mcp_slack"]);
// Command not in allowlist
let cmd = "uvx unauthorized_command";
// Without bypass, command should be denied with our test allowlist
assert!(!is_command_allowed_with_allowlist(cmd, &allowlist));
// Set the bypass environment variable
env::set_var("GOOSE_ALLOWLIST_BYPASS", "true");
// With bypass enabled, any command should be allowed regardless of allowlist
assert!(is_command_allowed(
"uvx",
&["unauthorized_command".to_string()]
));
// Test case insensitivity
env::set_var("GOOSE_ALLOWLIST_BYPASS", "TRUE");
assert!(is_command_allowed(
"uvx",
&["unauthorized_command".to_string()]
));
// Clean up
env::remove_var("GOOSE_ALLOWLIST_BYPASS");
// Create a mock function to test with allowlist and bypass
let test_with_allowlist_and_bypass = |bypass_value: &str, expected: bool| {
if bypass_value.is_empty() {
env::remove_var("GOOSE_ALLOWLIST_BYPASS");
} else {
env::set_var("GOOSE_ALLOWLIST_BYPASS", bypass_value);
}
// This is what we're testing - a direct call that simulates what happens in is_command_allowed
let result = if let Ok(bypass) = env::var("GOOSE_ALLOWLIST_BYPASS") {
if bypass.to_lowercase() == "true" {
true
} else {
is_command_allowed_with_allowlist(cmd, &allowlist)
}
} else {
is_command_allowed_with_allowlist(cmd, &allowlist)
};
assert_eq!(
result,
expected,
"With GOOSE_ALLOWLIST_BYPASS={}, expected allowed={}",
if bypass_value.is_empty() {
"not set"
} else {
bypass_value
},
expected
);
};
// Test various bypass values
test_with_allowlist_and_bypass("true", true);
test_with_allowlist_and_bypass("TRUE", true);
test_with_allowlist_and_bypass("True", true);
test_with_allowlist_and_bypass("false", false);
test_with_allowlist_and_bypass("0", false);
test_with_allowlist_and_bypass("", false);
// Final cleanup
env::remove_var("GOOSE_ALLOWLIST_BYPASS");
}
}