initial draft

This commit is contained in:
Roy Han
2026-03-18 14:39:21 -07:00
parent ef7f3b189e
commit 11c1cd375c
2 changed files with 84 additions and 26 deletions

View File

@@ -4636,14 +4636,7 @@ async fn tool_call_metadata_stamps_guardian_direct_review_when_feature_enabled()
async fn tool_call_metadata_stamps_policy_source_without_review_decision_when_feature_enabled() {
let (sess, tc, rx, expected_sandbox_policy) = setup_tool_call_metadata_runtime_test().await;
sess.record_call_approval_outcome(
"call-policy-runtime-1".to_string(),
ApprovalOutcomeMetadata {
review_decision: None,
approval_source: codex_protocol::models::ApprovalSourceMetadata::Policy,
},
)
.await;
sess.record_policy_outcome("call-policy-runtime-1").await;
sess.record_response_item_and_emit_turn_item(
tc.as_ref(),
function_call_item("call-policy-runtime-1"),
@@ -4794,6 +4787,87 @@ async fn tool_call_metadata_can_be_restamped_after_approval_outcome() {
));
}
#[tokio::test]
async fn tool_call_metadata_snapshot_stamps_guardian_approval_source() {
let (_session, turn_context_raw) = make_session_and_context().await;
let turn_context = Arc::new(turn_context_raw);
let expected_sandbox_policy = sandbox_policy_to_metadata(turn_context.sandbox_policy.get());
let item = ResponseItem::FunctionCall {
id: None,
name: "shell".to_string(),
namespace: None,
arguments: "{}".to_string(),
call_id: "call-guardian-1".to_string(),
metadata: None,
};
let snapshot = ToolApprovalMetadataSnapshot {
approval_outcomes_by_call_id: HashMap::from([(
"call-guardian-1".to_string(),
crate::state::ApprovalOutcomeMetadata {
review_decision: Some(codex_protocol::models::ReviewDecisionMetadata::Denied),
approval_source: codex_protocol::models::ApprovalSourceMetadata::Guardian,
},
)]),
pending_approval_call_ids: HashSet::new(),
};
let stamped =
stamp_tool_approval_metadata_with_snapshot(turn_context.as_ref(), item, Some(&snapshot));
assert!(matches!(
stamped,
ResponseItem::FunctionCall {
metadata: Some(metadata),
..
} if metadata.is_tool_call_escalated == Some(true)
&& metadata.review_decision
== Some(codex_protocol::models::ReviewDecisionMetadata::Denied)
&& metadata.approval_source
== Some(codex_protocol::models::ApprovalSourceMetadata::Guardian)
&& metadata.sandbox_policy == Some(expected_sandbox_policy)
));
}
#[tokio::test]
async fn tool_call_metadata_snapshot_stamps_policy_approval_source_without_review_decision() {
let (_session, turn_context_raw) = make_session_and_context().await;
let turn_context = Arc::new(turn_context_raw);
let expected_sandbox_policy = sandbox_policy_to_metadata(turn_context.sandbox_policy.get());
let item = ResponseItem::FunctionCall {
id: None,
name: "shell".to_string(),
namespace: None,
arguments: "{}".to_string(),
call_id: "call-policy-1".to_string(),
metadata: None,
};
let snapshot = ToolApprovalMetadataSnapshot {
approval_outcomes_by_call_id: HashMap::from([(
"call-policy-1".to_string(),
crate::state::ApprovalOutcomeMetadata {
review_decision: None,
approval_source: codex_protocol::models::ApprovalSourceMetadata::Policy,
},
)]),
pending_approval_call_ids: HashSet::new(),
};
let stamped =
stamp_tool_approval_metadata_with_snapshot(turn_context.as_ref(), item, Some(&snapshot));
assert!(matches!(
stamped,
ResponseItem::FunctionCall {
metadata: Some(metadata),
..
} if metadata.is_tool_call_escalated == Some(true)
&& metadata.review_decision.is_none()
&& metadata.approval_source
== Some(codex_protocol::models::ApprovalSourceMetadata::Policy)
&& metadata.sandbox_policy == Some(expected_sandbox_policy)
));
}
#[tokio::test]
async fn steer_input_requires_active_turn() {
let (sess, _tc, _rx) = make_session_and_context_with_rx().await;

View File

@@ -532,30 +532,14 @@ impl CoreShellActionProvider {
) -> anyhow::Result<EscalationDecision> {
let action = match decision {
Decision::Forbidden => {
self.session
.record_call_approval_outcome(
self.call_id.clone(),
ApprovalOutcomeMetadata {
review_decision: None,
approval_source: ApprovalSourceMetadata::Policy,
},
)
.await;
self.session.record_policy_outcome(&self.call_id).await;
EscalationDecision::deny(Some("Execution forbidden by policy".to_string()))
}
Decision::Prompt => {
if execve_prompt_is_rejected_by_policy(self.approval_policy, &decision_source)
.is_some()
{
self.session
.record_call_approval_outcome(
self.call_id.clone(),
ApprovalOutcomeMetadata {
review_decision: None,
approval_source: ApprovalSourceMetadata::Policy,
},
)
.await;
self.session.record_policy_outcome(&self.call_id).await;
EscalationDecision::deny(Some("Execution forbidden by policy".to_string()))
} else {
match self