mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Centralize app enabled-state evaluation (#36916)
## What changed - Add `AppToolPolicyEvaluator::apply_app_enabled_state` and use it when presenting app lists, building plugin context, and deciding whether app instructions are available. - Preserve each app's source state unless local or managed configuration explicitly overrides it. - Keep connector discovery and post-install refresh checks based on raw accessibility rather than configured enablement. ## Testing - Cover default enablement, per-app overrides, managed disablement, and preservation of unconfigured source state. GitOrigin-RevId: f1a62d55e7cc48b37113848e3baa0d69d8d9c8a8
This commit is contained in:
@@ -4,6 +4,8 @@ use codex_config::types::AppToolApproval;
|
||||
use codex_config::types::AppsConfigToml;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::AppInfo;
|
||||
|
||||
/// The effective enablement and approval policy for one app tool.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AppToolPolicy {
|
||||
@@ -63,6 +65,21 @@ impl<'a> AppToolPolicyEvaluator<'a> {
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Applies app policy without overriding source state for unconfigured apps.
|
||||
pub fn apply_app_enabled_state(&self, mut apps: Vec<AppInfo>) -> Vec<AppInfo> {
|
||||
let Some(apps_config) = self.apps_config.as_ref() else {
|
||||
return apps;
|
||||
};
|
||||
|
||||
for app in &mut apps {
|
||||
if apps_config.default.is_some() || apps_config.apps.contains_key(app.id.as_str()) {
|
||||
app.is_enabled = self.app_enabled(app.id.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
apps
|
||||
}
|
||||
|
||||
fn from_parts(
|
||||
apps_config: Option<AppsConfigToml>,
|
||||
requirements_apps_config: Option<&'a AppsRequirementsToml>,
|
||||
|
||||
@@ -189,6 +189,61 @@ fn app_enablement_uses_defaults_and_per_app_overrides() {
|
||||
],
|
||||
[true, false, false]
|
||||
);
|
||||
|
||||
let evaluator = AppToolPolicyEvaluator::from_parts(
|
||||
Some(apps_config),
|
||||
/*requirements_apps_config*/ None,
|
||||
);
|
||||
assert_eq!(
|
||||
evaluator.apply_app_enabled_state(vec![
|
||||
app("calendar", /*enabled*/ false),
|
||||
app("drive", /*enabled*/ true),
|
||||
]),
|
||||
vec![
|
||||
app("calendar", /*enabled*/ true),
|
||||
app("drive", /*enabled*/ false),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_enablement_preserves_source_state_and_honors_local_and_managed_overrides() {
|
||||
let apps_config = AppsConfigToml {
|
||||
default: None,
|
||||
apps: HashMap::from([
|
||||
(
|
||||
"calendar".to_string(),
|
||||
AppConfig {
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
"drive".to_string(),
|
||||
AppConfig {
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
};
|
||||
let requirements = app_enabled_requirement("drive", /*enabled*/ false);
|
||||
let evaluator = AppToolPolicyEvaluator::from_parts(Some(apps_config), Some(&requirements));
|
||||
|
||||
assert_eq!(
|
||||
evaluator.apply_app_enabled_state(vec![
|
||||
app("calendar", /*enabled*/ false),
|
||||
app("drive", /*enabled*/ true),
|
||||
app("slack", /*enabled*/ false),
|
||||
app("gmail", /*enabled*/ true),
|
||||
]),
|
||||
vec![
|
||||
app("calendar", /*enabled*/ true),
|
||||
app("drive", /*enabled*/ false),
|
||||
app("slack", /*enabled*/ false),
|
||||
app("gmail", /*enabled*/ true),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -657,6 +712,26 @@ fn input<'a>(tool_name: &'a str, tool_title: Option<&'a str>) -> AppToolPolicyIn
|
||||
}
|
||||
}
|
||||
|
||||
fn app(id: &str, enabled: bool) -> AppInfo {
|
||||
AppInfo {
|
||||
id: id.to_string(),
|
||||
name: id.to_string(),
|
||||
description: None,
|
||||
logo_url: None,
|
||||
logo_url_dark: None,
|
||||
icon_assets: None,
|
||||
icon_dark_assets: None,
|
||||
distribution_channel: None,
|
||||
branding: None,
|
||||
app_metadata: None,
|
||||
labels: None,
|
||||
install_url: None,
|
||||
is_accessible: true,
|
||||
is_enabled: enabled,
|
||||
plugin_display_names: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn policy_from_apps_config(
|
||||
apps_config: Option<&AppsConfigToml>,
|
||||
connector_id: Option<&str>,
|
||||
|
||||
Reference in New Issue
Block a user