diff --git a/codex-rs/core/src/guardian/review_session.rs b/codex-rs/core/src/guardian/review_session.rs index 7aea5978f..5bb3e9d1b 100644 --- a/codex-rs/core/src/guardian/review_session.rs +++ b/codex-rs/core/src/guardian/review_session.rs @@ -732,6 +732,13 @@ pub(crate) fn build_guardian_review_session_config( guardian_config.permissions.approval_policy = Constrained::allow_only(AskForApproval::Never); guardian_config.permissions.sandbox_policy = Constrained::allow_only(SandboxPolicy::new_read_only_policy()); + guardian_config.include_apps_instructions = false; + guardian_config + .mcp_servers + .set(HashMap::new()) + .map_err(|err| { + anyhow::anyhow!("guardian review session could not clear MCP servers: {err}") + })?; if let Some(live_network_config) = live_network_config && guardian_config.permissions.network.is_some() { @@ -751,6 +758,8 @@ pub(crate) fn build_guardian_review_session_config( Feature::SpawnCsv, Feature::Collab, Feature::CodexHooks, + Feature::Apps, + Feature::Plugins, Feature::WebSearchRequest, Feature::WebSearchCached, ] { diff --git a/codex-rs/core/src/guardian/tests.rs b/codex-rs/core/src/guardian/tests.rs index 19007e9d3..098e0f047 100644 --- a/codex-rs/core/src/guardian/tests.rs +++ b/codex-rs/core/src/guardian/tests.rs @@ -16,7 +16,9 @@ use crate::session::session::Session; use crate::session::turn_context::TurnContext; use crate::test_support; use codex_config::config_toml::ConfigToml; +use codex_config::types::McpServerConfig; use codex_exec_server::LOCAL_FS; +use codex_features::Feature; use codex_model_provider::create_model_provider; use codex_network_proxy::NetworkProxyConfig; use codex_protocol::ThreadId; @@ -52,6 +54,7 @@ use insta::Settings; use insta::assert_snapshot; use pretty_assertions::assert_eq; use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; use tempfile::TempDir; @@ -1684,6 +1687,39 @@ async fn guardian_review_session_config_uses_live_network_proxy_state() { ); } +#[tokio::test] +async fn guardian_review_session_config_disables_mcp_apps_and_plugins() { + let mut parent_config = test_config().await; + let server: McpServerConfig = + toml::from_str("command = \"docs-server\"").expect("deserialize MCP server"); + parent_config + .mcp_servers + .set(HashMap::from([("docs".to_string(), server)])) + .expect("parent MCP servers are configurable"); + parent_config + .features + .enable(Feature::Apps) + .expect("apps feature is configurable"); + parent_config + .features + .enable(Feature::Plugins) + .expect("plugins feature is configurable"); + parent_config.include_apps_instructions = true; + + let guardian_config = build_guardian_review_session_config_for_test( + &parent_config, + /*live_network_config*/ None, + "active-model", + /*reasoning_effort*/ None, + ) + .expect("guardian config"); + + assert!(guardian_config.mcp_servers.get().is_empty()); + assert!(!guardian_config.features.enabled(Feature::Apps)); + assert!(!guardian_config.features.enabled(Feature::Plugins)); + assert!(!guardian_config.include_apps_instructions); +} + #[tokio::test] async fn guardian_review_session_config_rejects_pinned_collab_feature() { let mut parent_config = test_config().await;