Update guardian output schema (#17061)

## Summary
- Update guardian output schema to separate risk, authorization,
outcome, and rationale.
- Feed guardian rationale into rejection messages.
- Split the guardian policy into template and tenant-config sections.

## Validation
- `cargo test -p codex-core mcp_tool_call`
- `env -u CODEX_SANDBOX_NETWORK_DISABLED INSTA_UPDATE=always cargo test
-p codex-core guardian::`

---------

Co-authored-by: Owen Lin <owen@openai.com>
This commit is contained in:
maja-openai
2026-04-08 15:47:29 -07:00
committed by GitHub
parent 49677ec71f
commit dcbc91fd39
45 changed files with 673 additions and 312 deletions

View File

@@ -39,6 +39,7 @@ pub(super) use codex_app_server_protocol::GuardianApprovalReviewAction as AppSer
pub(super) use codex_app_server_protocol::GuardianApprovalReviewStatus;
pub(super) use codex_app_server_protocol::GuardianCommandSource as AppServerGuardianCommandSource;
pub(super) use codex_app_server_protocol::GuardianRiskLevel as AppServerGuardianRiskLevel;
pub(super) use codex_app_server_protocol::GuardianUserAuthorization as AppServerGuardianUserAuthorization;
pub(super) use codex_app_server_protocol::HookCompletedNotification as AppServerHookCompletedNotification;
pub(super) use codex_app_server_protocol::HookEventName as AppServerHookEventName;
pub(super) use codex_app_server_protocol::HookExecutionMode as AppServerHookExecutionMode;
@@ -152,6 +153,7 @@ pub(super) use codex_protocol::protocol::GuardianAssessmentEvent;
pub(super) use codex_protocol::protocol::GuardianAssessmentStatus;
pub(super) use codex_protocol::protocol::GuardianCommandSource;
pub(super) use codex_protocol::protocol::GuardianRiskLevel;
pub(super) use codex_protocol::protocol::GuardianUserAuthorization;
pub(super) use codex_protocol::protocol::ImageGenerationEndEvent;
pub(super) use codex_protocol::protocol::ItemCompletedEvent;
pub(super) use codex_protocol::protocol::McpStartupCompleteEvent;

View File

@@ -18,8 +18,8 @@ async fn guardian_denied_exec_renders_warning_and_denied_request() {
id: "guardian-1".into(),
turn_id: "turn-1".into(),
status: GuardianAssessmentStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
action: action.clone(),
}),
@@ -36,8 +36,8 @@ async fn guardian_denied_exec_renders_warning_and_denied_request() {
id: "guardian-1".into(),
turn_id: "turn-1".into(),
status: GuardianAssessmentStatus::Denied,
risk_score: Some(96),
risk_level: Some(GuardianRiskLevel::High),
user_authorization: Some(GuardianUserAuthorization::Low),
rationale: Some("Would exfiltrate local source code.".into()),
action,
}),
@@ -79,8 +79,8 @@ async fn guardian_approved_exec_renders_approved_request() {
id: "thread:child-thread:guardian-1".into(),
turn_id: "turn-1".into(),
status: GuardianAssessmentStatus::Approved,
risk_score: Some(14),
risk_level: Some(GuardianRiskLevel::Low),
user_authorization: Some(GuardianUserAuthorization::High),
rationale: Some("Narrowly scoped to the requested file.".into()),
action: GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,
@@ -133,8 +133,8 @@ async fn app_server_guardian_review_started_sets_review_status() {
target_item_id: "guardian-1".to_string(),
review: GuardianApprovalReview {
status: GuardianApprovalReviewStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
},
action,
@@ -173,8 +173,8 @@ async fn app_server_guardian_review_denied_renders_denied_request_snapshot() {
target_item_id: "guardian-1".to_string(),
review: GuardianApprovalReview {
status: GuardianApprovalReviewStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
},
action: action.clone(),
@@ -191,8 +191,8 @@ async fn app_server_guardian_review_denied_renders_denied_request_snapshot() {
target_item_id: "guardian-1".to_string(),
review: GuardianApprovalReview {
status: GuardianApprovalReviewStatus::Denied,
risk_score: Some(96),
risk_level: Some(AppServerGuardianRiskLevel::High),
user_authorization: Some(AppServerGuardianUserAuthorization::Low),
rationale: Some("Would exfiltrate local source code.".to_string()),
},
action,
@@ -241,8 +241,8 @@ async fn guardian_parallel_reviews_render_aggregate_status_snapshot() {
id: id.to_string(),
turn_id: "turn-1".to_string(),
status: GuardianAssessmentStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
action: GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,
@@ -271,8 +271,8 @@ async fn guardian_parallel_reviews_keep_remaining_review_visible_after_denial()
id: "guardian-1".to_string(),
turn_id: "turn-1".to_string(),
status: GuardianAssessmentStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
action: GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,
@@ -287,8 +287,8 @@ async fn guardian_parallel_reviews_keep_remaining_review_visible_after_denial()
id: "guardian-2".to_string(),
turn_id: "turn-1".to_string(),
status: GuardianAssessmentStatus::InProgress,
risk_score: None,
risk_level: None,
user_authorization: None,
rationale: None,
action: GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,
@@ -303,8 +303,8 @@ async fn guardian_parallel_reviews_keep_remaining_review_visible_after_denial()
id: "guardian-1".to_string(),
turn_id: "turn-1".to_string(),
status: GuardianAssessmentStatus::Denied,
risk_score: Some(92),
risk_level: Some(GuardianRiskLevel::High),
user_authorization: Some(GuardianUserAuthorization::Low),
rationale: Some("Would delete important data.".to_string()),
action: GuardianAssessmentAction::Command {
source: GuardianCommandSource::Shell,