feat: add codex_linux_sandbox_exe: Option<PathBuf> field to Config (#1089)
https://github.com/openai/codex/pull/1086 is a work-in-progress to make Linux sandboxing work more like Seatbelt where, for the command we want to sandbox, we build up the command and then hand it, and some sandbox configuration flags, to another command to set up the sandbox and then run it. In the case of Seatbelt, macOS provides this helper binary and provides it at `/usr/bin/sandbox-exec`. For Linux, we have to build our own and pass it through (which is what #1086 does), so this makes the new `codex_linux_sandbox_exe` available on `Config` so that it will later be available in `exec.rs` when we need it in #1086.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use codex_cli::LandlockCommand;
|
use codex_cli::LandlockCommand;
|
||||||
use codex_cli::SeatbeltCommand;
|
use codex_cli::SeatbeltCommand;
|
||||||
@@ -66,17 +68,23 @@ struct ReplProto {}
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
let codex_linux_sandbox_exe: Option<PathBuf> = if cfg!(target_os = "linux") {
|
||||||
|
std::env::current_exe().ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let cli = MultitoolCli::parse();
|
let cli = MultitoolCli::parse();
|
||||||
|
|
||||||
match cli.subcommand {
|
match cli.subcommand {
|
||||||
None => {
|
None => {
|
||||||
codex_tui::run_main(cli.interactive)?;
|
codex_tui::run_main(cli.interactive, codex_linux_sandbox_exe)?;
|
||||||
}
|
}
|
||||||
Some(Subcommand::Exec(exec_cli)) => {
|
Some(Subcommand::Exec(exec_cli)) => {
|
||||||
codex_exec::run_main(exec_cli).await?;
|
codex_exec::run_main(exec_cli, codex_linux_sandbox_exe).await?;
|
||||||
}
|
}
|
||||||
Some(Subcommand::Mcp) => {
|
Some(Subcommand::Mcp) => {
|
||||||
codex_mcp_server::run_main().await?;
|
codex_mcp_server::run_main(codex_linux_sandbox_exe).await?;
|
||||||
}
|
}
|
||||||
Some(Subcommand::Proto(proto_cli)) => {
|
Some(Subcommand::Proto(proto_cli)) => {
|
||||||
proto::run_main(proto_cli).await?;
|
proto::run_main(proto_cli).await?;
|
||||||
|
|||||||
@@ -98,6 +98,14 @@ pub struct Config {
|
|||||||
|
|
||||||
/// Collection of settings that are specific to the TUI.
|
/// Collection of settings that are specific to the TUI.
|
||||||
pub tui: Tui,
|
pub tui: Tui,
|
||||||
|
|
||||||
|
/// Path to the `codex-linux-sandbox` executable. This must be set if
|
||||||
|
/// [`crate::exec::SandboxType::LinuxSeccomp`] is used. Note that this
|
||||||
|
/// cannot be set in the config file: it must be set in code via
|
||||||
|
/// [`ConfigOverrides`].
|
||||||
|
///
|
||||||
|
/// When this program is invoked, arg0 will be set to `codex-linux-sandbox`.
|
||||||
|
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Base config deserialized from ~/.codex/config.toml.
|
/// Base config deserialized from ~/.codex/config.toml.
|
||||||
@@ -222,6 +230,7 @@ pub struct ConfigOverrides {
|
|||||||
pub disable_response_storage: Option<bool>,
|
pub disable_response_storage: Option<bool>,
|
||||||
pub model_provider: Option<String>,
|
pub model_provider: Option<String>,
|
||||||
pub config_profile: Option<String>,
|
pub config_profile: Option<String>,
|
||||||
|
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -258,6 +267,7 @@ impl Config {
|
|||||||
disable_response_storage,
|
disable_response_storage,
|
||||||
model_provider,
|
model_provider,
|
||||||
config_profile: config_profile_key,
|
config_profile: config_profile_key,
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
} = overrides;
|
} = overrides;
|
||||||
|
|
||||||
let config_profile = match config_profile_key.or(cfg.profile) {
|
let config_profile = match config_profile_key.or(cfg.profile) {
|
||||||
@@ -359,6 +369,7 @@ impl Config {
|
|||||||
history,
|
history,
|
||||||
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
|
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
|
||||||
tui: cfg.tui.unwrap_or_default(),
|
tui: cfg.tui.unwrap_or_default(),
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
};
|
};
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
@@ -699,6 +710,7 @@ disable_response_storage = true
|
|||||||
history: History::default(),
|
history: History::default(),
|
||||||
file_opener: UriBasedFileOpener::VsCode,
|
file_opener: UriBasedFileOpener::VsCode,
|
||||||
tui: Tui::default(),
|
tui: Tui::default(),
|
||||||
|
codex_linux_sandbox_exe: None,
|
||||||
},
|
},
|
||||||
o3_profile_config
|
o3_profile_config
|
||||||
);
|
);
|
||||||
@@ -737,6 +749,7 @@ disable_response_storage = true
|
|||||||
history: History::default(),
|
history: History::default(),
|
||||||
file_opener: UriBasedFileOpener::VsCode,
|
file_opener: UriBasedFileOpener::VsCode,
|
||||||
tui: Tui::default(),
|
tui: Tui::default(),
|
||||||
|
codex_linux_sandbox_exe: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(expected_gpt3_profile_config, gpt3_profile_config);
|
assert_eq!(expected_gpt3_profile_config, gpt3_profile_config);
|
||||||
@@ -790,6 +803,7 @@ disable_response_storage = true
|
|||||||
history: History::default(),
|
history: History::default(),
|
||||||
file_opener: UriBasedFileOpener::VsCode,
|
file_opener: UriBasedFileOpener::VsCode,
|
||||||
tui: Tui::default(),
|
tui: Tui::default(),
|
||||||
|
codex_linux_sandbox_exe: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(expected_zdr_profile_config, zdr_profile_config);
|
assert_eq!(expected_zdr_profile_config, zdr_profile_config);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ mod event_processor;
|
|||||||
|
|
||||||
use std::io::IsTerminal;
|
use std::io::IsTerminal;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use cli::Cli;
|
pub use cli::Cli;
|
||||||
@@ -24,7 +25,7 @@ use tracing::error;
|
|||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
pub async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()> {
|
||||||
let Cli {
|
let Cli {
|
||||||
images,
|
images,
|
||||||
model,
|
model,
|
||||||
@@ -69,6 +70,7 @@ pub async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
|||||||
},
|
},
|
||||||
cwd: cwd.map(|p| p.canonicalize().unwrap_or(p)),
|
cwd: cwd.map(|p| p.canonicalize().unwrap_or(p)),
|
||||||
model_provider: None,
|
model_provider: None,
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
};
|
};
|
||||||
let config = Config::load_with_overrides(overrides)?;
|
let config = Config::load_with_overrides(overrides)?;
|
||||||
// Print the effective configuration so users can see what Codex is using.
|
// Print the effective configuration so users can see what Codex is using.
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use codex_exec::Cli;
|
use codex_exec::Cli;
|
||||||
use codex_exec::run_main;
|
use codex_exec::run_main;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
let codex_linux_sandbox_exe: Option<PathBuf> = if cfg!(target_os = "linux") {
|
||||||
|
std::env::current_exe().ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
run_main(cli).await?;
|
run_main(cli, codex_linux_sandbox_exe).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,10 @@ pub(crate) fn create_tool_for_codex_tool_call_param() -> Tool {
|
|||||||
impl CodexToolCallParam {
|
impl CodexToolCallParam {
|
||||||
/// Returns the initial user prompt to start the Codex conversation and the
|
/// Returns the initial user prompt to start the Codex conversation and the
|
||||||
/// Config.
|
/// Config.
|
||||||
pub fn into_config(self) -> std::io::Result<(String, codex_core::config::Config)> {
|
pub fn into_config(
|
||||||
|
self,
|
||||||
|
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
|
) -> std::io::Result<(String, codex_core::config::Config)> {
|
||||||
let Self {
|
let Self {
|
||||||
prompt,
|
prompt,
|
||||||
model,
|
model,
|
||||||
@@ -167,6 +170,7 @@ impl CodexToolCallParam {
|
|||||||
sandbox_policy,
|
sandbox_policy,
|
||||||
disable_response_storage,
|
disable_response_storage,
|
||||||
model_provider: None,
|
model_provider: None,
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cfg = codex_core::config::Config::load_with_overrides(overrides)?;
|
let cfg = codex_core::config::Config::load_with_overrides(overrides)?;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#![deny(clippy::print_stdout, clippy::print_stderr)]
|
#![deny(clippy::print_stdout, clippy::print_stderr)]
|
||||||
|
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use mcp_types::JSONRPCMessage;
|
use mcp_types::JSONRPCMessage;
|
||||||
use tokio::io::AsyncBufReadExt;
|
use tokio::io::AsyncBufReadExt;
|
||||||
@@ -24,7 +25,7 @@ use crate::message_processor::MessageProcessor;
|
|||||||
/// plenty for an interactive CLI.
|
/// plenty for an interactive CLI.
|
||||||
const CHANNEL_CAPACITY: usize = 128;
|
const CHANNEL_CAPACITY: usize = 128;
|
||||||
|
|
||||||
pub async fn run_main() -> IoResult<()> {
|
pub async fn run_main(codex_linux_sandbox_exe: Option<PathBuf>) -> IoResult<()> {
|
||||||
// Install a simple subscriber so `tracing` output is visible. Users can
|
// Install a simple subscriber so `tracing` output is visible. Users can
|
||||||
// control the log level with `RUST_LOG`.
|
// control the log level with `RUST_LOG`.
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
@@ -61,7 +62,7 @@ pub async fn run_main() -> IoResult<()> {
|
|||||||
|
|
||||||
// Task: process incoming messages.
|
// Task: process incoming messages.
|
||||||
let processor_handle = tokio::spawn({
|
let processor_handle = tokio::spawn({
|
||||||
let mut processor = MessageProcessor::new(outgoing_tx.clone());
|
let mut processor = MessageProcessor::new(outgoing_tx.clone(), codex_linux_sandbox_exe);
|
||||||
async move {
|
async move {
|
||||||
while let Some(msg) = incoming_rx.recv().await {
|
while let Some(msg) = incoming_rx.recv().await {
|
||||||
match msg {
|
match msg {
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use codex_mcp_server::run_main;
|
use codex_mcp_server::run_main;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
run_main().await?;
|
let codex_linux_sandbox_exe: Option<PathBuf> = if cfg!(target_os = "linux") {
|
||||||
|
std::env::current_exe().ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
run_main(codex_linux_sandbox_exe).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::codex_tool_config::CodexToolCallParam;
|
use crate::codex_tool_config::CodexToolCallParam;
|
||||||
use crate::codex_tool_config::create_tool_for_codex_tool_call_param;
|
use crate::codex_tool_config::create_tool_for_codex_tool_call_param;
|
||||||
|
|
||||||
@@ -28,15 +30,20 @@ use tokio::task;
|
|||||||
pub(crate) struct MessageProcessor {
|
pub(crate) struct MessageProcessor {
|
||||||
outgoing: mpsc::Sender<JSONRPCMessage>,
|
outgoing: mpsc::Sender<JSONRPCMessage>,
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
|
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageProcessor {
|
impl MessageProcessor {
|
||||||
/// Create a new `MessageProcessor`, retaining a handle to the outgoing
|
/// Create a new `MessageProcessor`, retaining a handle to the outgoing
|
||||||
/// `Sender` so handlers can enqueue messages to be written to stdout.
|
/// `Sender` so handlers can enqueue messages to be written to stdout.
|
||||||
pub(crate) fn new(outgoing: mpsc::Sender<JSONRPCMessage>) -> Self {
|
pub(crate) fn new(
|
||||||
|
outgoing: mpsc::Sender<JSONRPCMessage>,
|
||||||
|
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
outgoing,
|
outgoing,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +346,7 @@ impl MessageProcessor {
|
|||||||
|
|
||||||
let (initial_prompt, config): (String, CodexConfig) = match arguments {
|
let (initial_prompt, config): (String, CodexConfig) = match arguments {
|
||||||
Some(json_val) => match serde_json::from_value::<CodexToolCallParam>(json_val) {
|
Some(json_val) => match serde_json::from_value::<CodexToolCallParam>(json_val) {
|
||||||
Ok(tool_cfg) => match tool_cfg.into_config() {
|
Ok(tool_cfg) => match tool_cfg.into_config(self.codex_linux_sandbox_exe.clone()) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let result = CallToolResult {
|
let result = CallToolResult {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use codex_core::protocol::SandboxPolicy;
|
|||||||
use codex_core::util::is_inside_git_repo;
|
use codex_core::util::is_inside_git_repo;
|
||||||
use log_layer::TuiLogLayer;
|
use log_layer::TuiLogLayer;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
|
use std::path::PathBuf;
|
||||||
use tracing_appender::non_blocking;
|
use tracing_appender::non_blocking;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
@@ -36,7 +37,7 @@ mod user_approval_widget;
|
|||||||
|
|
||||||
pub use cli::Cli;
|
pub use cli::Cli;
|
||||||
|
|
||||||
pub fn run_main(cli: Cli) -> std::io::Result<()> {
|
pub fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> std::io::Result<()> {
|
||||||
let (sandbox_policy, approval_policy) = if cli.full_auto {
|
let (sandbox_policy, approval_policy) = if cli.full_auto {
|
||||||
(
|
(
|
||||||
Some(SandboxPolicy::new_full_auto_policy()),
|
Some(SandboxPolicy::new_full_auto_policy()),
|
||||||
@@ -61,6 +62,7 @@ pub fn run_main(cli: Cli) -> std::io::Result<()> {
|
|||||||
cwd: cli.cwd.clone().map(|p| p.canonicalize().unwrap_or(p)),
|
cwd: cli.cwd.clone().map(|p| p.canonicalize().unwrap_or(p)),
|
||||||
model_provider: None,
|
model_provider: None,
|
||||||
config_profile: cli.config_profile.clone(),
|
config_profile: cli.config_profile.clone(),
|
||||||
|
codex_linux_sandbox_exe,
|
||||||
};
|
};
|
||||||
#[allow(clippy::print_stderr)]
|
#[allow(clippy::print_stderr)]
|
||||||
match Config::load_with_overrides(overrides) {
|
match Config::load_with_overrides(overrides) {
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use codex_tui::Cli;
|
use codex_tui::Cli;
|
||||||
use codex_tui::run_main;
|
use codex_tui::run_main;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
|
let codex_linux_sandbox_exe: Option<PathBuf> = if cfg!(target_os = "linux") {
|
||||||
|
std::env::current_exe().ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
run_main(cli)?;
|
run_main(cli, codex_linux_sandbox_exe)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user