diff --git a/codex-rs/core/src/config_loader/layer_io.rs b/codex-rs/core/src/config_loader/layer_io.rs index 1e9052f21..58ccab194 100644 --- a/codex-rs/core/src/config_loader/layer_io.rs +++ b/codex-rs/core/src/config_loader/layer_io.rs @@ -1,4 +1,5 @@ use super::LoaderOverrides; +#[cfg(target_os = "macos")] use super::macos::load_managed_admin_config_layer; use super::overrides::default_empty_table; use crate::config::CONFIG_TOML_FILE; @@ -45,7 +46,7 @@ pub(super) async fn load_config_layers_internal( load_managed_admin_config_layer(managed_preferences_base64.as_deref()).await?; #[cfg(not(target_os = "macos"))] - let managed_preferences = load_managed_admin_config_layer(None).await?; + let managed_preferences = None; Ok(LoadedConfigLayers { base: user_config.unwrap_or_else(default_empty_table), diff --git a/codex-rs/core/src/config_loader/macos.rs b/codex-rs/core/src/config_loader/macos.rs index 036619e06..4a80267b9 100644 --- a/codex-rs/core/src/config_loader/macos.rs +++ b/codex-rs/core/src/config_loader/macos.rs @@ -1,118 +1,100 @@ +use base64::Engine; +use base64::prelude::BASE64_STANDARD; +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::string::CFStringRef; +use std::ffi::c_void; use std::io; +use tokio::task; use toml::Value as TomlValue; -#[cfg(target_os = "macos")] -mod native { - use super::*; - use base64::Engine; - use base64::prelude::BASE64_STANDARD; - use core_foundation::base::TCFType; - use core_foundation::string::CFString; - use core_foundation::string::CFStringRef; - use std::ffi::c_void; - use tokio::task; +const MANAGED_PREFERENCES_APPLICATION_ID: &str = "com.openai.codex"; +const MANAGED_PREFERENCES_CONFIG_KEY: &str = "config_toml_base64"; - pub(crate) async fn load_managed_admin_config_layer( - override_base64: Option<&str>, - ) -> io::Result> { - if let Some(encoded) = override_base64 { - let trimmed = encoded.trim(); - return if trimmed.is_empty() { - Ok(None) - } else { - parse_managed_preferences_base64(trimmed).map(Some) - }; - } - - const LOAD_ERROR: &str = "Failed to load managed preferences configuration"; - - match task::spawn_blocking(load_managed_admin_config).await { - Ok(result) => result, - Err(join_err) => { - if join_err.is_cancelled() { - tracing::error!("Managed preferences load task was cancelled"); - } else { - tracing::error!("Managed preferences load task failed: {join_err}"); - } - Err(io::Error::other(LOAD_ERROR)) - } - } - } - - pub(super) fn load_managed_admin_config() -> io::Result> { - #[link(name = "CoreFoundation", kind = "framework")] - unsafe extern "C" { - fn CFPreferencesCopyAppValue( - key: CFStringRef, - application_id: CFStringRef, - ) -> *mut c_void; - } - - const MANAGED_PREFERENCES_APPLICATION_ID: &str = "com.openai.codex"; - const MANAGED_PREFERENCES_CONFIG_KEY: &str = "config_toml_base64"; - - let application_id = CFString::new(MANAGED_PREFERENCES_APPLICATION_ID); - let key = CFString::new(MANAGED_PREFERENCES_CONFIG_KEY); - - let value_ref = unsafe { - CFPreferencesCopyAppValue( - key.as_concrete_TypeRef(), - application_id.as_concrete_TypeRef(), - ) - }; - - if value_ref.is_null() { - tracing::debug!( - "Managed preferences for {} key {} not found", - MANAGED_PREFERENCES_APPLICATION_ID, - MANAGED_PREFERENCES_CONFIG_KEY - ); - return Ok(None); - } - - let value = unsafe { CFString::wrap_under_create_rule(value_ref as _) }; - let contents = value.to_string(); - let trimmed = contents.trim(); - - parse_managed_preferences_base64(trimmed).map(Some) - } - - pub(super) fn parse_managed_preferences_base64(encoded: &str) -> io::Result { - let decoded = BASE64_STANDARD.decode(encoded.as_bytes()).map_err(|err| { - tracing::error!("Failed to decode managed preferences as base64: {err}"); - io::Error::new(io::ErrorKind::InvalidData, err) - })?; - - let decoded_str = String::from_utf8(decoded).map_err(|err| { - tracing::error!("Managed preferences base64 contents were not valid UTF-8: {err}"); - io::Error::new(io::ErrorKind::InvalidData, err) - })?; - - match toml::from_str::(&decoded_str) { - Ok(TomlValue::Table(parsed)) => Ok(TomlValue::Table(parsed)), - Ok(other) => { - tracing::error!( - "Managed preferences TOML must have a table at the root, found {other:?}", - ); - Err(io::Error::new( - io::ErrorKind::InvalidData, - "managed preferences root must be a table", - )) - } - Err(err) => { - tracing::error!("Failed to parse managed preferences TOML: {err}"); - Err(io::Error::new(io::ErrorKind::InvalidData, err)) - } - } - } -} - -#[cfg(target_os = "macos")] -pub(crate) use native::load_managed_admin_config_layer; - -#[cfg(not(target_os = "macos"))] pub(crate) async fn load_managed_admin_config_layer( - _override_base64: Option<&str>, + override_base64: Option<&str>, ) -> io::Result> { - Ok(None) + if let Some(encoded) = override_base64 { + let trimmed = encoded.trim(); + return if trimmed.is_empty() { + Ok(None) + } else { + parse_managed_preferences_base64(trimmed).map(Some) + }; + } + + const LOAD_ERROR: &str = "Failed to load managed preferences configuration"; + + match task::spawn_blocking(load_managed_admin_config).await { + Ok(result) => result, + Err(join_err) => { + if join_err.is_cancelled() { + tracing::error!("Managed preferences load task was cancelled"); + } else { + tracing::error!("Managed preferences load task failed: {join_err}"); + } + Err(io::Error::other(LOAD_ERROR)) + } + } +} + +fn load_managed_admin_config() -> io::Result> { + #[link(name = "CoreFoundation", kind = "framework")] + unsafe extern "C" { + fn CFPreferencesCopyAppValue(key: CFStringRef, application_id: CFStringRef) -> *mut c_void; + } + + let application_id = CFString::new(MANAGED_PREFERENCES_APPLICATION_ID); + let key = CFString::new(MANAGED_PREFERENCES_CONFIG_KEY); + + let value_ref = unsafe { + CFPreferencesCopyAppValue( + key.as_concrete_TypeRef(), + application_id.as_concrete_TypeRef(), + ) + }; + + if value_ref.is_null() { + tracing::debug!( + "Managed preferences for {} key {} not found", + MANAGED_PREFERENCES_APPLICATION_ID, + MANAGED_PREFERENCES_CONFIG_KEY + ); + return Ok(None); + } + + let value = unsafe { CFString::wrap_under_create_rule(value_ref as _) }; + let contents = value.to_string(); + let trimmed = contents.trim(); + + parse_managed_preferences_base64(trimmed).map(Some) +} + +fn parse_managed_preferences_base64(encoded: &str) -> io::Result { + let decoded = BASE64_STANDARD.decode(encoded.as_bytes()).map_err(|err| { + tracing::error!("Failed to decode managed preferences as base64: {err}"); + io::Error::new(io::ErrorKind::InvalidData, err) + })?; + + let decoded_str = String::from_utf8(decoded).map_err(|err| { + tracing::error!("Managed preferences base64 contents were not valid UTF-8: {err}"); + io::Error::new(io::ErrorKind::InvalidData, err) + })?; + + match toml::from_str::(&decoded_str) { + Ok(TomlValue::Table(parsed)) => Ok(TomlValue::Table(parsed)), + Ok(other) => { + tracing::error!( + "Managed preferences TOML must have a table at the root, found {other:?}", + ); + Err(io::Error::new( + io::ErrorKind::InvalidData, + "managed preferences root must be a table", + )) + } + Err(err) => { + tracing::error!("Failed to parse managed preferences TOML: {err}"); + Err(io::Error::new(io::ErrorKind::InvalidData, err)) + } + } } diff --git a/codex-rs/core/src/config_loader/mod.rs b/codex-rs/core/src/config_loader/mod.rs index 2c3634ea0..19af4c729 100644 --- a/codex-rs/core/src/config_loader/mod.rs +++ b/codex-rs/core/src/config_loader/mod.rs @@ -1,5 +1,6 @@ mod fingerprint; mod layer_io; +#[cfg(target_os = "macos")] mod macos; mod merge; mod overrides;