fix: Revert danger-full-access denylist-only mode (#17732)

## Summary

- Reverts openai/codex#16946 and removes the danger-full-access
denylist-only network mode.
- Removes the corresponding config requirements, app-server
protocol/schema, config API, TUI debug output, and network proxy
behavior.
- Drops stale tests that depended on the reverted mode while preserving
newer managed allowlist-only coverage.

## Verification

- `just write-app-server-schema`
- `just fmt`
- `cargo test -p codex-config network_requirements`
- `cargo test -p codex-core network_proxy_spec`
- `cargo test -p codex-core
managed_network_proxy_decider_survives_full_access_start`
- `cargo test -p codex-app-server map_requirements_toml_to_api`
- `cargo test -p codex-tui debug_config_output`
- `cargo test -p codex-app-server-protocol`
- `just fix -p codex-config -p codex-core -p codex-app-server-protocol
-p codex-app-server -p codex-tui`
- `git diff --cached --check`

Not run: full workspace `cargo test` (repo instructions ask for
confirmation before that broader run).
This commit is contained in:
viyatb-oai
2026-04-14 09:50:14 -07:00
committed by GitHub
Unverified
parent b3ae531b3a
commit 81c0bcc921
17 changed files with 60 additions and 384 deletions
+1 -1
View File
@@ -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}"
@@ -9829,12 +9829,6 @@
"null"
]
},
"dangerFullAccessDenylistOnly": {
"type": [
"boolean",
"null"
]
},
"dangerouslyAllowAllUnixSockets": {
"type": [
"boolean",
@@ -6605,12 +6605,6 @@
"null"
]
},
"dangerFullAccessDenylistOnly": {
"type": [
"boolean",
"null"
]
},
"dangerouslyAllowAllUnixSockets": {
"type": [
"boolean",
@@ -151,12 +151,6 @@
"null"
]
},
"dangerFullAccessDenylistOnly": {
"type": [
"boolean",
"null"
]
},
"dangerouslyAllowAllUnixSockets": {
"type": [
"boolean",
@@ -29,4 +29,4 @@ unixSockets: { [key in string]?: NetworkUnixSocketPermission } | null,
/**
* Legacy compatibility view derived from `unix_sockets`.
*/
allowUnixSockets: Array<string> | null, allowLocalBinding: boolean | null, dangerFullAccessDenylistOnly: boolean | null, };
allowUnixSockets: Array<string> | null, allowLocalBinding: boolean | null, };
@@ -899,7 +899,6 @@ pub struct NetworkRequirements {
/// Legacy compatibility view derived from `unix_sockets`.
pub allow_unix_sockets: Option<Vec<String>>,
pub allow_local_binding: Option<bool>,
pub danger_full_access_denylist_only: Option<bool>,
}
#[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": {
+1 -1
View File
@@ -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
-5
View File
@@ -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([(
@@ -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<bool>,
/// In danger-full-access mode, allow all network access and enforce managed deny entries.
pub danger_full_access_denylist_only: Option<bool>,
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
pub allow_local_binding: Option<bool>,
}
@@ -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<bool>,
/// In danger-full-access mode, allow all network access and enforce managed deny entries.
danger_full_access_denylist_only: Option<bool>,
#[serde(default)]
denied_domains: Option<Vec<String>>,
unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
@@ -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<bool>,
/// In danger-full-access mode, allow all network access and enforce managed deny entries.
pub danger_full_access_denylist_only: Option<bool>,
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
pub allow_local_binding: Option<bool>,
}
@@ -392,7 +384,6 @@ impl From<NetworkRequirementsToml> 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<NetworkRequirementsToml> 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 {
-66
View File
@@ -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,
+27 -55
View File
@@ -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,
@@ -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<Item = (&'static str, NetworkDomainPermissionToml)>,
@@ -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();
@@ -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
);
+15 -9
View File
@@ -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<String> = 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");
+1 -1
View File
@@ -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)))
@@ -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) {
+1 -8
View File
@@ -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:"));
}