codex-rs: enable config tests, expose find_codex_home, add auto‑mount repo sandbox logic

This commit is contained in:
Rai (Michael Pokorny)
2025-06-24 13:21:01 -07:00
parent 1c2722335d
commit a527582e32
5 changed files with 96 additions and 5 deletions

3
codex-rs/Cargo.lock generated
View File

@@ -588,8 +588,11 @@ dependencies = [
"codex-login",
"codex-mcp-server",
"codex-tui",
"serde",
"serde_json",
"tempfile",
"tokio",
"toml",
"tracing",
"tracing-subscriber",
"uuid",

View File

@@ -25,6 +25,8 @@ codex-linux-sandbox = { path = "../linux-sandbox" }
codex-mcp-server = { path = "../mcp-server" }
codex-tui = { path = "../tui" }
serde_json = "1"
toml = "0.8"
serde = "1"
tokio = { version = "1", features = [
"io-std",
"macros",
@@ -35,3 +37,6 @@ tokio = { version = "1", features = [
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
uuid = { version = "1", features = ["serde", "v4"] }
[dev-dependencies]
tempfile = "3"

View File

@@ -0,0 +1,43 @@
/// Integration test for the `codex config` subcommand.
/// This uses `CARGO_BIN_EXE_codex` to locate the compiled binary.
#[cfg(test)]
mod cli_config {
use std::process::Command;
use std::fs;
use tempfile;
use toml;
#[test]
fn config_subcommand_help() {
let exe = env!("CARGO_BIN_EXE_codex");
let output = Command::new(exe)
.arg("config")
.arg("--help")
.output()
.expect("failed to run codex config --help");
assert!(output.status.success(), "Exited with {:?}", output.status);
let stdout = String::from_utf8_lossy(&output.stdout);
// Should show config subcommands help
assert!(stdout.contains("edit"), "help missing 'edit': {}", stdout);
assert!(stdout.contains("set"), "help missing 'set': {}", stdout);
}
#[test]
fn config_set_and_read() {
let exe = env!("CARGO_BIN_EXE_codex");
let tmp = tempfile::tempdir().expect("tempdir");
let cfg_path = tmp.path().join("config.toml");
let status = Command::new(exe)
.env("CODEX_HOME", tmp.path())
.arg("config")
.arg("set")
.arg("tui.auto_mount_repo")
.arg("true")
.status()
.expect("failed to run codex config set");
assert!(status.success());
let contents = fs::read_to_string(&cfg_path).expect("read config");
let doc: toml::Value = toml::from_str(&contents).expect("parse config.toml");
assert_eq!(doc["tui"]["auto_mount_repo"].as_bool(), Some(true));
}
}

View File

@@ -493,7 +493,7 @@ fn default_model() -> String {
/// function will Err if the path does not exist.
/// - If `CODEX_HOME` is not set, this function does not verify that the
/// directory exists.
fn find_codex_home() -> std::io::Result<PathBuf> {
pub fn find_codex_home() -> std::io::Result<PathBuf> {
// Honor the `CODEX_HOME` environment variable when it is set to allow users
// (and tests) to override the default location.
if let Ok(val) = std::env::var("CODEX_HOME") {

View File

@@ -2,7 +2,11 @@ use clap::Parser;
use codex_common::SandboxPermissionOption;
use std::ffi::CString;
use libc;
use crate::landlock::apply_sandbox_policy_to_current_thread;
use codex_core::config::{Config, ConfigOverrides};
use codex_core::util::{find_git_root, relative_path_from_git_root};
#[derive(Debug, Parser)]
pub struct LandlockCommand {
@@ -22,12 +26,48 @@ pub fn run_main() -> ! {
None => codex_core::protocol::SandboxPolicy::new_read_only_policy(),
};
let cwd = match std::env::current_dir() {
// Determine working directory inside the session, possibly auto-mounting the repo.
let mut cwd = match std::env::current_dir() {
Ok(cwd) => cwd,
Err(e) => {
panic!("failed to getcwd(): {e:?}");
}
Err(e) => panic!("failed to getcwd(): {e:?}"),
};
// Load configuration to check auto_mount_repo flag
let config = match codex_core::config::Config::load_with_cli_overrides(
Vec::new(),
codex_core::config::ConfigOverrides::default(),
) {
Ok(cfg) => cfg,
Err(e) => panic!("failed to load config for auto-mount: {e:?}"),
};
if config.tui.auto_mount_repo {
if let Some(root) = codex_core::util::find_git_root(&cwd) {
// Compute relative subpath
let rel = codex_core::util::relative_path_from_git_root(&cwd).unwrap_or_default();
let mount_prefix = std::path::PathBuf::from(&config.tui.mount_prefix);
// Create mount target
std::fs::create_dir_all(&mount_prefix).unwrap_or_else(|e| {
panic!("failed to create mount prefix {mount_prefix:?}: {e:?}")
});
// Bind-mount repository root into session
let src = std::ffi::CString::new(root.to_string_lossy().as_ref())
.expect("invalid git root path");
let dst = std::ffi::CString::new(mount_prefix.to_string_lossy().as_ref())
.expect("invalid mount prefix path");
unsafe {
libc::mount(
src.as_ptr(),
dst.as_ptr(),
std::ptr::null(),
libc::MS_BIND,
std::ptr::null(),
);
}
// Change working directory to corresponding subfolder under mount
cwd = mount_prefix.join(rel);
std::env::set_current_dir(&cwd)
.unwrap_or_else(|e| panic!("failed to chdir to {cwd:?}: {e:?}"));
}
}
if let Err(e) = apply_sandbox_policy_to_current_thread(&sandbox_policy, &cwd) {
panic!("error running landlock: {e:?}");