mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
## Why A model-provided shell path should select the requested shell type without allowing that path to determine which executable Codex runs. ## What changed - Resolve model-provided shells through Codex's normal shell discovery and fallback logic after detecting their type. - Keep the configured packaged zsh executable when the zsh-fork feature is enabled and the file exists. - Update shell, unified exec, and network approval expectations to use the resolved local executable and arguments. GitOrigin-RevId: ebe6f7eec2cfd1c0548d5bf1a26b7a30dba02cc2
105 lines
3.2 KiB
Rust
105 lines
3.2 KiB
Rust
use codex_exec_server::ShellInfo;
|
|
use codex_shell_command::shell_detect::DetectedShell;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::path::PathBuf;
|
|
|
|
pub use codex_shell_command::shell_detect::ShellType;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Shell {
|
|
pub(crate) shell_type: ShellType,
|
|
pub(crate) shell_path: PathBuf,
|
|
}
|
|
|
|
impl Shell {
|
|
pub fn name(&self) -> &'static str {
|
|
self.shell_type.name()
|
|
}
|
|
|
|
/// Takes a string of shell and returns the full list of command args to
|
|
/// use with `exec()` to run the shell command.
|
|
pub fn derive_exec_args(&self, command: &str, use_login_shell: bool) -> Vec<String> {
|
|
match self.shell_type {
|
|
ShellType::Zsh | ShellType::Bash | ShellType::Sh => {
|
|
let arg = if use_login_shell { "-lc" } else { "-c" };
|
|
vec![
|
|
self.shell_path.to_string_lossy().to_string(),
|
|
arg.to_string(),
|
|
command.to_string(),
|
|
]
|
|
}
|
|
ShellType::PowerShell => {
|
|
let mut args = vec![self.shell_path.to_string_lossy().to_string()];
|
|
if !use_login_shell {
|
|
args.push("-NoProfile".to_string());
|
|
}
|
|
|
|
args.push("-Command".to_string());
|
|
args.push(command.to_string());
|
|
args
|
|
}
|
|
ShellType::Cmd => {
|
|
let mut args = vec![self.shell_path.to_string_lossy().to_string()];
|
|
args.push("/c".to_string());
|
|
args.push(command.to_string());
|
|
args
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<DetectedShell> for Shell {
|
|
fn from(detected: DetectedShell) -> Self {
|
|
Self {
|
|
shell_type: detected.shell_type,
|
|
shell_path: detected.shell_path,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Shell {
|
|
pub(crate) fn from_environment_shell_info(shell_info: ShellInfo) -> anyhow::Result<Self> {
|
|
let shell_type = match shell_info.name.as_str() {
|
|
"zsh" => ShellType::Zsh,
|
|
"bash" => ShellType::Bash,
|
|
"powershell" => ShellType::PowerShell,
|
|
"sh" => ShellType::Sh,
|
|
"cmd" => ShellType::Cmd,
|
|
name => anyhow::bail!("unknown environment shell `{name}`"),
|
|
};
|
|
|
|
Ok(Self {
|
|
shell_type,
|
|
shell_path: PathBuf::from(shell_info.path),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(all(test, unix))]
|
|
fn ultimate_fallback_shell() -> Shell {
|
|
codex_shell_command::shell_detect::ultimate_fallback_shell().into()
|
|
}
|
|
|
|
pub fn get_shell_by_model_provided_path(shell_path: &PathBuf) -> Shell {
|
|
codex_shell_command::shell_detect::get_shell_by_model_provided_path(shell_path).into()
|
|
}
|
|
|
|
pub fn get_shell(shell_type: ShellType) -> Option<Shell> {
|
|
codex_shell_command::shell_detect::get_shell(shell_type).map(Into::into)
|
|
}
|
|
|
|
pub fn default_user_shell() -> Shell {
|
|
codex_shell_command::shell_detect::default_user_shell().into()
|
|
}
|
|
|
|
#[cfg(all(test, target_os = "macos"))]
|
|
fn default_user_shell_from_path(user_shell_path: Option<PathBuf>) -> Shell {
|
|
codex_shell_command::shell_detect::default_user_shell_from_path(user_shell_path).into()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[cfg(unix)]
|
|
#[path = "shell_tests.rs"]
|
|
mod tests;
|