From a3edbe96be578ca97bd26127372fef7b72e7e84d Mon Sep 17 00:00:00 2001 From: Abhinav Vedmala Date: Tue, 16 Jun 2026 06:15:42 +0000 Subject: [PATCH] Honor managed login shell restrictions consistently --- codex-rs/config/src/config_toml.rs | 5 ---- codex-rs/core/config.schema.json | 1 - codex-rs/core/src/config/config_tests.rs | 15 ++++++++++++ codex-rs/core/src/session/tests.rs | 30 ++++++++++++++++++++++++ codex-rs/core/src/tasks/user_shell.rs | 2 +- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/codex-rs/config/src/config_toml.rs b/codex-rs/config/src/config_toml.rs index 7270c3f329..9d04ec220c 100644 --- a/codex-rs/config/src/config_toml.rs +++ b/codex-rs/config/src/config_toml.rs @@ -67,10 +67,6 @@ const RESERVED_MODEL_PROVIDER_IDS: [&str; 4] = [ pub const DEFAULT_PROJECT_DOC_MAX_BYTES: usize = 32 * 1024; -const fn default_allow_login_shell() -> Option { - Some(true) -} - fn default_history() -> Option { Some(History::default()) } @@ -178,7 +174,6 @@ pub struct ConfigToml { /// If `false`, the model can never use a login shell: `login = true` /// requests are rejected, and omitting `login` defaults to a non-login /// shell. - #[serde(default = "default_allow_login_shell")] pub allow_login_shell: Option, /// Sandbox mode to use. diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 22034964a0..9554cdcbac 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -4407,7 +4407,6 @@ "description": "Agent-related settings (thread limits, etc.)." }, "allow_login_shell": { - "default": true, "description": "Whether the model may request a login shell for shell-based tools. Default to `true`\n\nIf `true`, the model may request a login shell (`login = true`), and omitting `login` defaults to using a login shell. If `false`, the model can never use a login shell: `login = true` requests are rejected, and omitting `login` defaults to a non-login shell.", "type": "boolean" }, diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index d431e00877..e0e29094eb 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -10928,3 +10928,18 @@ sandbox_private_desktop = false })); Ok(()) } + +#[tokio::test] +async fn absent_allow_login_shell_does_not_report_an_override() -> std::io::Result<()> { + let codex_home = TempDir::new()?; + let config = load_with_enterprise_requirement(&codex_home, "allow_login_shell = false").await?; + + assert!(!config.permissions.allow_login_shell); + assert!( + config + .startup_warnings + .iter() + .all(|warning| !warning.contains("allow_login_shell")) + ); + Ok(()) +} diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 5086fd63bd..bded602223 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -1150,6 +1150,36 @@ async fn user_shell_commands_do_not_inherit_managed_network_proxy() -> anyhow::R Ok(()) } +#[tokio::test] +async fn user_shell_commands_honor_disabled_login_shells() -> anyhow::Result<()> { + let (session, rx) = make_session_with_config_and_rx(|config| { + config.permissions.allow_login_shell = false; + }) + .await?; + let turn_context = session.new_default_turn().await; + let command = "echo managed-login-shell".to_string(); + let expected_command = session.user_shell().derive_exec_args(&command, false); + + execute_user_shell_command( + Arc::clone(&session), + turn_context, + command, + CancellationToken::new(), + UserShellCommandMode::StandaloneTurn, + ) + .await; + + loop { + let event = rx.recv().await.expect("channel open"); + if let EventMsg::ExecCommandBegin(event) = event.msg { + assert_eq!(event.command, expected_command); + break; + } + } + + Ok(()) +} + #[tokio::test] async fn get_base_instructions_no_user_content() { let prompt_with_apply_patch_instructions = diff --git a/codex-rs/core/src/tasks/user_shell.rs b/codex-rs/core/src/tasks/user_shell.rs index 6a01a87a0e..5ddb8781d8 100644 --- a/codex-rs/core/src/tasks/user_shell.rs +++ b/codex-rs/core/src/tasks/user_shell.rs @@ -142,7 +142,7 @@ pub(crate) async fn execute_user_shell_command( // Execute the user's script under the environment's shell; this // allows commands that use shell features (pipes, &&, redirects, etc.). // We do not source rc files or otherwise reformat the script. - let use_login_shell = true; + let use_login_shell = turn_context.config.permissions.allow_login_shell; let display_command = environment_shell.derive_exec_args(&command, use_login_shell); let shell_snapshot_location = turn_environment.shell_snapshot(turn_environment.cwd()); let mut exec_env_map = create_env(