Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions codex-rs/core/src/config_loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ const DEFAULT_PROJECT_ROOT_MARKERS: &[&str] = &[".git"];
/// configuration layers in the following order, but a constraint defined in an
/// earlier layer cannot be overridden by a later layer:
///
/// - admin: managed preferences (*)
/// - cloud: managed cloud requirements
/// - admin: managed preferences (*)
/// - system `/etc/codex/requirements.toml`
///
/// For backwards compatibility, we also load from
Expand Down Expand Up @@ -107,6 +107,11 @@ pub async fn load_config_layers_state(
) -> io::Result<ConfigLayerStack> {
let mut config_requirements_toml = ConfigRequirementsWithSources::default();

if let Some(requirements) = cloud_requirements.get().await {
config_requirements_toml
.merge_unset_fields(RequirementSource::CloudRequirements, requirements);
}

#[cfg(target_os = "macos")]
macos::load_managed_admin_requirements_toml(
&mut config_requirements_toml,
Expand All @@ -116,11 +121,6 @@ pub async fn load_config_layers_state(
)
.await?;

if let Some(requirements) = cloud_requirements.get().await {
config_requirements_toml
.merge_unset_fields(RequirementSource::CloudRequirements, requirements);
}

// Honor /etc/codex/requirements.toml.
if cfg!(unix) {
load_requirements_toml(
Expand Down
53 changes: 53 additions & 0 deletions codex-rs/core/src/config_loader/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,59 @@ enforce_residency = "us"
Ok(())
}

#[cfg(target_os = "macos")]
#[tokio::test]
async fn cloud_requirements_take_precedence_over_mdm_requirements() -> anyhow::Result<()> {
use base64::Engine;

let tmp = tempdir()?;
let state = load_config_layers_state(
tmp.path(),
Some(AbsolutePathBuf::try_from(tmp.path())?),
&[] as &[(String, TomlValue)],
LoaderOverrides {
macos_managed_config_requirements_base64: Some(
base64::prelude::BASE64_STANDARD.encode(
r#"
allowed_approval_policies = ["on-request"]
"#
.as_bytes(),
),
),
..LoaderOverrides::default()
},
CloudRequirementsLoader::new(async {
Some(ConfigRequirementsToml {
allowed_approval_policies: Some(vec![AskForApproval::Never]),
allowed_sandbox_modes: None,
mcp_servers: None,
rules: None,
enforce_residency: None,
})
}),
)
.await?;

assert_eq!(
state.requirements().approval_policy.value(),
AskForApproval::Never
);
assert_eq!(
state
.requirements()
.approval_policy
.can_set(&AskForApproval::OnRequest),
Err(ConstraintError::InvalidValue {
field_name: "approval_policy",
candidate: "OnRequest".into(),
allowed: "[Never]".into(),
requirement_source: RequirementSource::CloudRequirements,
})
);

Ok(())
}

#[tokio::test(flavor = "current_thread")]
async fn cloud_requirements_are_not_overwritten_by_system_requirements() -> anyhow::Result<()> {
let tmp = tempdir()?;
Expand Down
Loading