mirror of
https://github.com/openai/codex.git
synced 2026-05-05 03:47:01 +00:00
Compare commits
4 Commits
commit-495
...
codex/viya
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf9d6b148b | ||
|
|
aa60403203 | ||
|
|
03ae22edf6 | ||
|
|
233a15294e |
@@ -829,6 +829,7 @@ mod tests {
|
||||
use super::*;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
|
||||
use codex_config::AppToolApproval;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::auth::AgentIdentityAuth;
|
||||
use codex_login::auth::AgentIdentityAuthRecord;
|
||||
@@ -1399,6 +1400,40 @@ enabled = false
|
||||
"connector_5f3c8c41a1e54ad7a76272c89e2554fa".to_string(),
|
||||
codex_config::AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_cloud_requirements_parses_apps_tool_requirements_toml() {
|
||||
let result = parse_for_fetch(Some(
|
||||
r#"
|
||||
[apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa.tools."calendar/list_events"]
|
||||
approval_mode = "approve"
|
||||
"#,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
Some(ConfigRequirementsToml {
|
||||
apps: Some(codex_config::AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_5f3c8c41a1e54ad7a76272c89e2554fa".to_string(),
|
||||
codex_config::AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(codex_config::AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
codex_config::AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
|
||||
@@ -18,6 +18,7 @@ use super::requirements_exec_policy::RequirementsExecPolicyToml;
|
||||
use crate::Constrained;
|
||||
use crate::ConstraintError;
|
||||
use crate::ManagedHooksRequirementsToml;
|
||||
use crate::mcp_types::AppToolApproval;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RequirementSource {
|
||||
@@ -597,9 +598,43 @@ impl FeatureRequirementsToml {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct AppToolRequirementToml {
|
||||
pub approval_mode: Option<AppToolApproval>,
|
||||
}
|
||||
|
||||
impl AppToolRequirementToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.approval_mode.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct AppToolsRequirementsToml {
|
||||
#[serde(default, flatten)]
|
||||
pub tools: BTreeMap<String, AppToolRequirementToml>,
|
||||
}
|
||||
|
||||
impl AppToolsRequirementsToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.tools.values().all(AppToolRequirementToml::is_empty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct AppRequirementToml {
|
||||
pub enabled: Option<bool>,
|
||||
pub tools: Option<AppToolsRequirementsToml>,
|
||||
}
|
||||
|
||||
impl AppRequirementToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.enabled.is_none()
|
||||
&& self
|
||||
.tools
|
||||
.as_ref()
|
||||
.is_none_or(AppToolsRequirementsToml::is_empty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
@@ -610,14 +645,14 @@ pub struct AppsRequirementsToml {
|
||||
|
||||
impl AppsRequirementsToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.apps.values().all(|app| app.enabled.is_none())
|
||||
self.apps.values().all(AppRequirementToml::is_empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge `enabled` configs from a lower-precedence source into an existing higher-precedence set.
|
||||
/// This lets managed sources (for example Cloud/MDM) enforce setting disablement across layers.
|
||||
/// Implemented with AppsRequirementsToml for now, could be abstracted if we have more enablement-style configs in the future.
|
||||
pub(crate) fn merge_enablement_settings_descending(
|
||||
/// Merge app requirements from a lower-precedence source into an existing higher-precedence set.
|
||||
/// This lets managed sources (for example Cloud/MDM) enforce setting disablement across layers,
|
||||
/// while exact tool approval settings keep the higher-precedence value when present.
|
||||
pub(crate) fn merge_app_requirements_descending(
|
||||
base: &mut AppsRequirementsToml,
|
||||
incoming: AppsRequirementsToml,
|
||||
) {
|
||||
@@ -631,6 +666,17 @@ pub(crate) fn merge_enablement_settings_descending(
|
||||
} else {
|
||||
higher_precedence.or(lower_precedence)
|
||||
};
|
||||
|
||||
let Some(incoming_tools) = incoming_requirement.tools else {
|
||||
continue;
|
||||
};
|
||||
let base_tools = base_requirement.tools.get_or_insert_with(Default::default);
|
||||
for (tool_name, incoming_tool) in incoming_tools.tools {
|
||||
let base_tool = base_tools.tools.entry(tool_name).or_default();
|
||||
if base_tool.approval_mode.is_none() {
|
||||
base_tool.approval_mode = incoming_tool.approval_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,7 +815,7 @@ impl ConfigRequirementsWithSources {
|
||||
|
||||
if let Some(incoming_apps) = other.apps.take() {
|
||||
if let Some(existing_apps) = self.apps.as_mut() {
|
||||
merge_enablement_settings_descending(&mut existing_apps.value, incoming_apps);
|
||||
merge_app_requirements_descending(&mut existing_apps.value, incoming_apps);
|
||||
} else {
|
||||
self.apps = Some(Sourced::new(incoming_apps, source));
|
||||
}
|
||||
@@ -1583,6 +1629,37 @@ allowed_approvals_reviewers = ["user"]
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
})
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_apps_tool_requirements() -> Result<()> {
|
||||
let toml_str = r#"
|
||||
[apps.connector_123123.tools."calendar/list_events"]
|
||||
approval_mode = "approve"
|
||||
"#;
|
||||
let requirements: ConfigRequirementsToml = from_str(toml_str)?;
|
||||
|
||||
assert_eq!(
|
||||
requirements.apps,
|
||||
Some(AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
})
|
||||
@@ -1597,19 +1674,45 @@ allowed_approvals_reviewers = ["user"]
|
||||
.map(|(app_id, enabled)| {
|
||||
(
|
||||
(*app_id).to_string(),
|
||||
AppRequirementToml { enabled: *enabled },
|
||||
AppRequirementToml {
|
||||
enabled: *enabled,
|
||||
tools: None,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn app_tool_requirements(
|
||||
app_id: &str,
|
||||
tool_name: &str,
|
||||
approval_mode: AppToolApproval,
|
||||
) -> AppsRequirementsToml {
|
||||
AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
app_id.to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
tool_name.to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(approval_mode),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_enablement_settings_descending_unions_distinct_apps() {
|
||||
fn merge_app_requirements_descending_unions_distinct_apps() {
|
||||
let mut merged = apps_requirements(&[("connector_high", Some(false))]);
|
||||
let lower = apps_requirements(&[("connector_low", Some(true))]);
|
||||
|
||||
merge_enablement_settings_descending(&mut merged, lower);
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
@@ -1621,11 +1724,11 @@ allowed_approvals_reviewers = ["user"]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_enablement_settings_descending_prefers_false_from_lower_precedence() {
|
||||
fn merge_app_requirements_descending_prefers_false_from_lower_precedence() {
|
||||
let mut merged = apps_requirements(&[("connector_123123", Some(true))]);
|
||||
let lower = apps_requirements(&[("connector_123123", Some(false))]);
|
||||
|
||||
merge_enablement_settings_descending(&mut merged, lower);
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
@@ -1634,11 +1737,11 @@ allowed_approvals_reviewers = ["user"]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_enablement_settings_descending_keeps_higher_true_when_lower_is_unset() {
|
||||
fn merge_app_requirements_descending_keeps_higher_true_when_lower_is_unset() {
|
||||
let mut merged = apps_requirements(&[("connector_123123", Some(true))]);
|
||||
let lower = apps_requirements(&[("connector_123123", None)]);
|
||||
|
||||
merge_enablement_settings_descending(&mut merged, lower);
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
@@ -1647,11 +1750,11 @@ allowed_approvals_reviewers = ["user"]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_enablement_settings_descending_uses_lower_value_when_higher_missing() {
|
||||
fn merge_app_requirements_descending_uses_lower_value_when_higher_missing() {
|
||||
let mut merged = apps_requirements(&[]);
|
||||
let lower = apps_requirements(&[("connector_123123", Some(true))]);
|
||||
|
||||
merge_enablement_settings_descending(&mut merged, lower);
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
@@ -1660,11 +1763,11 @@ allowed_approvals_reviewers = ["user"]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_enablement_settings_descending_preserves_higher_false_when_lower_missing_app() {
|
||||
fn merge_app_requirements_descending_preserves_higher_false_when_lower_missing_app() {
|
||||
let mut merged = apps_requirements(&[("connector_123123", Some(false))]);
|
||||
let lower = apps_requirements(&[]);
|
||||
|
||||
merge_enablement_settings_descending(&mut merged, lower);
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
@@ -1672,6 +1775,52 @@ allowed_approvals_reviewers = ["user"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_app_requirements_descending_preserves_higher_tool_approval_mode() {
|
||||
let mut merged = app_tool_requirements(
|
||||
"connector_123123",
|
||||
"calendar/list_events",
|
||||
AppToolApproval::Approve,
|
||||
);
|
||||
let lower = app_tool_requirements(
|
||||
"connector_123123",
|
||||
"calendar/list_events",
|
||||
AppToolApproval::Prompt,
|
||||
);
|
||||
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
app_tool_requirements(
|
||||
"connector_123123",
|
||||
"calendar/list_events",
|
||||
AppToolApproval::Approve,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_app_requirements_descending_uses_lower_tool_approval_when_higher_missing() {
|
||||
let mut merged = apps_requirements(&[("connector_123123", None)]);
|
||||
let lower = app_tool_requirements(
|
||||
"connector_123123",
|
||||
"calendar/list_events",
|
||||
AppToolApproval::Approve,
|
||||
);
|
||||
|
||||
merge_app_requirements_descending(&mut merged, lower);
|
||||
|
||||
assert_eq!(
|
||||
merged,
|
||||
app_tool_requirements(
|
||||
"connector_123123",
|
||||
"calendar/list_events",
|
||||
AppToolApproval::Approve,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_unset_fields_merges_apps_across_sources_with_enabled_evaluation() {
|
||||
let higher_source = RequirementSource::CloudRequirements;
|
||||
|
||||
@@ -33,6 +33,8 @@ pub use cloud_requirements::CloudRequirementsLoader;
|
||||
pub use codex_app_server_protocol::ConfigLayerSource;
|
||||
pub use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
pub use config_requirements::AppRequirementToml;
|
||||
pub use config_requirements::AppToolRequirementToml;
|
||||
pub use config_requirements::AppToolsRequirementsToml;
|
||||
pub use config_requirements::AppsRequirementsToml;
|
||||
pub use config_requirements::ConfigRequirements;
|
||||
pub use config_requirements::ConfigRequirementsToml;
|
||||
|
||||
@@ -578,13 +578,21 @@ pub(crate) fn app_tool_policy(
|
||||
annotations: Option<&ToolAnnotations>,
|
||||
) -> AppToolPolicy {
|
||||
let apps_config = read_apps_config(config);
|
||||
app_tool_policy_from_apps_config(
|
||||
let mut policy = app_tool_policy_from_apps_config(
|
||||
apps_config.as_ref(),
|
||||
connector_id,
|
||||
tool_name,
|
||||
tool_title,
|
||||
annotations,
|
||||
)
|
||||
);
|
||||
if let Some(approval) = managed_app_tool_approval(
|
||||
config.config_layer_stack.requirements_toml().apps.as_ref(),
|
||||
connector_id,
|
||||
tool_name,
|
||||
) {
|
||||
policy.approval = approval;
|
||||
}
|
||||
policy
|
||||
}
|
||||
|
||||
pub(crate) fn codex_app_tool_is_enabled(config: &Config, tool_info: &ToolInfo) -> bool {
|
||||
@@ -636,14 +644,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
|
||||
|
||||
@@ -2,6 +2,8 @@ use super::*;
|
||||
use crate::config::CONFIG_TOML_FILE;
|
||||
use crate::config::ConfigBuilder;
|
||||
use codex_config::AppRequirementToml;
|
||||
use codex_config::AppToolRequirementToml;
|
||||
use codex_config::AppToolsRequirementsToml;
|
||||
use codex_config::AppsRequirementsToml;
|
||||
use codex_config::CloudRequirementsLoader;
|
||||
use codex_config::ConfigLayerStack;
|
||||
@@ -503,6 +505,7 @@ fn requirements_disabled_connector_overrides_enabled_connector() {
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
};
|
||||
@@ -535,6 +538,7 @@ fn requirements_enabled_does_not_override_disabled_connector() {
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(true),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
};
|
||||
@@ -568,6 +572,7 @@ enabled = true
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -611,6 +616,7 @@ async fn cloud_requirements_disable_connector_applies_without_user_apps_table()
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -661,6 +667,7 @@ async fn local_requirements_disable_connector_overrides_user_apps_config() {
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -712,6 +719,7 @@ async fn local_requirements_disable_connector_applies_without_user_apps_table()
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -753,6 +761,7 @@ async fn with_app_enabled_state_preserves_unrelated_disabled_connector() {
|
||||
"connector_drive".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -804,6 +813,211 @@ fn app_tool_policy_honors_default_app_enabled_false() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn managed_app_tool_approval_uses_raw_tool_name() {
|
||||
let requirements_apps = AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
managed_app_tool_approval(
|
||||
Some(&requirements_apps),
|
||||
Some("connector_123123"),
|
||||
"calendar/list_events",
|
||||
),
|
||||
Some(AppToolApproval::Approve)
|
||||
);
|
||||
assert_eq!(
|
||||
managed_app_tool_approval(
|
||||
Some(&requirements_apps),
|
||||
Some("connector_123123"),
|
||||
"calendar/create_event",
|
||||
),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cloud_requirements_tool_approval_overrides_user_apps_config() {
|
||||
let codex_home = tempdir().expect("tempdir should succeed");
|
||||
std::fs::write(
|
||||
codex_home.path().join(CONFIG_TOML_FILE),
|
||||
r#"
|
||||
[apps.connector_123123.tools."calendar/list_events"]
|
||||
approval_mode = "prompt"
|
||||
"#,
|
||||
)
|
||||
.expect("write config");
|
||||
|
||||
let requirements = ConfigRequirementsToml {
|
||||
apps: Some(AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.fallback_cwd(Some(codex_home.path().to_path_buf()))
|
||||
.cloud_requirements(CloudRequirementsLoader::new(async move {
|
||||
Ok(Some(requirements))
|
||||
}))
|
||||
.build()
|
||||
.await
|
||||
.expect("config should build");
|
||||
|
||||
let policy = app_tool_policy(
|
||||
&config,
|
||||
Some("connector_123123"),
|
||||
"calendar/list_events",
|
||||
/*tool_title*/ None,
|
||||
/*annotations*/ None,
|
||||
);
|
||||
assert_eq!(
|
||||
policy,
|
||||
AppToolPolicy {
|
||||
enabled: true,
|
||||
approval: AppToolApproval::Approve,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn local_requirements_tool_approval_overrides_user_apps_config() {
|
||||
let codex_home = tempdir().expect("tempdir should succeed");
|
||||
let config_toml_path =
|
||||
AbsolutePathBuf::try_from(codex_home.path().join(CONFIG_TOML_FILE)).expect("abs path");
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.fallback_cwd(Some(codex_home.path().to_path_buf()))
|
||||
.build()
|
||||
.await
|
||||
.expect("config should build");
|
||||
|
||||
let requirements = ConfigRequirementsToml {
|
||||
apps: Some(AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
config.config_layer_stack =
|
||||
ConfigLayerStack::new(Vec::new(), ConfigRequirements::default(), requirements)
|
||||
.expect("requirements stack")
|
||||
.with_user_config(
|
||||
&config_toml_path,
|
||||
toml::from_str::<toml::Value>(
|
||||
r#"
|
||||
[apps.connector_123123.tools."calendar/list_events"]
|
||||
approval_mode = "prompt"
|
||||
"#,
|
||||
)
|
||||
.expect("apps config"),
|
||||
);
|
||||
|
||||
let policy = app_tool_policy(
|
||||
&config,
|
||||
Some("connector_123123"),
|
||||
"calendar/list_events",
|
||||
/*tool_title*/ None,
|
||||
/*annotations*/ None,
|
||||
);
|
||||
assert_eq!(
|
||||
policy,
|
||||
AppToolPolicy {
|
||||
enabled: true,
|
||||
approval: AppToolApproval::Approve,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn local_requirements_tool_approval_does_not_match_tool_title() {
|
||||
let codex_home = tempdir().expect("tempdir should succeed");
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.fallback_cwd(Some(codex_home.path().to_path_buf()))
|
||||
.build()
|
||||
.await
|
||||
.expect("config should build");
|
||||
|
||||
let requirements = ConfigRequirementsToml {
|
||||
apps: Some(AppsRequirementsToml {
|
||||
apps: BTreeMap::from([(
|
||||
"connector_123123".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: None,
|
||||
tools: Some(AppToolsRequirementsToml {
|
||||
tools: BTreeMap::from([(
|
||||
"calendar/list_events".to_string(),
|
||||
AppToolRequirementToml {
|
||||
approval_mode: Some(AppToolApproval::Approve),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
config.config_layer_stack =
|
||||
ConfigLayerStack::new(Vec::new(), ConfigRequirements::default(), requirements)
|
||||
.expect("requirements stack");
|
||||
|
||||
let policy = app_tool_policy(
|
||||
&config,
|
||||
Some("connector_123123"),
|
||||
"calendar/create_event",
|
||||
Some("calendar/list_events"),
|
||||
/*annotations*/ None,
|
||||
);
|
||||
assert_eq!(
|
||||
policy,
|
||||
AppToolPolicy {
|
||||
enabled: true,
|
||||
approval: AppToolApproval::Auto,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_tool_policy_allows_per_app_enable_when_default_is_disabled() {
|
||||
let apps_config = AppsConfigToml {
|
||||
|
||||
@@ -1916,6 +1916,7 @@ async fn apps_initial_load_applies_enabled_state_from_requirements_with_user_ove
|
||||
"connector_1".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
@@ -1989,6 +1990,7 @@ async fn apps_initial_load_applies_enabled_state_from_requirements_without_user_
|
||||
"connector_1".to_string(),
|
||||
AppRequirementToml {
|
||||
enabled: Some(false),
|
||||
tools: None,
|
||||
},
|
||||
)]),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user