From e35cbb7acfa049bd76ccc7881d4d17e420811d90 Mon Sep 17 00:00:00 2001 From: kevin zhao Date: Mon, 17 Nov 2025 22:07:36 -0800 Subject: [PATCH] execpolicy2 core integration --- codex-rs/core/src/exec_policy.rs | 30 +++++++++++++++++++++++++-- codex-rs/core/src/tools/sandboxing.rs | 3 +-- codex-rs/execpolicy2/tests/basic.rs | 4 ++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/codex-rs/core/src/exec_policy.rs b/codex-rs/core/src/exec_policy.rs index 2127f86c90..f1597c3de6 100644 --- a/codex-rs/core/src/exec_policy.rs +++ b/codex-rs/core/src/exec_policy.rs @@ -106,7 +106,7 @@ pub(crate) fn exec_policy_for( Ok(Some(policy)) } -pub(crate) fn evaluate_with_policy( +fn evaluate_with_policy( policy: &Policy, command: &[String], approval_policy: AskForApproval, @@ -247,9 +247,35 @@ prefix_rule(pattern=["rm"], decision="forbidden") ); } + #[test] + fn approval_requirement_respects_approval_policy() { + let policy_src = r#"prefix_rule(pattern=["rm"], decision="prompt")"#; + let mut parser = PolicyParser::new(); + parser + .parse("test.codexpolicy", policy_src) + .expect("parse policy"); + let policy = parser.build(); + let command = vec!["rm".to_string()]; + + let requirement = approval_requirement_for_command( + Some(&policy), + &command, + AskForApproval::Never, + &SandboxPolicy::DangerFullAccess, + false, + ); + + assert_eq!( + requirement, + ApprovalRequirement::Forbidden { + reason: PROMPT_REASON.to_string() + } + ); + } + #[test] fn approval_requirement_falls_back_to_heuristics() { - let command = vec!["ls".to_string()]; + let command = vec!["python".to_string()]; let requirement = approval_requirement_for_command( None, diff --git a/codex-rs/core/src/tools/sandboxing.rs b/codex-rs/core/src/tools/sandboxing.rs index 6b1738fb69..08c766ab7f 100644 --- a/codex-rs/core/src/tools/sandboxing.rs +++ b/codex-rs/core/src/tools/sandboxing.rs @@ -93,8 +93,7 @@ pub(crate) enum ApprovalRequirement { Forbidden { reason: String }, } -/// Decide whether an initial user approval should be requested before the -/// first attempt. Defaults to the orchestrator's behavior (pre‑refactor): +/// Reflects the orchestrator's behavior (pre-refactor): /// - Never, OnFailure: do not ask /// - OnRequest: ask unless sandbox policy is DangerFullAccess /// - UnlessTrusted: always ask diff --git a/codex-rs/execpolicy2/tests/basic.rs b/codex-rs/execpolicy2/tests/basic.rs index af4629e5c0..75921ecd57 100644 --- a/codex-rs/execpolicy2/tests/basic.rs +++ b/codex-rs/execpolicy2/tests/basic.rs @@ -296,7 +296,7 @@ fn strictest_decision_wins_across_matches() { let policy_src = r#" prefix_rule( pattern = ["git"], - decision = "allow", + decision = "prompt", ) prefix_rule( pattern = ["git", "commit"], @@ -316,7 +316,7 @@ prefix_rule( matched_rules: vec![ RuleMatch::PrefixRuleMatch { matched_prefix: tokens(&["git"]), - decision: Decision::Allow, + decision: Decision::Prompt, }, RuleMatch::PrefixRuleMatch { matched_prefix: tokens(&["git", "commit"]),