mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
feat(connectors): support managed app tool approval requirements (#21061)
## Why Managed requirements can already centrally disable apps, but they could not express the per-tool app approval rules that normal config already supports. That left admins without a way to enforce connector tool approvals through `/etc/codex/requirements.toml` or cloud requirements. ## What changed - Extend app requirements with per-tool `approval_mode` entries. - Merge managed app tool requirements across managed sources while preserving higher-precedence exact tool settings. - Apply managed tool approvals separately from user app config so managed policy is matched only on raw MCP `tool.name`, while user config keeps the existing raw-name-then-title convenience fallback. - Add coverage for local requirements, cloud requirements parsing, managed-over-user precedence, and a title-collision case that must not widen managed auto-approval. ## Configuration shape Local `/etc/codex/requirements.toml` and cloud requirements use the same TOML shape: ```toml [apps.connector_123123.tools."calendar/list_events"] approval_mode = "approve" ``` This is a per-tool approval rule keyed by app ID and raw MCP tool name, not an app-level boolean such as `apps.connector_123123.approve = true`.
This commit is contained in:
1 parent
6506765168
commit
d0fa2d81d8
6 files changed
+460
-24
No files matched your search
@@ -535,12 +535,18 @@ pub(crate) fn app_tool_policy(
|
||||
annotations: Option<&ToolAnnotations>,
|
||||
) -> AppToolPolicy {
|
||||
let apps_config = read_apps_config(config);
|
||||
let managed_approval = managed_app_tool_approval(
|
||||
config.config_layer_stack.requirements_toml().apps.as_ref(),
|
||||
connector_id,
|
||||
tool_name,
|
||||
);
|
||||
app_tool_policy_from_apps_config(
|
||||
apps_config.as_ref(),
|
||||
connector_id,
|
||||
tool_name,
|
||||
tool_title,
|
||||
annotations,
|
||||
managed_approval,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -593,14 +599,29 @@ fn apply_requirements_apps_constraints(
|
||||
};
|
||||
|
||||
for (app_id, requirement) in &requirements_apps_config.apps {
|
||||
if requirement.enabled != Some(false) {
|
||||
continue;
|
||||
if requirement.enabled == Some(false) {
|
||||
let app = apps_config.apps.entry(app_id.clone()).or_default();
|
||||
app.enabled = false;
|
||||
}
|
||||
let app = apps_config.apps.entry(app_id.clone()).or_default();
|
||||
app.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn managed_app_tool_approval(
|
||||
requirements_apps_config: Option<&AppsRequirementsToml>,
|
||||
connector_id: Option<&str>,
|
||||
tool_name: &str,
|
||||
) -> Option<AppToolApproval> {
|
||||
let connector_id = connector_id?;
|
||||
requirements_apps_config?
|
||||
.apps
|
||||
.get(connector_id)?
|
||||
.tools
|
||||
.as_ref()?
|
||||
.tools
|
||||
.get(tool_name)?
|
||||
.approval_mode
|
||||
}
|
||||
|
||||
fn app_is_enabled(apps_config: &AppsConfigToml, connector_id: Option<&str>) -> bool {
|
||||
let default_enabled = apps_config
|
||||
.default
|
||||
@@ -620,9 +641,13 @@ fn app_tool_policy_from_apps_config(
|
||||
tool_name: &str,
|
||||
tool_title: Option<&str>,
|
||||
annotations: Option<&ToolAnnotations>,
|
||||
managed_approval: Option<AppToolApproval>,
|
||||
) -> AppToolPolicy {
|
||||
let Some(apps_config) = apps_config else {
|
||||
return AppToolPolicy::default();
|
||||
return AppToolPolicy {
|
||||
approval: managed_approval.unwrap_or(AppToolApproval::Auto),
|
||||
..Default::default()
|
||||
};
|
||||
};
|
||||
|
||||
let app = connector_id.and_then(|connector_id| apps_config.apps.get(connector_id));
|
||||
@@ -633,8 +658,8 @@ fn app_tool_policy_from_apps_config(
|
||||
.get(tool_name)
|
||||
.or_else(|| tool_title.and_then(|title| tools.tools.get(title)))
|
||||
});
|
||||
let approval = tool_config
|
||||
.and_then(|tool| tool.approval_mode)
|
||||
let approval = managed_approval
|
||||
.or_else(|| tool_config.and_then(|tool| tool.approval_mode))
|
||||
.or_else(|| app.and_then(|app| app.default_tools_approval_mode))
|
||||
.unwrap_or(AppToolApproval::Auto);
|
||||
|
||||
|
||||
Reference in new issue
Block a user