diff --git a/codex-rs/core/src/exec_policy.rs b/codex-rs/core/src/exec_policy.rs index c0cb7f8fcf..64b6e7871a 100644 --- a/codex-rs/core/src/exec_policy.rs +++ b/codex-rs/core/src/exec_policy.rs @@ -310,13 +310,16 @@ pub fn render_decision_for_unmatched_command( let runtime_sandbox_provides_safety = cfg!(windows) && matches!(sandbox_policy, SandboxPolicy::ReadOnly); - // If the command is flagged as dangerous or we have no sandbox protection, - // we should never allow it to run without user approval. + // If the command is flagged as dangerous or we have no sandbox protection + // when we expect a sandbox to be on, we should never allow it to run + // without user approval. // // We prefer to prompt the user rather than outright forbid the command, // but if the user has explicitly disabled prompts, we must // forbid the command. - if command_might_be_dangerous(command) || runtime_sandbox_provides_safety { + if sandbox_policy.expects_enforcement() + && (command_might_be_dangerous(command) || runtime_sandbox_provides_safety) + { return if matches!(approval_policy, AskForApproval::Never) { Decision::Forbidden } else { @@ -1023,6 +1026,21 @@ prefix_rule( ); } + #[test] + fn danger_full_access_allows_dangerous_commands_with_never() { + let command = vec!["rm".to_string(), "-rf".to_string(), "/".to_string()]; + + assert_eq!( + render_decision_for_unmatched_command( + AskForApproval::Never, + &SandboxPolicy::DangerFullAccess, + &command, + SandboxPermissions::UseDefault, + ), + Decision::Allow + ); + } + #[tokio::test] async fn append_execpolicy_amendment_updates_policy_and_file() { let codex_home = tempdir().expect("create temp dir"); diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 6a6939620f..2b8e4e6ad3 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -416,6 +416,15 @@ pub enum SandboxPolicy { }, } +impl SandboxPolicy { + pub fn expects_enforcement(&self) -> bool { + matches!( + self, + SandboxPolicy::ReadOnly | SandboxPolicy::WorkspaceWrite { .. } + ) + } +} + /// A writable root path accompanied by a list of subpaths that should remain /// read‑only even when the root is writable. This is primarily used to ensure /// that folders containing files that could be modified to escalate the