diff --git a/codex-rs/app-server/src/request_processors/config_processor.rs b/codex-rs/app-server/src/request_processors/config_processor.rs index 52a05e5ae9..25e730e064 100644 --- a/codex-rs/app-server/src/request_processors/config_processor.rs +++ b/codex-rs/app-server/src/request_processors/config_processor.rs @@ -790,6 +790,7 @@ mod tests { let mapped = map_requirements_toml_to_api(ConfigRequirementsToml { computer_use: Some(ComputerUseRequirementsToml { allow_locked_computer_use: Some(false), + ..ComputerUseRequirementsToml::default() }), ..ConfigRequirementsToml::default() }); diff --git a/codex-rs/config/src/browser_computer_use_requirements.rs b/codex-rs/config/src/browser_computer_use_requirements.rs new file mode 100644 index 0000000000..eaf545a28a --- /dev/null +++ b/codex-rs/config/src/browser_computer_use_requirements.rs @@ -0,0 +1,108 @@ +use serde::Deserialize; +use std::collections::BTreeMap; + +#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum AllowDenyRequirementToml { + Allow, + Deny, +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct BrowserUseOriginPolicyToml { + pub access: Option, + pub downloads: Option, + pub uploads: Option, + pub full_cdp_access: Option, + pub auto_review: Option, + pub persistent_approval: Option, + pub access_approval_lifetime: Option, +} + +impl BrowserUseOriginPolicyToml { + fn is_empty(&self) -> bool { + self.access.is_none() + && self.downloads.is_none() + && self.uploads.is_none() + && self.full_cdp_access.is_none() + && self.auto_review.is_none() + && self.persistent_approval.is_none() + && self.access_approval_lifetime.is_none() + } +} + +#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserUseAccessApprovalLifetimeToml { + Turn, + Thread, +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct BrowserUseRequirementsToml { + pub allow_history_access: Option, + pub disable_auto_review: Option, + pub allow_global_persistent_approval: Option, + pub default_origin_policy: Option, + pub origins: Option>, +} + +impl BrowserUseRequirementsToml { + pub fn is_empty(&self) -> bool { + self.allow_history_access.is_none() + && self.disable_auto_review.is_none() + && self.allow_global_persistent_approval.is_none() + && self + .default_origin_policy + .as_ref() + .is_none_or(BrowserUseOriginPolicyToml::is_empty) + && self + .origins + .as_ref() + .is_none_or(|origins| origins.values().all(BrowserUseOriginPolicyToml::is_empty)) + } +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct ComputerUseMacosRequirementsToml { + pub bundle_ids: Option>, +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct ComputerUseWindowsRequirementsToml { + pub aumids: Option>, + pub exes: Option>, +} + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct ComputerUseWindowsExeRequirementToml { + pub publisher_name: String, + pub product_name: String, + pub binary_name: Option, + pub access: AllowDenyRequirementToml, +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct ComputerUseRequirementsToml { + pub allow_locked_computer_use: Option, + pub allow_persistent_approval: Option, + pub default_app_access: Option, + pub macos: Option, + pub windows: Option, +} + +impl ComputerUseRequirementsToml { + pub fn is_empty(&self) -> bool { + self.allow_locked_computer_use.is_none() + && self.allow_persistent_approval.is_none() + && self.default_app_access.is_none() + && self + .macos + .as_ref() + .is_none_or(|macos| macos.bundle_ids.as_ref().is_none_or(BTreeMap::is_empty)) + && self.windows.as_ref().is_none_or(|windows| { + windows.aumids.as_ref().is_none_or(BTreeMap::is_empty) + && windows.exes.as_ref().is_none_or(Vec::is_empty) + }) + } +} diff --git a/codex-rs/config/src/config_requirements.rs b/codex-rs/config/src/config_requirements.rs index 81c082bb2c..0b6785b594 100644 --- a/codex-rs/config/src/config_requirements.rs +++ b/codex-rs/config/src/config_requirements.rs @@ -27,6 +27,8 @@ use crate::ManagedHooksRequirementsToml; use crate::McpServerRequirement; use crate::PluginRequirementsToml; use crate::RequirementsExecPolicy; +use crate::browser_computer_use_requirements::BrowserUseRequirementsToml; +use crate::browser_computer_use_requirements::ComputerUseRequirementsToml; use crate::config_toml::ConfigToml; use crate::mcp_requirements::validate_mcp_server_requirement; use crate::mcp_types::AppToolApproval; @@ -793,28 +795,6 @@ impl fmt::Display for WebSearchModeRequirement { } } -#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] -pub struct ComputerUseRequirementsToml { - pub allow_locked_computer_use: Option, -} - -impl ComputerUseRequirementsToml { - pub fn is_empty(&self) -> bool { - self.allow_locked_computer_use.is_none() - } -} - -#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] -pub struct BrowserUseRequirementsToml { - pub disable_auto_review: Option, -} - -impl BrowserUseRequirementsToml { - pub fn is_empty(&self) -> bool { - self.disable_auto_review.is_none() - } -} - #[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] pub struct WindowsRequirementsToml { pub allowed_sandbox_implementations: Option>, @@ -942,6 +922,7 @@ pub struct ConfigRequirementsToml { pub remote_sandbox_config: Option>, pub allowed_web_search_modes: Option>, pub allow_managed_hooks_only: Option, + pub allow_browser_and_computer_use: Option, pub allow_appshots: Option, pub allow_remote_control: Option, pub computer_use: Option, @@ -1045,6 +1026,7 @@ pub struct ConfigRequirementsWithSources { pub default_permissions: Option>, pub allowed_web_search_modes: Option>>, pub allow_managed_hooks_only: Option>, + pub allow_browser_and_computer_use: Option>, pub allow_appshots: Option>, pub allow_remote_control: Option>, pub computer_use: Option>, @@ -1104,6 +1086,7 @@ impl ConfigRequirementsWithSources { remote_sandbox_config: _, allowed_web_search_modes: _, allow_managed_hooks_only: _, + allow_browser_and_computer_use: _, allow_appshots: _, allow_remote_control: _, computer_use: _, @@ -1156,6 +1139,7 @@ impl ConfigRequirementsWithSources { default_permissions, allowed_web_search_modes, allow_managed_hooks_only, + allow_browser_and_computer_use, allow_appshots, allow_remote_control, computer_use, @@ -1237,6 +1221,7 @@ impl ConfigRequirementsWithSources { default_permissions, allowed_web_search_modes, allow_managed_hooks_only, + allow_browser_and_computer_use, allow_appshots, allow_remote_control, computer_use, @@ -1277,6 +1262,8 @@ impl ConfigRequirementsWithSources { remote_sandbox_config: None, allowed_web_search_modes: allowed_web_search_modes.map(|sourced| sourced.value), allow_managed_hooks_only: allow_managed_hooks_only.map(|sourced| sourced.value), + allow_browser_and_computer_use: allow_browser_and_computer_use + .map(|sourced| sourced.value), allow_appshots: allow_appshots.map(|sourced| sourced.value), allow_remote_control: allow_remote_control.map(|sourced| sourced.value), computer_use: computer_use.map(|sourced| sourced.value), @@ -1387,6 +1374,7 @@ impl ConfigRequirementsToml { && self.remote_sandbox_config.is_none() && self.allowed_web_search_modes.is_none() && self.allow_managed_hooks_only.is_none() + && self.allow_browser_and_computer_use.is_none() && self.allow_appshots.is_none() && self.allow_remote_control.is_none() && self @@ -1599,6 +1587,7 @@ impl TryFrom for ConfigRequirements { default_permissions: _, allowed_web_search_modes, allow_managed_hooks_only, + allow_browser_and_computer_use: _, allow_appshots, allow_remote_control, computer_use, @@ -2006,6 +1995,12 @@ pub fn sandbox_mode_requirement_for_permission_profile( #[cfg(test)] mod tests { use super::*; + use crate::AllowDenyRequirementToml; + use crate::BrowserUseAccessApprovalLifetimeToml; + use crate::BrowserUseOriginPolicyToml; + use crate::ComputerUseMacosRequirementsToml; + use crate::ComputerUseWindowsExeRequirementToml; + use crate::ComputerUseWindowsRequirementsToml; use crate::HookEventsToml; use crate::McpServerCommandMatcher; use crate::McpServerIdentity; @@ -2129,6 +2124,7 @@ mod tests { remote_sandbox_config: _, allowed_web_search_modes, allow_managed_hooks_only, + allow_browser_and_computer_use, allow_appshots, allow_remote_control, computer_use, @@ -2182,6 +2178,8 @@ mod tests { .map(|value| Sourced::new(value, RequirementSource::Unknown)), allow_managed_hooks_only: allow_managed_hooks_only .map(|value| Sourced::new(value, RequirementSource::Unknown)), + allow_browser_and_computer_use: allow_browser_and_computer_use + .map(|value| Sourced::new(value, RequirementSource::Unknown)), allow_appshots: allow_appshots .map(|value| Sourced::new(value, RequirementSource::Unknown)), allow_remote_control: allow_remote_control @@ -2341,24 +2339,216 @@ mod tests { } #[test] - fn deserialize_computer_use_requirements() -> Result<()> { + fn deserialize_browser_and_computer_use_requirements() -> Result<()> { let requirements: ConfigRequirementsToml = from_str( r#" + allow_browser_and_computer_use = false + + [browser_use] + allow_history_access = false + disable_auto_review = true + allow_global_persistent_approval = false + + [browser_use.default_origin_policy] + access = "deny" + downloads = "allow" + uploads = "deny" + full_cdp_access = "allow" + auto_review = "deny" + persistent_approval = false + access_approval_lifetime = "turn" + + [browser_use.origins."https://example.com"] + access = "allow" + downloads = "deny" + uploads = "allow" + full_cdp_access = "deny" + auto_review = "deny" + persistent_approval = true + access_approval_lifetime = "thread" + [computer_use] allow_locked_computer_use = false + allow_persistent_approval = false + default_app_access = "deny" + + [computer_use.macos.bundle_ids] + "com.apple.Safari" = "allow" + + [computer_use.windows.aumids] + "Microsoft.Paint_8wekyb3d8bbwe!App" = "allow" + + [[computer_use.windows.exes]] + publisher_name = "CN=Google LLC, O=Google LLC, L=Mountain View, S=California, C=US" + product_name = "Google Chrome" + binary_name = "chrome.exe" + access = "deny" "#, )?; + assert_eq!(requirements.allow_browser_and_computer_use, Some(false)); + assert_eq!( + requirements.browser_use, + Some(BrowserUseRequirementsToml { + allow_history_access: Some(false), + disable_auto_review: Some(true), + allow_global_persistent_approval: Some(false), + default_origin_policy: Some(BrowserUseOriginPolicyToml { + access: Some(AllowDenyRequirementToml::Deny), + downloads: Some(AllowDenyRequirementToml::Allow), + uploads: Some(AllowDenyRequirementToml::Deny), + full_cdp_access: Some(AllowDenyRequirementToml::Allow), + auto_review: Some(AllowDenyRequirementToml::Deny), + persistent_approval: Some(false), + access_approval_lifetime: Some(BrowserUseAccessApprovalLifetimeToml::Turn), + }), + origins: Some(BTreeMap::from([( + "https://example.com".to_string(), + BrowserUseOriginPolicyToml { + access: Some(AllowDenyRequirementToml::Allow), + downloads: Some(AllowDenyRequirementToml::Deny), + uploads: Some(AllowDenyRequirementToml::Allow), + full_cdp_access: Some(AllowDenyRequirementToml::Deny), + auto_review: Some(AllowDenyRequirementToml::Deny), + persistent_approval: Some(true), + access_approval_lifetime: Some( + BrowserUseAccessApprovalLifetimeToml::Thread, + ), + }, + )])), + }) + ); assert_eq!( requirements.computer_use, Some(ComputerUseRequirementsToml { allow_locked_computer_use: Some(false), + allow_persistent_approval: Some(false), + default_app_access: Some(AllowDenyRequirementToml::Deny), + macos: Some(ComputerUseMacosRequirementsToml { + bundle_ids: Some(BTreeMap::from([( + "com.apple.Safari".to_string(), + AllowDenyRequirementToml::Allow, + )])), + }), + windows: Some(ComputerUseWindowsRequirementsToml { + aumids: Some(BTreeMap::from([( + "Microsoft.Paint_8wekyb3d8bbwe!App".to_string(), + AllowDenyRequirementToml::Allow, + )])), + exes: Some(vec![ComputerUseWindowsExeRequirementToml { + publisher_name: + "CN=Google LLC, O=Google LLC, L=Mountain View, S=California, C=US" + .to_string(), + product_name: "Google Chrome".to_string(), + binary_name: Some("chrome.exe".to_string()), + access: AllowDenyRequirementToml::Deny, + }]), + }), }) ); assert!(!requirements.is_empty()); Ok(()) } + #[test] + fn browser_and_computer_use_leaf_requirements_are_not_empty() -> Result<()> { + for (name, requirements_toml) in [ + ( + "browser history", + "[browser_use]\nallow_history_access = false", + ), + ( + "browser auto-review", + "[browser_use]\ndisable_auto_review = true", + ), + ( + "global persistent approval", + "[browser_use]\nallow_global_persistent_approval = false", + ), + ( + "default origin access", + "[browser_use.default_origin_policy]\naccess = \"deny\"", + ), + ( + "default origin downloads", + "[browser_use.default_origin_policy]\ndownloads = \"deny\"", + ), + ( + "default origin uploads", + "[browser_use.default_origin_policy]\nuploads = \"deny\"", + ), + ( + "default origin full CDP access", + "[browser_use.default_origin_policy]\nfull_cdp_access = \"deny\"", + ), + ( + "default origin auto-review", + "[browser_use.default_origin_policy]\nauto_review = \"deny\"", + ), + ( + "default origin persistent approval", + "[browser_use.default_origin_policy]\npersistent_approval = false", + ), + ( + "default origin access approval lifetime", + "[browser_use.default_origin_policy]\naccess_approval_lifetime = \"turn\"", + ), + ( + "origin access", + "[browser_use.origins.\"https://example.com\"]\naccess = \"deny\"", + ), + ( + "origin downloads", + "[browser_use.origins.\"https://example.com\"]\ndownloads = \"deny\"", + ), + ( + "origin uploads", + "[browser_use.origins.\"https://example.com\"]\nuploads = \"deny\"", + ), + ( + "origin full CDP access", + "[browser_use.origins.\"https://example.com\"]\nfull_cdp_access = \"deny\"", + ), + ( + "origin auto-review", + "[browser_use.origins.\"https://example.com\"]\nauto_review = \"deny\"", + ), + ( + "origin persistent approval", + "[browser_use.origins.\"https://example.com\"]\npersistent_approval = false", + ), + ( + "origin access approval lifetime", + "[browser_use.origins.\"https://example.com\"]\naccess_approval_lifetime = \"turn\"", + ), + ( + "computer persistent approval", + "[computer_use]\nallow_persistent_approval = false", + ), + ( + "default app access", + "[computer_use]\ndefault_app_access = \"deny\"", + ), + ( + "macOS bundle identifier", + "[computer_use.macos.bundle_ids]\n\"com.example.App\" = \"deny\"", + ), + ( + "Windows AUMID", + "[computer_use.windows.aumids]\n\"Example.App_123!Main\" = \"deny\"", + ), + ( + "Windows executable", + "[[computer_use.windows.exes]]\npublisher_name = \"CN=Example Corp\"\nproduct_name = \"Example App\"\naccess = \"deny\"", + ), + ] { + let requirements: ConfigRequirementsToml = from_str(requirements_toml)?; + assert!(!requirements.is_empty(), "{name} requirement was dropped"); + } + + Ok(()) + } + #[test] fn deserialize_new_thread_model_defaults() -> Result<()> { let requirements: ConfigRequirementsToml = from_str( @@ -2431,8 +2621,19 @@ mod tests { let feature_requirements = FeatureRequirementsToml { entries: BTreeMap::from([("personality".to_string(), true)]), }; + let browser_use = BrowserUseRequirementsToml { + allow_history_access: Some(false), + disable_auto_review: Some(true), + allow_global_persistent_approval: None, + default_origin_policy: None, + origins: None, + }; let computer_use = ComputerUseRequirementsToml { allow_locked_computer_use: Some(false), + allow_persistent_approval: Some(false), + default_app_access: None, + macos: None, + windows: None, }; let auto_review = AutoReviewRequirementsToml { required_on_models: Some(vec!["managed-model".to_string()]), @@ -2485,10 +2686,11 @@ mod tests { remote_sandbox_config: None, allowed_web_search_modes: Some(allowed_web_search_modes.clone()), allow_managed_hooks_only: Some(true), + allow_browser_and_computer_use: Some(false), allow_appshots: Some(false), allow_remote_control: Some(false), computer_use: Some(computer_use.clone()), - browser_use: None, + browser_use: Some(browser_use.clone()), in_app_browser: None, windows: Some(windows.clone()), feature_requirements: Some(feature_requirements.clone()), @@ -2559,13 +2761,17 @@ mod tests { /*value*/ true, enforce_source.clone(), )), + allow_browser_and_computer_use: Some(Sourced::new( + /*value*/ false, + enforce_source.clone(), + )), allow_appshots: Some(Sourced::new(/*value*/ false, enforce_source.clone(),)), allow_remote_control: Some(Sourced::new( /*value*/ false, enforce_source.clone(), )), computer_use: Some(Sourced::new(computer_use, enforce_source.clone())), - browser_use: None, + browser_use: Some(Sourced::new(browser_use, enforce_source.clone())), in_app_browser: None, windows: Some(Sourced::new(windows, enforce_source.clone())), feature_requirements: Some(Sourced::new( diff --git a/codex-rs/config/src/lib.rs b/codex-rs/config/src/lib.rs index 907bd2c4f6..1913d09058 100644 --- a/codex-rs/config/src/lib.rs +++ b/codex-rs/config/src/lib.rs @@ -1,4 +1,5 @@ mod auth_policy; +mod browser_computer_use_requirements; mod cloud_config_bundle; mod cloud_config_layers; mod config_layer_source; @@ -37,6 +38,14 @@ pub mod types; pub const CONFIG_TOML_FILE: &str = "config.toml"; pub use auth_policy::ManagedAuthPolicy; +pub use browser_computer_use_requirements::AllowDenyRequirementToml; +pub use browser_computer_use_requirements::BrowserUseAccessApprovalLifetimeToml; +pub use browser_computer_use_requirements::BrowserUseOriginPolicyToml; +pub use browser_computer_use_requirements::BrowserUseRequirementsToml; +pub use browser_computer_use_requirements::ComputerUseMacosRequirementsToml; +pub use browser_computer_use_requirements::ComputerUseRequirementsToml; +pub use browser_computer_use_requirements::ComputerUseWindowsExeRequirementToml; +pub use browser_computer_use_requirements::ComputerUseWindowsRequirementsToml; pub use cloud_config_bundle::CloudConfigBundle; pub use cloud_config_bundle::CloudConfigBundleLayers; pub use cloud_config_bundle::CloudConfigBundleLoadError; @@ -69,8 +78,6 @@ pub use config_requirements::AppToolRequirementToml; pub use config_requirements::AppToolsRequirementsToml; pub use config_requirements::AppsRequirementsToml; pub use config_requirements::AutoReviewRequirementsToml; -pub use config_requirements::BrowserUseRequirementsToml; -pub use config_requirements::ComputerUseRequirementsToml; pub use config_requirements::ConfigRequirements; pub use config_requirements::ConfigRequirementsToml; pub use config_requirements::ConfigRequirementsWithSources; diff --git a/codex-rs/config/src/requirements_layers/stack.rs b/codex-rs/config/src/requirements_layers/stack.rs index 9da3fca305..09e3f13cd5 100644 --- a/codex-rs/config/src/requirements_layers/stack.rs +++ b/codex-rs/config/src/requirements_layers/stack.rs @@ -229,6 +229,7 @@ fn populate_merged_regular_fields_with_sources( remote_sandbox_config: _, allowed_web_search_modes, allow_managed_hooks_only, + allow_browser_and_computer_use, allow_appshots, allow_remote_control, computer_use, @@ -277,6 +278,10 @@ fn populate_merged_regular_fields_with_sources( set_sourced!(default_permissions, &["default_permissions"]); set_sourced!(allowed_web_search_modes, &["allowed_web_search_modes"]); set_sourced!(allow_managed_hooks_only, &["allow_managed_hooks_only"]); + set_sourced!( + allow_browser_and_computer_use, + &["allow_browser_and_computer_use"] + ); set_sourced!(allow_appshots, &["allow_appshots"]); set_sourced!(allow_remote_control, &["allow_remote_control"]); set_sourced!(auto_review, &["auto_review"]); diff --git a/codex-rs/config/src/requirements_layers/stack_tests.rs b/codex-rs/config/src/requirements_layers/stack_tests.rs index dadd362bd9..8b784bcff7 100644 --- a/codex-rs/config/src/requirements_layers/stack_tests.rs +++ b/codex-rs/config/src/requirements_layers/stack_tests.rs @@ -609,6 +609,114 @@ fn network_maps_use_regular_toml_merge() { ); } +#[test] +fn browser_and_computer_use_requirements_use_regular_toml_merge() { + let composed = compose(vec![ + layer( + "req_low", + "Low", + r#" +allow_browser_and_computer_use = true + +[browser_use] +allow_history_access = true +allow_global_persistent_approval = true + +[browser_use.default_origin_policy] +access = "allow" +access_approval_lifetime = "thread" + +[browser_use.origins."https://example.com"] +access = "deny" +downloads = "allow" + +[computer_use] +allow_locked_computer_use = true +default_app_access = "allow" + +[computer_use.macos.bundle_ids] +"com.apple.Safari" = "deny" + +[computer_use.windows.aumids] +"Microsoft.Paint_8wekyb3d8bbwe!App" = "allow" +"#, + ), + layer( + "req_high", + "High", + r#" +allow_browser_and_computer_use = false + +[browser_use] +allow_history_access = false +allow_global_persistent_approval = false + +[browser_use.default_origin_policy] +persistent_approval = false +access_approval_lifetime = "turn" + +[browser_use.origins."https://example.com"] +downloads = "deny" +uploads = "deny" + +[computer_use] +allow_persistent_approval = false + +[computer_use.macos.bundle_ids] +"com.apple.Safari" = "allow" + +[[computer_use.windows.exes]] +publisher_name = "CN=Google LLC" +product_name = "Google Chrome" +binary_name = "chrome.exe" +access = "deny" +"#, + ), + ]) + .expect("compose requirements") + .expect("requirements present"); + + assert_eq!( + composed, + expected_requirements( + r#" +allow_browser_and_computer_use = false + +[browser_use] +allow_history_access = false +allow_global_persistent_approval = false + +[browser_use.default_origin_policy] +access = "allow" +persistent_approval = false +access_approval_lifetime = "turn" + +[browser_use.origins."https://example.com"] +access = "deny" +downloads = "deny" +uploads = "deny" + +[computer_use] +allow_locked_computer_use = true +allow_persistent_approval = false +default_app_access = "allow" + +[computer_use.macos.bundle_ids] +"com.apple.Safari" = "allow" + +[computer_use.windows.aumids] +"Microsoft.Paint_8wekyb3d8bbwe!App" = "allow" + +[[computer_use.windows.exes]] +publisher_name = "CN=Google LLC" +product_name = "Google Chrome" +binary_name = "chrome.exe" +access = "deny" +"# + ) + ); +} + #[test] fn windows_requirements_use_regular_toml_merge() { let composed = compose(vec![ diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 56afc33648..b02140c861 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -9886,6 +9886,7 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset() allow_managed_hooks_only: None, allow_appshots: None, allow_remote_control: None, + allow_browser_and_computer_use: None, computer_use: None, browser_use: None, in_app_browser: None, diff --git a/codex-rs/tui/src/debug_config.rs b/codex-rs/tui/src/debug_config.rs index e0d76deb01..1564d36606 100644 --- a/codex-rs/tui/src/debug_config.rs +++ b/codex-rs/tui/src/debug_config.rs @@ -953,6 +953,7 @@ interrupt_message = false allow_managed_hooks_only: Some(true), allow_appshots: Some(false), allow_remote_control: Some(false), + allow_browser_and_computer_use: None, computer_use: None, browser_use: None, in_app_browser: None,