1- use crate :: codex:: Session ;
21use crate :: codex:: TurnContext ;
32use crate :: function_tool:: FunctionCallError ;
43use crate :: protocol:: FileChange ;
5- use crate :: protocol:: ReviewDecision ;
64use crate :: safety:: SafetyCheck ;
75use crate :: safety:: assess_patch_safety;
6+ use crate :: tools:: sandboxing:: ExecApprovalRequirement ;
87use codex_apply_patch:: ApplyPatchAction ;
98use codex_apply_patch:: ApplyPatchFileChange ;
109use std:: collections:: HashMap ;
@@ -30,70 +29,43 @@ pub(crate) enum InternalApplyPatchInvocation {
3029#[ derive( Debug ) ]
3130pub ( crate ) struct ApplyPatchExec {
3231 pub ( crate ) action : ApplyPatchAction ,
33- pub ( crate ) user_explicitly_approved_this_action : bool ,
32+ pub ( crate ) auto_approved : bool ,
33+ pub ( crate ) exec_approval_requirement : ExecApprovalRequirement ,
3434}
3535
3636pub ( crate ) async fn apply_patch (
37- sess : & Session ,
3837 turn_context : & TurnContext ,
39- call_id : & str ,
4038 action : ApplyPatchAction ,
4139) -> InternalApplyPatchInvocation {
42- let session_patch_approved = {
43- let store = sess. services . apply_patch_approvals . lock ( ) . await ;
44- store. is_action_approved ( & action, & action. cwd )
45- } ;
4640 match assess_patch_safety (
4741 & action,
4842 turn_context. approval_policy ,
4943 & turn_context. sandbox_policy ,
5044 & turn_context. cwd ,
51- session_patch_approved,
5245 ) {
5346 SafetyCheck :: AutoApprove {
5447 user_explicitly_approved,
5548 ..
5649 } => InternalApplyPatchInvocation :: DelegateToExec ( ApplyPatchExec {
5750 action,
58- user_explicitly_approved_this_action : user_explicitly_approved,
51+ auto_approved : !user_explicitly_approved,
52+ exec_approval_requirement : ExecApprovalRequirement :: Skip {
53+ bypass_sandbox : false ,
54+ proposed_execpolicy_amendment : None ,
55+ } ,
5956 } ) ,
6057 SafetyCheck :: AskUser => {
61- // Compute a readable summary of path changes to include in the
62- // approval request so the user can make an informed decision.
63- //
64- // Note that it might be worth expanding this approval request to
65- // give the user the option to expand the set of writable roots so
66- // that similar patches can be auto-approved in the future during
67- // this session.
68- let rx_approve = sess
69- . request_patch_approval (
70- turn_context,
71- call_id. to_owned ( ) ,
72- convert_apply_patch_to_protocol ( & action) ,
73- None ,
74- None ,
75- )
76- . await ;
77- let decision = rx_approve. await . unwrap_or_default ( ) ;
78- if matches ! ( decision, ReviewDecision :: ApprovedForSession ) {
79- let mut store = sess. services . apply_patch_approvals . lock ( ) . await ;
80- store. approve_action ( & action, & action. cwd ) ;
81- }
82- match decision {
83- ReviewDecision :: Approved
84- | ReviewDecision :: ApprovedExecpolicyAmendment { .. }
85- | ReviewDecision :: ApprovedForSession => {
86- InternalApplyPatchInvocation :: DelegateToExec ( ApplyPatchExec {
87- action,
88- user_explicitly_approved_this_action : true ,
89- } )
90- }
91- ReviewDecision :: Denied | ReviewDecision :: Abort => {
92- InternalApplyPatchInvocation :: Output ( Err ( FunctionCallError :: RespondToModel (
93- "patch rejected by user" . to_string ( ) ,
94- ) ) )
95- }
96- }
58+ // Delegate the approval prompt (including cached approvals) to the
59+ // tool runtime, consistent with how shell/unified_exec approvals
60+ // are orchestrator-driven.
61+ InternalApplyPatchInvocation :: DelegateToExec ( ApplyPatchExec {
62+ action,
63+ auto_approved : false ,
64+ exec_approval_requirement : ExecApprovalRequirement :: NeedsApproval {
65+ reason : None ,
66+ proposed_execpolicy_amendment : None ,
67+ } ,
68+ } )
9769 }
9870 SafetyCheck :: Reject { reason } => InternalApplyPatchInvocation :: Output ( Err (
9971 FunctionCallError :: RespondToModel ( format ! ( "patch rejected: {reason}" ) ) ,
0 commit comments