From b61264985f6711a0f3db44e181737d6b4c4f3502 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Mon, 20 Apr 2026 15:04:17 -0700 Subject: [PATCH] protocol: preserve glob scan depth in permission profiles --- ...CommandExecutionRequestApprovalParams.json | 8 ++ .../PermissionsRequestApprovalParams.json | 8 ++ .../PermissionsRequestApprovalResponse.json | 8 ++ .../schema/json/ServerRequest.json | 8 ++ .../codex_app_server_protocol.schemas.json | 8 ++ .../v2/AdditionalFileSystemPermissions.ts | 2 +- .../src/protocol/common.rs | 1 + .../app-server-protocol/src/protocol/v2.rs | 16 ++- codex-rs/app-server/src/transport/mod.rs | 2 + .../tests/suite/v2/request_permissions.rs | 1 + codex-rs/protocol/src/models.rs | 86 +++++++++++++- codex-rs/sandboxing/src/policy_transforms.rs | 72 +++++++++++- .../sandboxing/src/policy_transforms_tests.rs | 109 ++++++++++++++++++ codex-rs/tui/src/app.rs | 2 + codex-rs/tui/src/app/app_server_requests.rs | 1 + .../src/app_server_approval_conversions.rs | 3 + .../tui/src/bottom_pane/approval_overlay.rs | 1 + .../src/chatwidget/tests/approval_requests.rs | 2 + 18 files changed, 326 insertions(+), 12 deletions(-) diff --git a/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json b/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json index b55e14f4ad..94668c6d8f 100644 --- a/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json +++ b/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json @@ -16,6 +16,14 @@ "null" ] }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, "read": { "items": { "$ref": "#/definitions/AbsolutePathBuf" diff --git a/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalParams.json b/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalParams.json index 2c8bfba83c..df05a56ef4 100644 --- a/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalParams.json +++ b/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalParams.json @@ -16,6 +16,14 @@ "null" ] }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, "read": { "items": { "$ref": "#/definitions/AbsolutePathBuf" diff --git a/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalResponse.json b/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalResponse.json index 4564138527..b6a388d666 100644 --- a/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalResponse.json +++ b/codex-rs/app-server-protocol/schema/json/PermissionsRequestApprovalResponse.json @@ -16,6 +16,14 @@ "null" ] }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, "read": { "items": { "$ref": "#/definitions/AbsolutePathBuf" diff --git a/codex-rs/app-server-protocol/schema/json/ServerRequest.json b/codex-rs/app-server-protocol/schema/json/ServerRequest.json index b778ae0205..a4aeb9ddc3 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ServerRequest.json @@ -16,6 +16,14 @@ "null" ] }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, "read": { "items": { "$ref": "#/definitions/AbsolutePathBuf" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 7f645dfd3d..9ab9604982 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -16,6 +16,14 @@ "null" ] }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, "read": { "items": { "$ref": "#/definitions/v2/AbsolutePathBuf" diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalFileSystemPermissions.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalFileSystemPermissions.ts index 21af5dda71..2be8f7f0e7 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalFileSystemPermissions.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalFileSystemPermissions.ts @@ -4,4 +4,4 @@ import type { AbsolutePathBuf } from "../AbsolutePathBuf"; import type { FileSystemSandboxEntry } from "./FileSystemSandboxEntry"; -export type AdditionalFileSystemPermissions = { read: Array | null, write: Array | null, entries?: Array, }; +export type AdditionalFileSystemPermissions = { read: Array | null, write: Array | null, globScanMaxDepth?: number, entries?: Array, }; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index 6253315610..aa3ff8331c 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -2056,6 +2056,7 @@ mod tests { file_system: Some(v2::AdditionalFileSystemPermissions { read: Some(vec![absolute_path("/tmp/allowed")]), write: None, + glob_scan_max_depth: None, entries: None, }), }), diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 77f339db53..5431bb8dda 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -1162,6 +1162,9 @@ pub struct AdditionalFileSystemPermissions { pub write: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] + pub glob_scan_max_depth: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional)] pub entries: Option>, } @@ -1171,12 +1174,14 @@ impl From for AdditionalFileSystemPermissions { Self { read, write, + glob_scan_max_depth: None, entries: None, } } else { Self { read: None, write: None, + glob_scan_max_depth: value.glob_scan_max_depth, entries: Some( value .entries @@ -1191,16 +1196,19 @@ impl From for AdditionalFileSystemPermissions { impl From for CoreFileSystemPermissions { fn from(value: AdditionalFileSystemPermissions) -> Self { - if let Some(entries) = value.entries { + let mut permissions = if let Some(entries) = value.entries { Self { entries: entries .into_iter() .map(CoreFileSystemSandboxEntry::from) .collect(), + glob_scan_max_depth: None, } } else { CoreFileSystemPermissions::from_read_write_roots(value.read, value.write) - } + }; + permissions.glob_scan_max_depth = value.glob_scan_max_depth; + permissions } } @@ -7084,6 +7092,7 @@ mod tests { AbsolutePathBuf::try_from(PathBuf::from(read_write_path)) .expect("path must be absolute"), ]), + glob_scan_max_depth: None, entries: None, }), } @@ -7155,6 +7164,7 @@ mod tests { access: CoreFileSystemAccessMode::None, }, ], + glob_scan_max_depth: Some(2), }; let permissions = AdditionalFileSystemPermissions::from(core_permissions.clone()); @@ -7163,6 +7173,7 @@ mod tests { AdditionalFileSystemPermissions { read: None, write: None, + glob_scan_max_depth: Some(2), entries: Some(vec![ FileSystemSandboxEntry { path: FileSystemPath::Special { @@ -7225,6 +7236,7 @@ mod tests { AbsolutePathBuf::try_from(PathBuf::from(read_write_path)) .expect("path must be absolute"), ]), + glob_scan_max_depth: None, entries: None, }), } diff --git a/codex-rs/app-server/src/transport/mod.rs b/codex-rs/app-server/src/transport/mod.rs index d12107b1d8..a07bd44188 100644 --- a/codex-rs/app-server/src/transport/mod.rs +++ b/codex-rs/app-server/src/transport/mod.rs @@ -781,6 +781,7 @@ mod tests { codex_app_server_protocol::AdditionalFileSystemPermissions { read: Some(vec![absolute_path("/tmp/allowed")]), write: None, + glob_scan_max_depth: None, entries: None, }, ), @@ -844,6 +845,7 @@ mod tests { codex_app_server_protocol::AdditionalFileSystemPermissions { read: Some(vec![absolute_path("/tmp/allowed")]), write: None, + glob_scan_max_depth: None, entries: None, }, ), diff --git a/codex-rs/app-server/tests/suite/v2/request_permissions.rs b/codex-rs/app-server/tests/suite/v2/request_permissions.rs index 05a45011de..295ac96a3b 100644 --- a/codex-rs/app-server/tests/suite/v2/request_permissions.rs +++ b/codex-rs/app-server/tests/suite/v2/request_permissions.rs @@ -93,6 +93,7 @@ async fn request_permissions_round_trip() -> Result<()> { file_system: Some(codex_app_server_protocol::AdditionalFileSystemPermissions { read: None, write: Some(vec![requested_writes[0].clone()]), + glob_scan_max_depth: None, entries: None, }), }, diff --git a/codex-rs/protocol/src/models.rs b/codex-rs/protocol/src/models.rs index 25c44fae09..208ef80f2f 100644 --- a/codex-rs/protocol/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -146,6 +146,7 @@ impl SandboxPermissions { #[derive(Debug, Clone, Default, Eq, Hash, PartialEq, JsonSchema, TS)] pub struct FileSystemPermissions { pub entries: Vec, + pub glob_scan_max_depth: Option, } pub type LegacyReadWriteRoots = (Option>, Option>); @@ -172,7 +173,10 @@ impl FileSystemPermissions { access: FileSystemAccessMode::Write, })); } - Self { entries } + Self { + entries, + glob_scan_max_depth: None, + } } pub fn explicit_path_entries( @@ -190,6 +194,10 @@ impl FileSystemPermissions { } fn as_legacy_permissions(&self) -> Option { + if self.glob_scan_max_depth.is_some() { + return None; + } + let mut read = Vec::new(); let mut write = Vec::new(); @@ -225,6 +233,8 @@ struct LegacyFileSystemPermissions { struct CanonicalFileSystemPermissions { #[serde(default, skip_serializing_if = "Vec::is_empty")] entries: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + glob_scan_max_depth: Option, } #[derive(Debug, Clone, Deserialize)] @@ -244,6 +254,7 @@ impl Serialize for FileSystemPermissions { } else { CanonicalFileSystemPermissions { entries: self.entries.clone(), + glob_scan_max_depth: self.glob_scan_max_depth, } .serialize(serializer) } @@ -256,9 +267,13 @@ impl<'de> Deserialize<'de> for FileSystemPermissions { D: Deserializer<'de>, { match FileSystemPermissionsDe::deserialize(deserializer)? { - FileSystemPermissionsDe::Canonical(CanonicalFileSystemPermissions { entries }) => { - Ok(Self { entries }) - } + FileSystemPermissionsDe::Canonical(CanonicalFileSystemPermissions { + entries, + glob_scan_max_depth, + }) => Ok(Self { + entries, + glob_scan_max_depth, + }), FileSystemPermissionsDe::Legacy(LegacyFileSystemPermissions { read, write }) => { Ok(Self::from_read_write_roots(read, write)) } @@ -352,13 +367,18 @@ impl From<&FileSystemSandboxPolicy> for FileSystemPermissions { }] } }; - Self { entries } + Self { + entries, + glob_scan_max_depth: value.glob_scan_max_depth, + } } } impl From<&FileSystemPermissions> for FileSystemSandboxPolicy { fn from(value: &FileSystemPermissions) -> Self { - FileSystemSandboxPolicy::restricted(value.entries.clone()) + let mut policy = FileSystemSandboxPolicy::restricted(value.entries.clone()); + policy.glob_scan_max_depth = value.glob_scan_max_depth; + policy } } @@ -1828,6 +1848,60 @@ mod tests { assert_eq!(permission_profile.is_empty(), false); } + #[test] + fn permission_profile_round_trip_preserves_glob_scan_max_depth() { + let mut file_system_sandbox_policy = + FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry { + path: FileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: FileSystemAccessMode::None, + }]); + file_system_sandbox_policy.glob_scan_max_depth = Some(2); + + let permission_profile = PermissionProfile::from_runtime_permissions( + &file_system_sandbox_policy, + NetworkSandboxPolicy::Restricted, + ); + + assert_eq!( + permission_profile.file_system_sandbox_policy(), + file_system_sandbox_policy + ); + } + + #[test] + fn file_system_permissions_with_glob_scan_depth_uses_canonical_json() -> Result<()> { + let path = AbsolutePathBuf::try_from(PathBuf::from(if cfg!(windows) { + r"C:\tmp\allowed" + } else { + "/tmp/allowed" + })) + .expect("absolute path"); + let file_system_permissions = FileSystemPermissions { + entries: vec![FileSystemSandboxEntry { + path: FileSystemPath::Path { path }, + access: FileSystemAccessMode::Read, + }], + glob_scan_max_depth: Some(2), + }; + + let serialized = serde_json::to_value(&file_system_permissions)?; + + assert_eq!(serialized.get("read"), None); + assert_eq!(serialized.get("write"), None); + assert_eq!( + serialized.get("glob_scan_max_depth"), + Some(&serde_json::json!(2)) + ); + assert!(serialized.get("entries").is_some()); + assert_eq!( + serde_json::from_value::(serialized)?, + file_system_permissions + ); + Ok(()) + } + #[test] fn convert_mcp_content_to_items_builds_data_urls_when_missing_prefix() { let contents = vec![serde_json::json!({ diff --git a/codex-rs/sandboxing/src/policy_transforms.rs b/codex-rs/sandboxing/src/policy_transforms.rs index aa0ccc267b..fa6c93b109 100644 --- a/codex-rs/sandboxing/src/policy_transforms.rs +++ b/codex-rs/sandboxing/src/policy_transforms.rs @@ -45,6 +45,7 @@ pub fn normalize_additional_permissions( let file_system = match additional_permissions.file_system { Some(file_system) => { let mut entries = Vec::with_capacity(file_system.entries.len()); + let glob_scan_max_depth = file_system.glob_scan_max_depth; for entry in file_system.entries { if matches!(&entry.path, FileSystemPath::GlobPattern { .. }) && entry.access != FileSystemAccessMode::None @@ -73,7 +74,10 @@ pub fn normalize_additional_permissions( entries.push(normalized_entry); } } - let file_system = FileSystemPermissions { entries }; + let file_system = FileSystemPermissions { + entries, + glob_scan_max_depth, + }; (!file_system.is_empty()).then_some(file_system) } None => None, @@ -114,6 +118,12 @@ pub fn merge_permission_profiles( let file_system = match (base.file_system.as_ref(), permissions.file_system.as_ref()) { (Some(base), Some(permissions)) => Some(FileSystemPermissions { entries: merge_permission_entries(&base.entries, &permissions.entries), + glob_scan_max_depth: merge_glob_scan_max_depth( + &base.entries, + base.glob_scan_max_depth, + &permissions.entries, + permissions.glob_scan_max_depth, + ), }) .filter(|file_system| !file_system.is_empty()), (Some(base), None) => Some(base.clone()), @@ -139,12 +149,20 @@ pub fn intersect_permission_profiles( .file_system .map(|requested_file_system| { let granted_file_system = granted.file_system.unwrap_or_default(); - let entries = requested_file_system + let entries: Vec<_> = requested_file_system .entries .into_iter() .filter(|entry| granted_file_system.entries.contains(entry)) .collect(); - FileSystemPermissions { entries } + FileSystemPermissions { + glob_scan_max_depth: merge_glob_scan_max_depth( + &entries, + requested_file_system.glob_scan_max_depth, + &entries, + granted_file_system.glob_scan_max_depth, + ), + entries, + } }) .filter(|file_system| !file_system.is_empty()); let network = match (requested.network, granted.network) { @@ -167,6 +185,48 @@ pub fn intersect_permission_profiles( } } +fn merge_glob_scan_max_depth( + left_entries: &[FileSystemSandboxEntry], + left_depth: Option, + right_entries: &[FileSystemSandboxEntry], + right_depth: Option, +) -> Option { + let left_depth = effective_glob_scan_depth(left_entries, left_depth); + let right_depth = effective_glob_scan_depth(right_entries, right_depth); + + match (left_depth, right_depth) { + (Some(GlobScanDepth::Unbounded), _) | (_, Some(GlobScanDepth::Unbounded)) => None, + (Some(GlobScanDepth::Bounded(left)), Some(GlobScanDepth::Bounded(right))) => { + Some(left.max(right)) + } + (Some(GlobScanDepth::Bounded(depth)), None) + | (None, Some(GlobScanDepth::Bounded(depth))) => Some(depth), + (None, None) => None, + } +} + +fn effective_glob_scan_depth( + entries: &[FileSystemSandboxEntry], + depth: Option, +) -> Option { + entries + .iter() + .any(|entry| { + entry.access == FileSystemAccessMode::None + && matches!(&entry.path, FileSystemPath::GlobPattern { .. }) + }) + .then_some(match depth { + Some(depth) => GlobScanDepth::Bounded(depth), + None => GlobScanDepth::Unbounded, + }) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum GlobScanDepth { + Bounded(usize), + Unbounded, +} + fn merge_permission_entries( base: &[FileSystemSandboxEntry], permissions: &[FileSystemSandboxEntry], @@ -234,6 +294,12 @@ fn merge_file_system_policy_with_additional_permissions( merged_policy.entries.push(entry.clone()); } } + merged_policy.glob_scan_max_depth = merge_glob_scan_max_depth( + &file_system_policy.entries, + file_system_policy.glob_scan_max_depth, + &additional_permissions.entries, + additional_permissions.glob_scan_max_depth, + ); merged_policy } FileSystemSandboxKind::Unrestricted | FileSystemSandboxKind::ExternalSandbox => { diff --git a/codex-rs/sandboxing/src/policy_transforms_tests.rs b/codex-rs/sandboxing/src/policy_transforms_tests.rs index 5de8a5cd5a..5540d8fb6f 100644 --- a/codex-rs/sandboxing/src/policy_transforms_tests.rs +++ b/codex-rs/sandboxing/src/policy_transforms_tests.rs @@ -171,6 +171,7 @@ fn normalize_additional_permissions_rejects_glob_read_grants() { }, access: FileSystemAccessMode::Read, }], + glob_scan_max_depth: None, }), ..Default::default() }) @@ -192,6 +193,7 @@ fn normalize_additional_permissions_preserves_deny_globs() { }, access: FileSystemAccessMode::None, }], + glob_scan_max_depth: Some(2), }), ..Default::default() }) @@ -207,6 +209,7 @@ fn normalize_additional_permissions_preserves_deny_globs() { }, access: FileSystemAccessMode::None, }], + glob_scan_max_depth: Some(2), }), ..Default::default() } @@ -288,6 +291,76 @@ fn intersect_permission_profiles_drops_explicit_empty_reads_without_grant() { ); } +#[test] +fn intersect_permission_profiles_uses_granted_bounded_glob_scan_depth() { + let deny_env_files = FileSystemSandboxEntry { + path: FileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: FileSystemAccessMode::None, + }; + let requested = PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files.clone()], + glob_scan_max_depth: Some(2), + }), + ..Default::default() + }; + let granted = PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files.clone()], + glob_scan_max_depth: Some(4), + }), + ..Default::default() + }; + + assert_eq!( + intersect_permission_profiles(requested, granted), + PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files], + glob_scan_max_depth: Some(4), + }), + ..Default::default() + } + ); +} + +#[test] +fn intersect_permission_profiles_uses_granted_unbounded_glob_scan_depth() { + let deny_env_files = FileSystemSandboxEntry { + path: FileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: FileSystemAccessMode::None, + }; + let requested = PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files.clone()], + glob_scan_max_depth: Some(2), + }), + ..Default::default() + }; + let granted = PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files.clone()], + glob_scan_max_depth: None, + }), + ..Default::default() + }; + + assert_eq!( + intersect_permission_profiles(requested, granted), + PermissionProfile { + file_system: Some(FileSystemPermissions { + entries: vec![deny_env_files], + glob_scan_max_depth: None, + }), + ..Default::default() + } + ); +} + #[test] fn read_only_additional_permissions_can_enable_network_without_writes() { let temp_dir = TempDir::new().expect("create temp dir"); @@ -402,6 +475,42 @@ fn merge_file_system_policy_with_additional_permissions_preserves_unreadable_roo ); } +#[test] +fn merge_file_system_policy_with_additional_permissions_carries_bounded_glob_scan_depth() { + let deny_env_files = FileSystemSandboxEntry { + path: FileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: FileSystemAccessMode::None, + }; + let merged_policy = merge_file_system_policy_with_additional_permissions( + &FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry { + path: FileSystemPath::Special { + value: FileSystemSpecialPath::Root, + }, + access: FileSystemAccessMode::Write, + }]), + &FileSystemPermissions { + entries: vec![deny_env_files.clone()], + glob_scan_max_depth: Some(2), + }, + ); + + assert_eq!(merged_policy, { + let mut policy = FileSystemSandboxPolicy::restricted(vec![ + FileSystemSandboxEntry { + path: FileSystemPath::Special { + value: FileSystemSpecialPath::Root, + }, + access: FileSystemAccessMode::Write, + }, + deny_env_files, + ]); + policy.glob_scan_max_depth = Some(2); + policy + }); +} + #[test] fn effective_file_system_sandbox_policy_returns_base_policy_without_additional_permissions() { let temp_dir = TempDir::new().expect("create temp dir"); diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index dc8ca2784c..55659ea866 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -9667,6 +9667,7 @@ guardian_approval = true file_system: Some(AdditionalFileSystemPermissions { read: Some(vec![test_absolute_path("/tmp/read-only")]), write: Some(vec![test_absolute_path("/tmp/write")]), + glob_scan_max_depth: None, entries: None, }), }); @@ -9775,6 +9776,7 @@ guardian_approval = true file_system: Some(AdditionalFileSystemPermissions { read: Some(vec![test_absolute_path("/tmp/read-only")]), write: Some(vec![test_absolute_path("/tmp/write")]), + glob_scan_max_depth: None, entries: None, }), }, diff --git a/codex-rs/tui/src/app/app_server_requests.rs b/codex-rs/tui/src/app/app_server_requests.rs index c54aae826f..58ee962fdb 100644 --- a/codex-rs/tui/src/app/app_server_requests.rs +++ b/codex-rs/tui/src/app/app_server_requests.rs @@ -558,6 +558,7 @@ mod tests { file_system: Some(AdditionalFileSystemPermissions { read: Some(vec![absolute_path(read_path)]), write: Some(vec![absolute_path(write_path)]), + glob_scan_max_depth: None, entries: None, }), }, diff --git a/codex-rs/tui/src/app_server_approval_conversions.rs b/codex-rs/tui/src/app_server_approval_conversions.rs index 7b8e777d5b..a26f9b2a90 100644 --- a/codex-rs/tui/src/app_server_approval_conversions.rs +++ b/codex-rs/tui/src/app_server_approval_conversions.rs @@ -92,6 +92,7 @@ mod tests { file_system: Some(codex_app_server_protocol::AdditionalFileSystemPermissions { read: Some(vec![absolute_path("/tmp/read-only")]), write: Some(vec![absolute_path("/tmp/write")]), + glob_scan_max_depth: None, entries: None, }), } @@ -109,6 +110,7 @@ mod tests { }, access: FileSystemAccessMode::Write, }], + glob_scan_max_depth: None, }), ..Default::default() }), @@ -117,6 +119,7 @@ mod tests { file_system: Some(codex_app_server_protocol::AdditionalFileSystemPermissions { read: None, write: None, + glob_scan_max_depth: None, entries: Some(vec![codex_app_server_protocol::FileSystemSandboxEntry { path: codex_app_server_protocol::FileSystemPath::Special { value: codex_app_server_protocol::FileSystemSpecialPath::Root, diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs index 1c148cd02a..5212d81953 100644 --- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs +++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs @@ -1372,6 +1372,7 @@ mod tests { access: FileSystemAccessMode::None, }, ], + glob_scan_max_depth: None, }), ..Default::default() }; diff --git a/codex-rs/tui/src/chatwidget/tests/approval_requests.rs b/codex-rs/tui/src/chatwidget/tests/approval_requests.rs index 472a13c118..4e5bc7556e 100644 --- a/codex-rs/tui/src/chatwidget/tests/approval_requests.rs +++ b/codex-rs/tui/src/chatwidget/tests/approval_requests.rs @@ -113,6 +113,7 @@ fn app_server_exec_approval_request_preserves_permissions_context() { file_system: Some(AppServerAdditionalFileSystemPermissions { read: Some(vec![read_path.clone()]), write: Some(vec![write_path.clone()]), + glob_scan_max_depth: None, entries: None, }), }), @@ -163,6 +164,7 @@ fn app_server_request_permissions_preserves_file_system_permissions() { file_system: Some(AppServerAdditionalFileSystemPermissions { read: Some(vec![read_path.clone()]), write: Some(vec![write_path.clone()]), + glob_scan_max_depth: None, entries: None, }), },