diff --git a/src/config.rs b/src/config.rs index ef9ce96..98733bc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -21,7 +21,7 @@ pub fn build(args: Args, file_config: Option) -> Result, profile: &Options, globals: &Options, -) -> (OsString, Vec) { +) -> Result<(OsString, Vec), SandboxError> { let entrypoint = profile.entrypoint.clone().or(globals.entrypoint.clone()); let command = profile.command.clone().or(globals.command.clone()); @@ -131,22 +131,16 @@ fn resolve_command( args.extend(default_cmd.into_vec().into_iter().map(OsString::from)); } - return (cmd, args); + return Ok((cmd, args)); } if !passthrough_args.is_empty() { - return (passthrough_args.remove(0), passthrough_args); + return Ok((passthrough_args.remove(0), passthrough_args)); } if let Some(config_cmd) = command { - return config_cmd.into_binary_and_args(); + return Ok(config_cmd.into_binary_and_args()); } - if let Ok(cmd) = std::env::var("SANDBOX_CMD") { - return (OsString::from(cmd), vec![]); - } - ( - OsString::from("claude"), - vec![OsString::from("--dangerously-skip-permissions")], - ) + Err(SandboxError::NoCommand) } fn resolve_binary(name: &OsString) -> Option { @@ -712,7 +706,8 @@ mod tests { ..Options::default() }, &Options::default(), - ); + ) + .unwrap(); assert_eq!(cmd, "claude"); assert_eq!( args, @@ -741,7 +736,8 @@ mod tests { ..Options::default() }, &Options::default(), - ); + ) + .unwrap(); assert_eq!(cmd, "claude"); assert_eq!( args, @@ -764,7 +760,8 @@ mod tests { ..Options::default() }, &Options::default(), - ); + ) + .unwrap(); assert_eq!(cmd, "claude"); assert_eq!(args, vec![OsString::from("--dangerously-skip-permissions")]); } @@ -781,7 +778,8 @@ mod tests { entrypoint: Some(CommandValue::Simple("codex".into())), ..Options::default() }, - ); + ) + .unwrap(); assert_eq!(cmd, "claude"); } @@ -800,7 +798,8 @@ mod tests { entrypoint: Some(CommandValue::Simple("claude".into())), ..Options::default() }, - ); + ) + .unwrap(); assert_eq!(cmd, "claude"); assert_eq!( args, @@ -810,6 +809,12 @@ mod tests { .collect::>() ); } + #[test] + fn no_command_errors() { + let result = resolve_command(vec![], &Options::default(), &Options::default()); + assert!(matches!(result, Err(SandboxError::NoCommand))); + } + fn assert_paths(actual: &[PathBuf], expected: &[&str]) { let expected: Vec = expected.iter().map(PathBuf::from).collect(); assert_eq!(actual, &expected); diff --git a/src/errors.rs b/src/errors.rs index 19ed1bb..530255b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -25,6 +25,7 @@ pub enum SandboxError { UnknownConfigKey(String), ConfigPathNotAbsolute(PathBuf), InvalidBwrapArg(String), + NoCommand, } impl std::fmt::Display for SandboxError { @@ -69,6 +70,10 @@ impl std::fmt::Display for SandboxError { Self::InvalidBwrapArg(s) => { write!(f, "invalid quoting in --bwrap-arg: {s}") } + Self::NoCommand => write!( + f, + "no command to run; specify a command via config, entrypoint, or pass one after --" + ), } } }