mirror of
https://github.com/openai/codex.git
synced 2026-11-10 16:44:38 +00:00
[app-server][core] Add connector-level Guardian reviewer overrides (#25167)
Context: https://openai.slack.com/archives/C0B4JAF0Q2C/p1779912328647229 ``` approvals_reviewer = "auto_review" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "user" default_tools_approval_mode = "prompt" ``` <img width="230" height="84" alt="Screenshot 2026-05-31 at 11 56 34 AM" src="https://github.com/user-attachments/assets/e319f8f7-0983-42a7-98cd-3302732fa406" /> <img width="841" height="233" alt="Screenshot 2026-05-31 at 11 52 42 AM" src="https://github.com/user-attachments/assets/7ac76645-4e90-4d00-8242-f031146a22a5" /> ------- ``` approvals_reviewer = "user" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "auto_review" default_tools_approval_mode = "prompt" ``` <img width="195" height="83" alt="Screenshot 2026-05-31 at 12 02 27 PM" src="https://github.com/user-attachments/assets/3d374dc8-8aa2-466f-a13f-e4ed8567aa2e" /> <img width="771" height="207" alt="Screenshot 2026-05-31 at 12 05 42 PM" src="https://github.com/user-attachments/assets/105c2575-68d6-4ca6-8e69-dc8c82da36a2" /> ## Summary - add `apps.<connector_id>.approvals_reviewer` to override Guardian or user review routing per connected app - apply overrides across direct app MCP calls, delegated MCP prompts, and app-server MCP elicitation review while preserving global behavior for non-app MCP servers - expose and document the config through app-server v2 and generated schemas, while honoring global managed reviewer requirements --------- Co-authored-by: jif-oai <jif@openai.com>
This commit is contained in:
1 parent
c097ad3e9e
commit
4d80d808b4
22 files changed
+337
-21
No files matched your search
@@ -2,6 +2,7 @@ use super::*;
|
||||
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_DECLINE_SYNTHETIC;
|
||||
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_QUESTION_ID_PREFIX;
|
||||
use async_channel::bounded;
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_protocol::config_types::ApprovalsReviewer;
|
||||
use codex_protocol::models::NetworkPermissions;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
@@ -445,3 +446,72 @@ async fn delegated_mcp_guardian_abort_returns_synthetic_decline_answer() {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn delegated_mcp_user_reviewer_waits_for_metadata_lookup() {
|
||||
let (parent_session, parent_ctx, _rx_events) =
|
||||
crate::session::tests::make_session_and_context_with_rx().await;
|
||||
let pending_mcp_invocations = Arc::new(Mutex::new(HashMap::from([(
|
||||
"call-1".to_string(),
|
||||
McpInvocation {
|
||||
server: CODEX_APPS_MCP_SERVER_NAME.to_string(),
|
||||
tool: "dangerous_tool".to_string(),
|
||||
arguments: None,
|
||||
},
|
||||
)])));
|
||||
let cancel_token = CancellationToken::new();
|
||||
let manager = Arc::clone(&parent_session.services.mcp_connection_manager);
|
||||
let (manager_locked_tx, manager_locked_rx) = std::sync::mpsc::sync_channel(0);
|
||||
let (release_manager_tx, release_manager_rx) = std::sync::mpsc::sync_channel(0);
|
||||
let manager_lock = tokio::task::spawn_blocking(move || {
|
||||
let _manager_guard = manager.blocking_write();
|
||||
manager_locked_tx
|
||||
.send(())
|
||||
.expect("manager lock receiver should remain open");
|
||||
release_manager_rx
|
||||
.recv()
|
||||
.expect("manager lock release sender should remain open");
|
||||
});
|
||||
manager_locked_rx
|
||||
.recv_timeout(Duration::from_secs(1))
|
||||
.expect("manager write lock should be acquired");
|
||||
|
||||
let event = RequestUserInputEvent {
|
||||
call_id: "call-1".to_string(),
|
||||
turn_id: "child-turn-1".to_string(),
|
||||
questions: vec![RequestUserInputQuestion {
|
||||
id: format!("{MCP_TOOL_APPROVAL_QUESTION_ID_PREFIX}_call-1"),
|
||||
header: "Approve app tool call?".to_string(),
|
||||
question: "Allow this app tool?".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: None,
|
||||
}],
|
||||
};
|
||||
let response = maybe_auto_review_mcp_request_user_input(
|
||||
&parent_session,
|
||||
&parent_ctx,
|
||||
&pending_mcp_invocations,
|
||||
&event,
|
||||
&cancel_token,
|
||||
);
|
||||
tokio::pin!(response);
|
||||
assert!(
|
||||
timeout(Duration::from_millis(100), &mut response)
|
||||
.await
|
||||
.is_err(),
|
||||
"manual reviewer should wait for MCP metadata"
|
||||
);
|
||||
release_manager_tx
|
||||
.send(())
|
||||
.expect("manager lock holder should remain open");
|
||||
manager_lock
|
||||
.await
|
||||
.expect("manager lock task should not panic");
|
||||
assert_eq!(
|
||||
timeout(Duration::from_secs(1), response)
|
||||
.await
|
||||
.expect("manual reviewer should finish after MCP metadata lookup"),
|
||||
None
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user