Skip to content

Commit d39d29f

Browse files
committed
fix: introduce AbsolutePathBuf as part of sandbox config
1 parent 3fc8b28 commit d39d29f

File tree

32 files changed

+256
-104
lines changed

32 files changed

+256
-104
lines changed

codex-rs/Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/app-server-protocol/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ workspace = true
1515
anyhow = { workspace = true }
1616
clap = { workspace = true, features = ["derive"] }
1717
codex-protocol = { workspace = true }
18+
codex-utils-absolute-path = { workspace = true }
1819
mcp-types = { workspace = true }
1920
schemars = { workspace = true }
2021
serde = { workspace = true, features = ["derive"] }

codex-rs/app-server-protocol/src/protocol/v1.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use codex_protocol::protocol::ReviewDecision;
1616
use codex_protocol::protocol::SandboxPolicy;
1717
use codex_protocol::protocol::SessionSource;
1818
use codex_protocol::protocol::TurnAbortReason;
19+
use codex_utils_absolute_path::AbsolutePathBuf;
1920
use schemars::JsonSchema;
2021
use serde::Deserialize;
2122
use serde::Serialize;
@@ -359,7 +360,7 @@ pub struct Tools {
359360
#[serde(rename_all = "camelCase")]
360361
pub struct SandboxSettings {
361362
#[serde(default)]
362-
pub writable_roots: Vec<PathBuf>,
363+
pub writable_roots: Vec<AbsolutePathBuf>,
363364
pub network_access: Option<bool>,
364365
pub exclude_tmpdir_env_var: Option<bool>,
365366
pub exclude_slash_tmp: Option<bool>,

codex-rs/app-server-protocol/src/protocol/v2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use codex_protocol::protocol::SessionSource as CoreSessionSource;
2424
use codex_protocol::protocol::TokenUsage as CoreTokenUsage;
2525
use codex_protocol::protocol::TokenUsageInfo as CoreTokenUsageInfo;
2626
use codex_protocol::user_input::UserInput as CoreUserInput;
27+
use codex_utils_absolute_path::AbsolutePathBuf;
2728
use mcp_types::ContentBlock as McpContentBlock;
2829
use mcp_types::Resource as McpResource;
2930
use mcp_types::ResourceTemplate as McpResourceTemplate;
@@ -420,7 +421,7 @@ pub enum SandboxPolicy {
420421
#[ts(rename_all = "camelCase")]
421422
WorkspaceWrite {
422423
#[serde(default)]
423-
writable_roots: Vec<PathBuf>,
424+
writable_roots: Vec<AbsolutePathBuf>,
424425
#[serde(default)]
425426
network_access: bool,
426427
#[serde(default)]

codex-rs/app-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ codex-protocol = { workspace = true }
2727
codex-app-server-protocol = { workspace = true }
2828
codex-feedback = { workspace = true }
2929
codex-rmcp-client = { workspace = true }
30+
codex-utils-absolute-path = { workspace = true }
3031
codex-utils-json-to-toml = { workspace = true }
3132
chrono = { workspace = true }
3233
serde = { workspace = true, features = ["derive"] }

codex-rs/app-server/tests/suite/codex_message_processor_flow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ async fn test_send_user_turn_updates_sandbox_and_cwd_between_turns() -> Result<(
410410
cwd: first_cwd.clone(),
411411
approval_policy: AskForApproval::Never,
412412
sandbox_policy: SandboxPolicy::WorkspaceWrite {
413-
writable_roots: vec![first_cwd.clone()],
413+
writable_roots: vec![first_cwd.try_into()?],
414414
network_access: false,
415415
exclude_tmpdir_env_var: false,
416416
exclude_slash_tmp: false,

codex-rs/app-server/tests/suite/config.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use codex_protocol::config_types::ReasoningSummary;
1414
use codex_protocol::config_types::SandboxMode;
1515
use codex_protocol::config_types::Verbosity;
1616
use codex_protocol::openai_models::ReasoningEffort;
17+
use codex_utils_absolute_path::AbsolutePathBuf;
1718
use pretty_assertions::assert_eq;
1819
use std::collections::HashMap;
1920
use std::path::Path;
@@ -23,10 +24,16 @@ use tokio::time::timeout;
2324
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
2425

2526
fn create_config_toml(codex_home: &Path) -> std::io::Result<()> {
27+
let writable_root = if cfg!(windows) {
28+
r"C:\Users\codex\AppData\Local\Temp"
29+
} else {
30+
"/tmp"
31+
};
2632
let config_toml = codex_home.join("config.toml");
2733
std::fs::write(
2834
config_toml,
29-
r#"
35+
format!(
36+
r#"
3037
model = "gpt-5.1-codex-max"
3138
approval_policy = "on-request"
3239
sandbox_mode = "workspace-write"
@@ -38,7 +45,7 @@ forced_chatgpt_workspace_id = "12345678-0000-0000-0000-000000000000"
3845
forced_login_method = "chatgpt"
3946
4047
[sandbox_workspace_write]
41-
writable_roots = ["/tmp"]
48+
writable_roots = [{}]
4249
network_access = true
4350
exclude_tmpdir_env_var = true
4451
exclude_slash_tmp = true
@@ -56,6 +63,8 @@ model_verbosity = "medium"
5663
model_provider = "openai"
5764
chatgpt_base_url = "https://api.chatgpt.com"
5865
"#,
66+
serde_json::json!(writable_root)
67+
),
5968
)
6069
}
6170

@@ -75,12 +84,18 @@ async fn get_config_toml_parses_all_fields() -> Result<()> {
7584
.await??;
7685

7786
let config: GetUserSavedConfigResponse = to_response(resp)?;
87+
let writable_root = if cfg!(windows) {
88+
r"C:\Users\codex\AppData\Local\Temp"
89+
} else {
90+
"/tmp"
91+
};
92+
let writable_root = AbsolutePathBuf::from_absolute_path(writable_root)?;
7893
let expected = GetUserSavedConfigResponse {
7994
config: UserSavedConfig {
8095
approval_policy: Some(AskForApproval::OnRequest),
8196
sandbox_mode: Some(SandboxMode::WorkspaceWrite),
8297
sandbox_settings: Some(SandboxSettings {
83-
writable_roots: vec!["/tmp".into()],
98+
writable_roots: vec![writable_root],
8499
network_access: Some(true),
85100
exclude_tmpdir_env_var: Some(true),
86101
exclude_slash_tmp: Some(true),

codex-rs/app-server/tests/suite/v2/config_rpc.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,29 +135,40 @@ view_image = false
135135
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
136136
async fn config_read_includes_system_layer_and_overrides() -> Result<()> {
137137
let codex_home = TempDir::new()?;
138+
let (user_dir, system_dir) = if cfg!(windows) {
139+
(r"C:\Users\user", r"C:\System")
140+
} else {
141+
("/user", "/system")
142+
};
138143
write_config(
139144
&codex_home,
140-
r#"
145+
&format!(
146+
r#"
141147
model = "gpt-user"
142148
approval_policy = "on-request"
143149
sandbox_mode = "workspace-write"
144150
145151
[sandbox_workspace_write]
146-
writable_roots = ["/user"]
152+
writable_roots = [{}]
147153
network_access = true
148154
"#,
155+
serde_json::json!(user_dir)
156+
),
149157
)?;
150158

151159
let managed_path = codex_home.path().join("managed_config.toml");
152160
std::fs::write(
153161
&managed_path,
154-
r#"
162+
format!(
163+
r#"
155164
model = "gpt-system"
156165
approval_policy = "never"
157166
158167
[sandbox_workspace_write]
159-
writable_roots = ["/system"]
168+
writable_roots = [{}]
160169
"#,
170+
serde_json::json!(system_dir)
171+
),
161172
)?;
162173

163174
let managed_path_str = managed_path.display().to_string();
@@ -207,7 +218,7 @@ writable_roots = ["/system"]
207218
.sandbox_workspace_write
208219
.as_ref()
209220
.expect("sandbox workspace write");
210-
assert_eq!(sandbox.writable_roots, vec![PathBuf::from("/system")]);
221+
assert_eq!(sandbox.writable_roots, vec![PathBuf::from(system_dir)]);
211222
assert_eq!(
212223
origins
213224
.get("sandbox_workspace_write.writable_roots.0")
@@ -350,6 +361,11 @@ async fn config_batch_write_applies_multiple_edits() -> Result<()> {
350361
let mut mcp = McpProcess::new(codex_home.path()).await?;
351362
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
352363

364+
let writable_root = if cfg!(windows) {
365+
r"C:\Users\codex\AppData\Local\Temp"
366+
} else {
367+
"/tmp"
368+
};
353369
let batch_id = mcp
354370
.send_config_batch_write_request(ConfigBatchWriteParams {
355371
file_path: Some(codex_home.path().join("config.toml").display().to_string()),
@@ -362,7 +378,7 @@ async fn config_batch_write_applies_multiple_edits() -> Result<()> {
362378
ConfigEdit {
363379
key_path: "sandbox_workspace_write".to_string(),
364380
value: json!({
365-
"writable_roots": ["/tmp"],
381+
"writable_roots": [writable_root],
366382
"network_access": false
367383
}),
368384
merge_strategy: MergeStrategy::Replace,
@@ -404,7 +420,7 @@ async fn config_batch_write_applies_multiple_edits() -> Result<()> {
404420
.sandbox_workspace_write
405421
.as_ref()
406422
.expect("sandbox workspace write");
407-
assert_eq!(sandbox.writable_roots, vec![PathBuf::from("/tmp")]);
423+
assert_eq!(sandbox.writable_roots, vec![PathBuf::from(writable_root)]);
408424
assert!(!sandbox.network_access);
409425

410426
Ok(())

codex-rs/app-server/tests/suite/v2/turn_start.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ async fn turn_start_updates_sandbox_and_cwd_between_turns_v2() -> Result<()> {
532532
cwd: Some(first_cwd.clone()),
533533
approval_policy: Some(codex_app_server_protocol::AskForApproval::Never),
534534
sandbox_policy: Some(codex_app_server_protocol::SandboxPolicy::WorkspaceWrite {
535-
writable_roots: vec![first_cwd.clone()],
535+
writable_roots: vec![first_cwd.try_into()?],
536536
network_access: false,
537537
exclude_tmpdir_env_var: false,
538538
exclude_slash_tmp: false,

0 commit comments

Comments
 (0)