diff --git a/.github/scripts/run-bazel-ci.sh b/.github/scripts/run-bazel-ci.sh index 9c95fda15..fefca90b3 100755 --- a/.github/scripts/run-bazel-ci.sh +++ b/.github/scripts/run-bazel-ci.sh @@ -92,7 +92,7 @@ print_bazel_test_log_tails() { for target in "${failed_targets[@]}"; do local rel_path="${target#//}" - rel_path="${rel_path/:/\/}" + rel_path="${rel_path/://}" local test_log="${testlogs_dir}/${rel_path}/test.log" echo "::group::Bazel test log tail for ${target}" 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 5ecdb5a5c..ec3db7494 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 @@ -9829,12 +9829,6 @@ "null" ] }, - "dangerFullAccessDenylistOnly": { - "type": [ - "boolean", - "null" - ] - }, "dangerouslyAllowAllUnixSockets": { "type": [ "boolean", diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index a37456c86..9294e533f 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -6605,12 +6605,6 @@ "null" ] }, - "dangerFullAccessDenylistOnly": { - "type": [ - "boolean", - "null" - ] - }, "dangerouslyAllowAllUnixSockets": { "type": [ "boolean", diff --git a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json index ae6eb1dc7..614575a95 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json @@ -151,12 +151,6 @@ "null" ] }, - "dangerFullAccessDenylistOnly": { - "type": [ - "boolean", - "null" - ] - }, "dangerouslyAllowAllUnixSockets": { "type": [ "boolean", diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/NetworkRequirements.ts b/codex-rs/app-server-protocol/schema/typescript/v2/NetworkRequirements.ts index d1cd1ab29..04e07ef1d 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/NetworkRequirements.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/NetworkRequirements.ts @@ -29,4 +29,4 @@ unixSockets: { [key in string]?: NetworkUnixSocketPermission } | null, /** * Legacy compatibility view derived from `unix_sockets`. */ -allowUnixSockets: Array | null, allowLocalBinding: boolean | null, dangerFullAccessDenylistOnly: boolean | null, }; +allowUnixSockets: Array | null, allowLocalBinding: boolean | null, }; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 4f8d9f121..6144ac290 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -899,7 +899,6 @@ pub struct NetworkRequirements { /// Legacy compatibility view derived from `unix_sockets`. pub allow_unix_sockets: Option>, pub allow_local_binding: Option, - pub danger_full_access_denylist_only: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] @@ -8103,7 +8102,6 @@ mod tests { dangerously_allow_all_unix_sockets: None, domains: None, managed_allowed_domains_only: None, - danger_full_access_denylist_only: None, allowed_domains: Some(vec!["api.openai.com".to_string()]), denied_domains: Some(vec!["blocked.example.com".to_string()]), unix_sockets: None, @@ -8130,7 +8128,6 @@ mod tests { ), ])), managed_allowed_domains_only: Some(true), - danger_full_access_denylist_only: Some(true), allowed_domains: Some(vec!["api.openai.com".to_string()]), denied_domains: Some(vec!["blocked.example.com".to_string()]), unix_sockets: Some(BTreeMap::from([ @@ -8161,7 +8158,6 @@ mod tests { "blocked.example.com": "deny" }, "managedAllowedDomainsOnly": true, - "dangerFullAccessDenylistOnly": true, "allowedDomains": ["api.openai.com"], "deniedDomains": ["blocked.example.com"], "unixSockets": { diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 6337fe1f0..9715db92f 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -200,7 +200,7 @@ Example with notification opt-out: - `externalAgentConfig/import` — apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home). - `config/value/write` — write a single config key/value to the user's config.toml on disk. - `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk, with optional `reloadUserConfig: true` to hot-reload loaded threads. -- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), pinned feature values (`featureRequirements`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`. +- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), pinned feature values (`featureRequirements`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly`. ### Example: Start or resume a thread diff --git a/codex-rs/app-server/src/config_api.rs b/codex-rs/app-server/src/config_api.rs index 7c39f1c44..4d0b450d7 100644 --- a/codex-rs/app-server/src/config_api.rs +++ b/codex-rs/app-server/src/config_api.rs @@ -452,7 +452,6 @@ fn map_network_requirements_to_api( .collect() }), managed_allowed_domains_only: network.managed_allowed_domains_only, - danger_full_access_denylist_only: network.danger_full_access_denylist_only, allowed_domains, denied_domains, unix_sockets: network.unix_sockets.map(|unix_sockets| { @@ -598,7 +597,6 @@ mod tests { ]), }), managed_allowed_domains_only: Some(false), - danger_full_access_denylist_only: Some(true), unix_sockets: Some(CoreNetworkUnixSocketPermissionsToml { entries: std::collections::BTreeMap::from([( "/tmp/proxy.sock".to_string(), @@ -658,7 +656,6 @@ mod tests { ("example.com".to_string(), NetworkDomainPermission::Deny), ])), managed_allowed_domains_only: Some(false), - danger_full_access_denylist_only: Some(true), allowed_domains: Some(vec!["api.openai.com".to_string()]), denied_domains: Some(vec!["example.com".to_string()]), unix_sockets: Some(std::collections::BTreeMap::from([( @@ -693,7 +690,6 @@ mod tests { dangerously_allow_all_unix_sockets: None, domains: None, managed_allowed_domains_only: None, - danger_full_access_denylist_only: None, unix_sockets: Some(CoreNetworkUnixSocketPermissionsToml { entries: std::collections::BTreeMap::from([( "/tmp/ignored.sock".to_string(), @@ -717,7 +713,6 @@ mod tests { dangerously_allow_all_unix_sockets: None, domains: None, managed_allowed_domains_only: None, - danger_full_access_denylist_only: None, allowed_domains: None, denied_domains: None, unix_sockets: Some(std::collections::BTreeMap::from([( diff --git a/codex-rs/config/src/config_requirements.rs b/codex-rs/config/src/config_requirements.rs index 2e6756d81..7abedc62f 100644 --- a/codex-rs/config/src/config_requirements.rs +++ b/codex-rs/config/src/config_requirements.rs @@ -237,8 +237,6 @@ pub struct NetworkRequirementsToml { /// When true, only managed `allowed_domains` are respected while managed /// network enforcement is active. User allowlist entries are ignored. pub managed_allowed_domains_only: Option, - /// In danger-full-access mode, allow all network access and enforce managed deny entries. - pub danger_full_access_denylist_only: Option, pub unix_sockets: Option, pub allow_local_binding: Option, } @@ -257,8 +255,6 @@ struct RawNetworkRequirementsToml { /// When true, only managed `allowed_domains` are respected while managed /// network enforcement is active. User allowlist entries are ignored. managed_allowed_domains_only: Option, - /// In danger-full-access mode, allow all network access and enforce managed deny entries. - danger_full_access_denylist_only: Option, #[serde(default)] denied_domains: Option>, unix_sockets: Option, @@ -283,7 +279,6 @@ impl<'de> Deserialize<'de> for NetworkRequirementsToml { domains, allowed_domains, managed_allowed_domains_only, - danger_full_access_denylist_only, denied_domains, unix_sockets, allow_unix_sockets, @@ -312,7 +307,6 @@ impl<'de> Deserialize<'de> for NetworkRequirementsToml { domains: domains .or_else(|| legacy_domain_permissions_from_lists(allowed_domains, denied_domains)), managed_allowed_domains_only, - danger_full_access_denylist_only, unix_sockets: unix_sockets .or_else(|| legacy_unix_socket_permissions_from_list(allow_unix_sockets)), allow_local_binding, @@ -365,8 +359,6 @@ pub struct NetworkConstraints { /// When true, only managed `allowed_domains` are respected while managed /// network enforcement is active. User allowlist entries are ignored. pub managed_allowed_domains_only: Option, - /// In danger-full-access mode, allow all network access and enforce managed deny entries. - pub danger_full_access_denylist_only: Option, pub unix_sockets: Option, pub allow_local_binding: Option, } @@ -392,7 +384,6 @@ impl From for NetworkConstraints { dangerously_allow_all_unix_sockets, domains, managed_allowed_domains_only, - danger_full_access_denylist_only, unix_sockets, allow_local_binding, } = value; @@ -405,7 +396,6 @@ impl From for NetworkConstraints { dangerously_allow_all_unix_sockets, domains, managed_allowed_domains_only, - danger_full_access_denylist_only, unix_sockets, allow_local_binding, } @@ -1811,7 +1801,6 @@ allowed_approvals_reviewers = ["user"] allow_upstream_proxy = false dangerously_allow_all_unix_sockets = true managed_allowed_domains_only = true - danger_full_access_denylist_only = true allow_local_binding = false [experimental_network.domains] @@ -1862,10 +1851,6 @@ allowed_approvals_reviewers = ["user"] sourced_network.value.managed_allowed_domains_only, Some(true) ); - assert_eq!( - sourced_network.value.danger_full_access_denylist_only, - Some(true) - ); assert_eq!( sourced_network.value.unix_sockets.as_ref(), Some(&NetworkUnixSocketPermissionsToml { @@ -1889,7 +1874,6 @@ allowed_approvals_reviewers = ["user"] dangerously_allow_all_unix_sockets = true allowed_domains = ["api.example.com", "*.openai.com"] managed_allowed_domains_only = true - danger_full_access_denylist_only = true denied_domains = ["blocked.example.com"] allow_unix_sockets = ["/tmp/example.sock"] allow_local_binding = false @@ -1934,10 +1918,6 @@ allowed_approvals_reviewers = ["user"] sourced_network.value.managed_allowed_domains_only, Some(true) ); - assert_eq!( - sourced_network.value.danger_full_access_denylist_only, - Some(true) - ); assert_eq!( sourced_network.value.unix_sockets.as_ref(), Some(&NetworkUnixSocketPermissionsToml { diff --git a/codex-rs/core/src/codex_tests.rs b/codex-rs/core/src/codex_tests.rs index 19ee45f41..25a72d3bb 100644 --- a/codex-rs/core/src/codex_tests.rs +++ b/codex-rs/core/src/codex_tests.rs @@ -588,78 +588,12 @@ async fn start_managed_network_proxy_ignores_invalid_execpolicy_network_rules() Ok(()) } -#[tokio::test] -async fn managed_network_proxy_refreshes_when_sandbox_policy_changes() -> anyhow::Result<()> { - let spec = crate::config::NetworkProxySpec::from_config_and_constraints( - NetworkProxyConfig::default(), - Some(NetworkConstraints { - domains: Some(NetworkDomainPermissionsToml { - entries: std::collections::BTreeMap::from([( - "blocked.example.com".to_string(), - NetworkDomainPermissionToml::Deny, - )]), - }), - danger_full_access_denylist_only: Some(true), - allow_local_binding: Some(false), - ..Default::default() - }), - &SandboxPolicy::new_workspace_write_policy(), - )?; - let exec_policy = Policy::empty(); - - let (started_proxy, _) = Session::start_managed_network_proxy( - &spec, - &exec_policy, - &SandboxPolicy::new_workspace_write_policy(), - /*network_policy_decider*/ None, - /*blocked_request_observer*/ None, - /*managed_network_requirements_enabled*/ false, - crate::config::NetworkProxyAuditMetadata::default(), - ) - .await?; - - assert!(!started_proxy.proxy().allow_local_binding()); - let current_cfg = started_proxy.proxy().current_cfg().await?; - assert_eq!(current_cfg.network.allowed_domains(), None); - assert_eq!( - current_cfg.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - - let spec = spec.recompute_for_sandbox_policy(&SandboxPolicy::DangerFullAccess)?; - spec.apply_to_started_proxy(&started_proxy).await?; - - assert!(started_proxy.proxy().allow_local_binding()); - let current_cfg = started_proxy.proxy().current_cfg().await?; - assert_eq!( - current_cfg.network.allowed_domains(), - Some(vec!["*".to_string()]) - ); - assert_eq!( - current_cfg.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - - let spec = spec.recompute_for_sandbox_policy(&SandboxPolicy::new_workspace_write_policy())?; - spec.apply_to_started_proxy(&started_proxy).await?; - - assert!(!started_proxy.proxy().allow_local_binding()); - let current_cfg = started_proxy.proxy().current_cfg().await?; - assert_eq!(current_cfg.network.allowed_domains(), None); - assert_eq!( - current_cfg.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - Ok(()) -} - #[tokio::test] async fn managed_network_proxy_decider_survives_full_access_start() -> anyhow::Result<()> { let spec = crate::config::NetworkProxySpec::from_config_and_constraints( NetworkProxyConfig::default(), Some(NetworkConstraints { enabled: Some(true), - danger_full_access_denylist_only: Some(true), ..Default::default() }), &SandboxPolicy::DangerFullAccess, diff --git a/codex-rs/core/src/config/network_proxy_spec.rs b/codex-rs/core/src/config/network_proxy_spec.rs index b67c41a44..acabe24f2 100644 --- a/codex-rs/core/src/config/network_proxy_spec.rs +++ b/codex-rs/core/src/config/network_proxy_spec.rs @@ -20,8 +20,6 @@ use codex_protocol::protocol::SandboxPolicy; use std::collections::HashSet; use std::sync::Arc; -const GLOBAL_ALLOWLIST_PATTERN: &str = "*"; - #[derive(Debug, Clone, PartialEq, Eq)] pub struct NetworkProxySpec { base_config: NetworkProxyConfig, @@ -225,8 +223,6 @@ impl NetworkProxySpec { let allowlist_expansion_enabled = Self::allowlist_expansion_enabled(sandbox_policy, hard_deny_allowlist_misses); let denylist_expansion_enabled = Self::denylist_expansion_enabled(sandbox_policy); - let danger_full_access_denylist_only = - Self::danger_full_access_denylist_only_enabled(requirements, sandbox_policy); if let Some(enabled) = requirements.enabled { config.network.enabled = enabled; @@ -257,43 +253,37 @@ impl NetworkProxySpec { constraints.dangerously_allow_all_unix_sockets = Some(dangerously_allow_all_unix_sockets); } - if danger_full_access_denylist_only { - config - .network - .set_allowed_domains(vec![GLOBAL_ALLOWLIST_PATTERN.to_string()]); - } else { - let managed_allowed_domains = if hard_deny_allowlist_misses { - Some( - requirements - .domains - .as_ref() - .and_then(codex_config::NetworkDomainPermissionsToml::allowed_domains) - .unwrap_or_default(), - ) - } else { + let managed_allowed_domains = if hard_deny_allowlist_misses { + Some( requirements .domains .as_ref() .and_then(codex_config::NetworkDomainPermissionsToml::allowed_domains) + .unwrap_or_default(), + ) + } else { + requirements + .domains + .as_ref() + .and_then(codex_config::NetworkDomainPermissionsToml::allowed_domains) + }; + if let Some(managed_allowed_domains) = managed_allowed_domains { + // Managed requirements seed the baseline allowlist. User additions + // can extend that baseline unless managed-only mode pins the + // effective allowlist to the managed set. + let effective_allowed_domains = if allowlist_expansion_enabled { + Self::merge_domain_lists( + managed_allowed_domains.clone(), + config.network.allowed_domains().as_deref().unwrap_or(&[]), + ) + } else { + managed_allowed_domains.clone() }; - if let Some(managed_allowed_domains) = managed_allowed_domains { - // Managed requirements seed the baseline allowlist. User additions - // can extend that baseline unless managed-only mode pins the - // effective allowlist to the managed set. - let effective_allowed_domains = if allowlist_expansion_enabled { - Self::merge_domain_lists( - managed_allowed_domains.clone(), - config.network.allowed_domains().as_deref().unwrap_or(&[]), - ) - } else { - managed_allowed_domains.clone() - }; - config - .network - .set_allowed_domains(effective_allowed_domains); - constraints.allowed_domains = Some(managed_allowed_domains); - constraints.allowlist_expansion_enabled = Some(allowlist_expansion_enabled); - } + config + .network + .set_allowed_domains(effective_allowed_domains); + constraints.allowed_domains = Some(managed_allowed_domains); + constraints.allowlist_expansion_enabled = Some(allowlist_expansion_enabled); } let managed_denied_domains = requirements .domains @@ -312,7 +302,7 @@ impl NetworkProxySpec { constraints.denied_domains = Some(managed_denied_domains); constraints.denylist_expansion_enabled = Some(denylist_expansion_enabled); } - if requirements.unix_sockets.is_some() && !danger_full_access_denylist_only { + if requirements.unix_sockets.is_some() { let allow_unix_sockets = requirements .unix_sockets .as_ref() @@ -327,14 +317,6 @@ impl NetworkProxySpec { config.network.allow_local_binding = allow_local_binding; constraints.allow_local_binding = Some(allow_local_binding); } - if danger_full_access_denylist_only { - config.network.allow_upstream_proxy = true; - constraints.allow_upstream_proxy = Some(true); - config.network.dangerously_allow_all_unix_sockets = true; - constraints.dangerously_allow_all_unix_sockets = Some(true); - config.network.allow_local_binding = true; - constraints.allow_local_binding = Some(true); - } (config, constraints) } @@ -353,16 +335,6 @@ impl NetworkProxySpec { requirements.managed_allowed_domains_only.unwrap_or(false) } - fn danger_full_access_denylist_only_enabled( - requirements: &NetworkConstraints, - sandbox_policy: &SandboxPolicy, - ) -> bool { - matches!(sandbox_policy, SandboxPolicy::DangerFullAccess) - && requirements - .danger_full_access_denylist_only - .unwrap_or(false) - } - fn denylist_expansion_enabled(sandbox_policy: &SandboxPolicy) -> bool { matches!( sandbox_policy, diff --git a/codex-rs/core/src/config/network_proxy_spec_tests.rs b/codex-rs/core/src/config/network_proxy_spec_tests.rs index ff351d1e7..5ba4bd153 100644 --- a/codex-rs/core/src/config/network_proxy_spec_tests.rs +++ b/codex-rs/core/src/config/network_proxy_spec_tests.rs @@ -1,11 +1,8 @@ use super::*; use crate::config_loader::NetworkDomainPermissionToml; use crate::config_loader::NetworkDomainPermissionsToml; -use crate::config_loader::NetworkUnixSocketPermissionToml; -use crate::config_loader::NetworkUnixSocketPermissionsToml; use codex_network_proxy::NetworkDomainPermission; use pretty_assertions::assert_eq; -use std::collections::BTreeMap; fn domain_permissions( entries: impl IntoIterator, @@ -183,196 +180,6 @@ fn danger_full_access_keeps_managed_allowlist_and_denylist_fixed() { assert_eq!(spec.constraints.denylist_expansion_enabled, Some(false)); } -#[test] -fn danger_full_access_denylist_only_allows_all_domains_and_enforces_managed_denies() { - let mut config = NetworkProxyConfig::default(); - config - .network - .set_allowed_domains(vec!["evil.com".to_string()]); - config - .network - .set_denied_domains(vec!["more-blocked.example.com".to_string()]); - let requirements = NetworkConstraints { - allow_upstream_proxy: Some(false), - dangerously_allow_all_unix_sockets: Some(false), - domains: Some(domain_permissions([ - ("*.example.com", NetworkDomainPermissionToml::Allow), - ("blocked.example.com", NetworkDomainPermissionToml::Deny), - ])), - danger_full_access_denylist_only: Some(true), - unix_sockets: Some(NetworkUnixSocketPermissionsToml { - entries: BTreeMap::from([( - "/tmp/managed.sock".to_string(), - NetworkUnixSocketPermissionToml::Allow, - )]), - }), - allow_local_binding: Some(false), - ..Default::default() - }; - - let spec = NetworkProxySpec::from_config_and_constraints( - config, - Some(requirements), - &SandboxPolicy::DangerFullAccess, - ) - .expect("denylist-only yolo mode should allow all domains except managed denies"); - - assert_eq!( - spec.config.network.allowed_domains(), - Some(vec!["*".to_string()]) - ); - assert_eq!( - spec.config.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - assert!(spec.config.network.allow_upstream_proxy); - assert!(spec.config.network.dangerously_allow_all_unix_sockets); - assert!(spec.config.network.allow_local_binding); - assert_eq!(spec.constraints.allow_upstream_proxy, Some(true)); - assert_eq!( - spec.constraints.dangerously_allow_all_unix_sockets, - Some(true) - ); - assert_eq!(spec.constraints.allow_unix_sockets, None); - assert_eq!(spec.constraints.allow_local_binding, Some(true)); - assert_eq!(spec.constraints.allowed_domains, None); - assert_eq!(spec.constraints.allowlist_expansion_enabled, None); - assert_eq!( - spec.constraints.denied_domains, - Some(vec!["blocked.example.com".to_string()]) - ); - assert_eq!(spec.constraints.denylist_expansion_enabled, Some(false)); -} - -#[test] -fn danger_full_access_denylist_only_does_not_change_workspace_write_behavior() { - let mut config = NetworkProxyConfig::default(); - config - .network - .set_allowed_domains(vec!["api.example.com".to_string()]); - config - .network - .set_denied_domains(vec!["blocked.example.com".to_string()]); - let requirements = NetworkConstraints { - allow_upstream_proxy: Some(false), - dangerously_allow_all_unix_sockets: Some(false), - domains: Some(domain_permissions([ - ("*.example.com", NetworkDomainPermissionToml::Allow), - ( - "managed-blocked.example.com", - NetworkDomainPermissionToml::Deny, - ), - ])), - danger_full_access_denylist_only: Some(true), - unix_sockets: Some(NetworkUnixSocketPermissionsToml { - entries: BTreeMap::from([( - "/tmp/managed.sock".to_string(), - NetworkUnixSocketPermissionToml::Allow, - )]), - }), - allow_local_binding: Some(false), - ..Default::default() - }; - - let spec = NetworkProxySpec::from_config_and_constraints( - config, - Some(requirements), - &SandboxPolicy::new_workspace_write_policy(), - ) - .expect("denylist-only yolo flag should not affect workspace-write mode"); - - assert_eq!( - spec.config.network.allowed_domains(), - Some(vec![ - "*.example.com".to_string(), - "api.example.com".to_string() - ]) - ); - assert_eq!( - spec.config.network.denied_domains(), - Some(vec![ - "managed-blocked.example.com".to_string(), - "blocked.example.com".to_string() - ]) - ); - assert!(!spec.config.network.allow_upstream_proxy); - assert!(!spec.config.network.dangerously_allow_all_unix_sockets); - assert_eq!( - spec.config.network.allow_unix_sockets(), - vec!["/tmp/managed.sock".to_string()] - ); - assert!(!spec.config.network.allow_local_binding); - assert_eq!(spec.constraints.allow_upstream_proxy, Some(false)); - assert_eq!( - spec.constraints.dangerously_allow_all_unix_sockets, - Some(false) - ); - assert_eq!( - spec.constraints.allow_unix_sockets, - Some(vec!["/tmp/managed.sock".to_string()]) - ); - assert_eq!(spec.constraints.allow_local_binding, Some(false)); - assert_eq!( - spec.constraints.allowed_domains, - Some(vec!["*.example.com".to_string()]) - ); - assert_eq!(spec.constraints.allowlist_expansion_enabled, Some(true)); - assert_eq!( - spec.constraints.denied_domains, - Some(vec!["managed-blocked.example.com".to_string()]) - ); - assert_eq!(spec.constraints.denylist_expansion_enabled, Some(true)); -} - -#[test] -fn recompute_for_sandbox_policy_rebuilds_denylist_only_full_access_policy() { - let requirements = NetworkConstraints { - domains: Some(domain_permissions([( - "blocked.example.com", - NetworkDomainPermissionToml::Deny, - )])), - danger_full_access_denylist_only: Some(true), - ..Default::default() - }; - let spec = NetworkProxySpec::from_config_and_constraints( - NetworkProxyConfig::default(), - Some(requirements), - &SandboxPolicy::new_workspace_write_policy(), - ) - .expect("workspace-write policy should load"); - - assert_eq!(spec.config.network.allowed_domains(), None); - assert_eq!( - spec.config.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - - let spec = spec - .recompute_for_sandbox_policy(&SandboxPolicy::DangerFullAccess) - .expect("full-access policy should load"); - - assert_eq!( - spec.config.network.allowed_domains(), - Some(vec!["*".to_string()]) - ); - assert_eq!( - spec.config.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - assert!(spec.config.network.allow_local_binding); - - let spec = spec - .recompute_for_sandbox_policy(&SandboxPolicy::new_workspace_write_policy()) - .expect("workspace-write policy should reload"); - - assert_eq!(spec.config.network.allowed_domains(), None); - assert_eq!( - spec.config.network.denied_domains(), - Some(vec!["blocked.example.com".to_string()]) - ); - assert!(!spec.config.network.allow_local_binding); -} - #[test] fn managed_allowed_domains_only_disables_default_mode_allowlist_expansion() { let mut config = NetworkProxyConfig::default(); diff --git a/codex-rs/core/src/plugins/discoverable_tests.rs b/codex-rs/core/src/plugins/discoverable_tests.rs index b1d0d79e2..a0fc3fb28 100644 --- a/codex-rs/core/src/plugins/discoverable_tests.rs +++ b/codex-rs/core/src/plugins/discoverable_tests.rs @@ -201,13 +201,16 @@ async fn list_tool_suggest_discoverable_plugins_does_not_reload_marketplace_per_ let logs = String::from_utf8(buffer.lock().expect("buffer lock").clone()).expect("utf8 logs"); assert_eq!(logs.matches("ignoring interface.defaultPrompt").count(), 2); + let normalized_logs = logs.replace('\\', "/"); assert_eq!( - logs.matches("build-ios-apps/.codex-plugin/plugin.json") + normalized_logs + .matches("build-ios-apps/.codex-plugin/plugin.json") .count(), 1 ); assert_eq!( - logs.matches("life-science-research/.codex-plugin/plugin.json") + normalized_logs + .matches("life-science-research/.codex-plugin/plugin.json") .count(), 1 ); diff --git a/codex-rs/core/tests/suite/apply_patch_cli.rs b/codex-rs/core/tests/suite/apply_patch_cli.rs index 4882bcd11..cb264a0b2 100644 --- a/codex-rs/core/tests/suite/apply_patch_cli.rs +++ b/codex-rs/core/tests/suite/apply_patch_cli.rs @@ -10,6 +10,7 @@ use core_test_support::test_codex::ApplyPatchModelOutput; use pretty_assertions::assert_eq; use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering; +use std::time::Duration; use codex_features::Feature; use codex_protocol::protocol::AskForApproval; @@ -34,6 +35,7 @@ use core_test_support::test_codex::TestCodexBuilder; use core_test_support::test_codex::TestCodexHarness; use core_test_support::test_codex::test_codex; use core_test_support::wait_for_event; +use core_test_support::wait_for_event_with_timeout; use serde_json::json; use test_case::test_case; use wiremock::Mock; @@ -950,7 +952,7 @@ async fn apply_patch_shell_command_heredoc_with_cd_emits_turn_diff() -> Result<( let script = "cd sub && apply_patch <<'EOF'\n*** Begin Patch\n*** Update File: in_sub.txt\n@@\n-before\n+after\n*** End Patch\nEOF\n"; let call_id = "shell-heredoc-cd"; - let args = json!({ "command": script, "timeout_ms": 5_000 }); + let args = json!({ "command": script, "timeout_ms": 30_000 }); let bodies = vec![ sse(vec![ ev_response_created("resp-1"), @@ -1444,14 +1446,18 @@ async fn apply_patch_aggregates_diff_preserves_success_after_failure() -> Result .await?; let mut last_diff: Option = None; - wait_for_event(&codex, |event| match event { - EventMsg::TurnDiff(ev) => { - last_diff = Some(ev.unified_diff.clone()); - false - } - EventMsg::TurnComplete(_) => true, - _ => false, - }) + wait_for_event_with_timeout( + &codex, + |event| match event { + EventMsg::TurnDiff(ev) => { + last_diff = Some(ev.unified_diff.clone()); + false + } + EventMsg::TurnComplete(_) => true, + _ => false, + }, + Duration::from_secs(30), + ) .await; let diff = last_diff.expect("expected TurnDiff after failed patch"); diff --git a/codex-rs/core/tests/suite/approvals.rs b/codex-rs/core/tests/suite/approvals.rs index f7874eaf4..84066ff6e 100644 --- a/codex-rs/core/tests/suite/approvals.rs +++ b/codex-rs/core/tests/suite/approvals.rs @@ -229,7 +229,7 @@ impl ActionKind { let event = shell_event( call_id, &command, - /*timeout_ms*/ 5_000, + /*timeout_ms*/ 30_000, sandbox_permissions, )?; Ok((event, Some(command))) diff --git a/codex-rs/core/tests/suite/pending_input.rs b/codex-rs/core/tests/suite/pending_input.rs index 719cc1f0a..2376da3d6 100644 --- a/codex-rs/core/tests/suite/pending_input.rs +++ b/codex-rs/core/tests/suite/pending_input.rs @@ -157,6 +157,14 @@ async fn submit_queue_only_agent_mail(codex: &CodexThread, text: &str) { }) .await .unwrap_or_else(|err| panic!("submit queue-only agent mail: {err}")); + codex + .submit(Op::ListMcpTools) + .await + .unwrap_or_else(|err| panic!("submit list-mcp-tools barrier: {err}")); + wait_for_event(codex, |event| { + matches!(event, EventMsg::McpListToolsResponse(_)) + }) + .await; } async fn wait_for_reasoning_item_started(codex: &CodexThread) { diff --git a/codex-rs/tui/src/debug_config.rs b/codex-rs/tui/src/debug_config.rs index aa9526c4e..16af4c24f 100644 --- a/codex-rs/tui/src/debug_config.rs +++ b/codex-rs/tui/src/debug_config.rs @@ -367,7 +367,6 @@ fn format_network_constraints(network: &NetworkConstraints) -> String { dangerously_allow_all_unix_sockets, domains, managed_allowed_domains_only, - danger_full_access_denylist_only, unix_sockets, allow_local_binding, } = network; @@ -405,11 +404,6 @@ fn format_network_constraints(network: &NetworkConstraints) -> String { "managed_allowed_domains_only={managed_allowed_domains_only}" )); } - if let Some(danger_full_access_denylist_only) = danger_full_access_denylist_only { - parts.push(format!( - "danger_full_access_denylist_only={danger_full_access_denylist_only}" - )); - } if let Some(unix_sockets) = unix_sockets { parts.push(format!( "unix_sockets={}", @@ -605,7 +599,6 @@ mod tests { NetworkDomainPermissionToml::Allow, )]), }), - danger_full_access_denylist_only: Some(true), ..Default::default() }, RequirementSource::CloudRequirements, @@ -676,7 +669,7 @@ mod tests { assert!(rendered.contains("mcp_servers: docs (source: MDM managed_config.toml (legacy))")); assert!(rendered.contains("enforce_residency: us (source: cloud requirements)")); assert!(rendered.contains( - "experimental_network: enabled=true, domains={example.com=allow}, danger_full_access_denylist_only=true (source: cloud requirements)" + "experimental_network: enabled=true, domains={example.com=allow} (source: cloud requirements)" )); assert!(!rendered.contains(" - rules:")); }