use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum AskForApproval {
#[serde(rename = "untrusted")]
UnlessTrusted,
#[default]
OnRequest,
Granular(GranularApprovalConfig),
Never,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct GranularApprovalConfig {
pub sandbox_approval: bool,
pub rules: bool,
#[serde(default)]
pub skill_approval: bool,
#[serde(default)]
pub request_permissions: bool,
pub mcp_elicitations: bool,
}
impl GranularApprovalConfig {
pub const fn allows_sandbox_approval(self) -> bool {
self.sandbox_approval
}
pub const fn allows_rules_approval(self) -> bool {
self.rules
}
pub const fn allows_skill_approval(self) -> bool {
self.skill_approval
}
pub const fn allows_request_permissions(self) -> bool {
self.request_permissions
}
pub const fn allows_mcp_elicitations(self) -> bool {
self.mcp_elicitations
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum NetworkAccess {
#[default]
Restricted,
Enabled,
}
impl NetworkAccess {
pub const fn is_enabled(self) -> bool {
matches!(self, Self::Enabled)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ask_for_approval_keeps_codex_wire_tags() {
assert_eq!(
serde_json::to_value(AskForApproval::UnlessTrusted).unwrap(),
serde_json::json!("untrusted")
);
assert_eq!(
serde_json::to_value(AskForApproval::OnRequest).unwrap(),
serde_json::json!("on-request")
);
assert_eq!(
serde_json::to_value(AskForApproval::Never).unwrap(),
serde_json::json!("never")
);
assert_eq!(
serde_json::from_value::<AskForApproval>(serde_json::json!("untrusted")).unwrap(),
AskForApproval::UnlessTrusted
);
}
#[test]
fn ask_for_approval_defaults_to_on_request() {
assert_eq!(AskForApproval::default(), AskForApproval::OnRequest);
}
#[test]
fn granular_approval_config_round_trips() {
let config = GranularApprovalConfig {
sandbox_approval: true,
rules: false,
skill_approval: true,
request_permissions: false,
mcp_elicitations: true,
};
let ask = AskForApproval::Granular(config);
let value = serde_json::to_value(ask).unwrap();
let back: AskForApproval = serde_json::from_value(value).unwrap();
assert_eq!(back, ask);
assert!(config.allows_sandbox_approval());
assert!(!config.allows_rules_approval());
assert!(config.allows_skill_approval());
assert!(!config.allows_request_permissions());
assert!(config.allows_mcp_elicitations());
}
#[test]
fn network_access_keeps_kebab_case_wire_tags() {
assert_eq!(
serde_json::to_value(NetworkAccess::Restricted).unwrap(),
serde_json::json!("restricted")
);
assert_eq!(
serde_json::to_value(NetworkAccess::Enabled).unwrap(),
serde_json::json!("enabled")
);
assert!(!NetworkAccess::Restricted.is_enabled());
assert!(NetworkAccess::Enabled.is_enabled());
assert_eq!(NetworkAccess::default(), NetworkAccess::Restricted);
}
}