Codex Handbook
config/src/loader/macos.rs 223 lines
use crate::RequirementsLayerEntry;use crate::config_requirements::RequirementSource;use crate::config_toml::ConfigToml;use crate::diagnostics::ConfigDiagnosticSource;use crate::diagnostics::config_error_from_toml_for_source;use crate::diagnostics::io_error_from_config_error;use crate::strict_config::config_error_from_ignored_toml_value_fields_for_source_name;use base64::Engine;use base64::prelude::BASE64_STANDARD;use codex_utils_absolute_path::AbsolutePathBufGuard;use core_foundation::base::TCFType;use core_foundation::string::CFString;use core_foundation::string::CFStringRef;use std::ffi::c_void;use std::io;use std::path::Path;use tokio::task;use toml::Value as TomlValue;const MANAGED_PREFERENCES_APPLICATION_ID: &str = "com.openai.codex";const MANAGED_PREFERENCES_CONFIG_KEY: &str = "config_toml_base64";const MANAGED_PREFERENCES_REQUIREMENTS_KEY: &str = "requirements_toml_base64";#[derive(Debug, Clone)]pub(super) struct ManagedAdminConfigLayer {    pub config: TomlValue,    pub raw_toml: String,}pub(super) fn managed_preferences_requirements_source() -> RequirementSource {    RequirementSource::MdmManagedPreferences {        domain: MANAGED_PREFERENCES_APPLICATION_ID.to_string(),        key: MANAGED_PREFERENCES_REQUIREMENTS_KEY.to_string(),    }}pub(crate) async fn load_managed_admin_config_layer(    override_base64: Option<&str>,    strict_config: bool,    base_dir: &Path,) -> io::Result<Option<ManagedAdminConfigLayer>> {    if let Some(encoded) = override_base64 {        let trimmed = encoded.trim();        return if trimmed.is_empty() {            Ok(None)        } else {            parse_managed_config_base64(trimmed, strict_config, base_dir).map(Some)        };    }    let base_dir = base_dir.to_path_buf();    match task::spawn_blocking(move || load_managed_admin_config(strict_config, &base_dir)).await {        Ok(result) => result,        Err(join_err) => {            if join_err.is_cancelled() {                tracing::error!("Managed config load task was cancelled");            } else {                tracing::error!("Managed config load task failed: {join_err}");            }            Err(io::Error::other("Failed to load managed config"))        }    }}fn load_managed_admin_config(    strict_config: bool,    base_dir: &Path,) -> io::Result<Option<ManagedAdminConfigLayer>> {    load_managed_preference(MANAGED_PREFERENCES_CONFIG_KEY)?        .as_deref()        .map(str::trim)        .map(|encoded| parse_managed_config_base64(encoded, strict_config, base_dir))        .transpose()}pub(crate) async fn load_managed_admin_requirements_layer(    override_base64: Option<&str>,) -> io::Result<Option<RequirementsLayerEntry>> {    if let Some(encoded) = override_base64 {        let trimmed = encoded.trim();        if trimmed.is_empty() {            return Ok(None);        }        return parse_managed_requirements_base64(trimmed).map(|contents| {            Some(RequirementsLayerEntry::from_toml(                managed_preferences_requirements_source(),                contents,            ))        });    }    match task::spawn_blocking(load_managed_admin_requirements).await {        Ok(result) => Ok(result?.map(|contents| {            RequirementsLayerEntry::from_toml(managed_preferences_requirements_source(), contents)        })),        Err(join_err) => {            if join_err.is_cancelled() {                tracing::error!("Managed requirements load task was cancelled");            } else {                tracing::error!("Managed requirements load task failed: {join_err}");            }            Err(io::Error::other("Failed to load managed requirements"))        }    }}fn load_managed_admin_requirements() -> io::Result<Option<String>> {    load_managed_preference(MANAGED_PREFERENCES_REQUIREMENTS_KEY)?        .as_deref()        .map(str::trim)        .map(parse_managed_requirements_base64)        .transpose()}fn load_managed_preference(key_name: &str) -> io::Result<Option<String>> {    #[link(name = "CoreFoundation", kind = "framework")]    unsafe extern "C" {        fn CFPreferencesCopyAppValue(key: CFStringRef, application_id: CFStringRef) -> *mut c_void;    }    let value_ref = unsafe {        CFPreferencesCopyAppValue(            CFString::new(key_name).as_concrete_TypeRef(),            CFString::new(MANAGED_PREFERENCES_APPLICATION_ID).as_concrete_TypeRef(),        )    };    if value_ref.is_null() {        tracing::debug!(            "Managed preferences for {MANAGED_PREFERENCES_APPLICATION_ID} key {key_name} not found",        );        return Ok(None);    }    let value = unsafe { CFString::wrap_under_create_rule(value_ref as _) }.to_string();    Ok(Some(value))}fn parse_managed_config_base64(    encoded: &str,    strict_config: bool,    base_dir: &Path,) -> io::Result<ManagedAdminConfigLayer> {    let raw_toml = decode_managed_preferences_base64(encoded)?;    let source_name =        format!("{MANAGED_PREFERENCES_APPLICATION_ID}:{MANAGED_PREFERENCES_CONFIG_KEY}");    let parsed = toml::from_str::<TomlValue>(&raw_toml).map_err(|err| {        tracing::error!("Failed to parse managed config TOML: {err}");        if strict_config {            let config_error = config_error_from_toml_for_source(                ConfigDiagnosticSource::DisplayName(&source_name),                &raw_toml,                err.clone(),            );            io_error_from_config_error(io::ErrorKind::InvalidData, config_error, Some(err))        } else {            io::Error::new(io::ErrorKind::InvalidData, err)        }    })?;    validate_managed_config_toml_strictly_if_requested(        strict_config,        &source_name,        &raw_toml,        &parsed,        base_dir,    )?;    match parsed {        TomlValue::Table(parsed) => Ok(ManagedAdminConfigLayer {            config: TomlValue::Table(parsed),            raw_toml,        }),        other => {            tracing::error!("Managed config TOML must have a table at the root, found {other:?}",);            Err(io::Error::new(                io::ErrorKind::InvalidData,                "managed config root must be a table",            ))        }    }}fn validate_managed_config_toml_strictly_if_requested(    strict_config: bool,    source_name: &str,    raw_toml: &str,    parsed: &TomlValue,    base_dir: &Path,) -> io::Result<()> {    if !strict_config {        return Ok(());    }    let _guard = AbsolutePathBufGuard::new(base_dir);    if let Some(config_error) = config_error_from_ignored_toml_value_fields_for_source_name::<        ConfigToml,    >(source_name, raw_toml, parsed.clone())    {        Err(io_error_from_config_error(            io::ErrorKind::InvalidData,            config_error,            /*source*/ None,        ))    } else {        Ok(())    }}fn parse_managed_requirements_base64(encoded: &str) -> io::Result<String> {    decode_managed_preferences_base64(encoded)}fn decode_managed_preferences_base64(encoded: &str) -> io::Result<String> {    String::from_utf8(BASE64_STANDARD.decode(encoded.as_bytes()).map_err(|err| {        tracing::error!("Failed to decode managed value as base64: {err}",);        io::Error::new(io::ErrorKind::InvalidData, err)    })?)    .map_err(|err| {        tracing::error!("Managed value base64 contents were not valid UTF-8: {err}",);        io::Error::new(io::ErrorKind::InvalidData, err)    })}