Expand ~ in MDM workspace write roots (#15351)

## Summary
- Reuse the existing config path resolver for the macOS MDM managed
preferences layer so `writable_roots = ["~/code"]` expands the same way
as file-backed config
- keep the change scoped to the MDM branch in `config_loader`; the
current net diff is only `config_loader/mod.rs` plus focused regression
tests in `config_loader/tests.rs` and `config/service_tests.rs`
- research note: `resolve_relative_paths_in_config_toml(...)` is already
used in several existing configuration paths, including [CLI
overrides](https://github.com/openai/codex/blob/74fda242d3651f0a43ec8657bdbc7bde426dce0e/codex-rs/core/src/config_loader/mod.rs#L152-L163),
[file-backed managed
config](https://github.com/openai/codex/blob/74fda242d3651f0a43ec8657bdbc7bde426dce0e/codex-rs/core/src/config_loader/mod.rs#L274-L285),
[normal config-file
loading](https://github.com/openai/codex/blob/74fda242d3651f0a43ec8657bdbc7bde426dce0e/codex-rs/core/src/config_loader/mod.rs#L311-L331),
[project `.codex/config.toml`
loading](https://github.com/openai/codex/blob/74fda242d3651f0a43ec8657bdbc7bde426dce0e/codex-rs/core/src/config_loader/mod.rs#L863-L865),
and [role config
loading](https://github.com/openai/codex/blob/74fda242d3651f0a43ec8657bdbc7bde426dce0e/codex-rs/core/src/agent/role.rs#L105-L109)

## Validation
- `cargo fmt --all --check`
- `cargo test -p codex-core
managed_preferences_expand_home_directory_in_workspace_write_roots --
--nocapture`
- `cargo test -p codex-core
write_value_succeeds_when_managed_preferences_expand_home_directory_paths
-- --nocapture`

---------

Co-authored-by: Michael Bolin <mbolin@openai.com>
Co-authored-by: Michael Bolin <bolinfest@gmail.com>
This commit is contained in:
evawong-oai
2026-03-24 17:55:06 -07:00
committed by GitHub
Unverified
parent 38b638d89d
commit ea3f3467e2
3 changed files with 99 additions and 1 deletions
+48
View File
@@ -237,6 +237,54 @@ async fn read_includes_origins_and_layers() {
));
}
#[cfg(target_os = "macos")]
#[tokio::test]
async fn write_value_succeeds_when_managed_preferences_expand_home_directory_paths() -> Result<()> {
use base64::Engine;
let tmp = tempdir().expect("tempdir");
std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "model = \"user\"\n")?;
let service = ConfigService::new(
tmp.path().to_path_buf(),
vec![],
LoaderOverrides {
managed_config_path: Some(tmp.path().join("managed_config.toml")),
managed_preferences_base64: Some(
base64::prelude::BASE64_STANDARD.encode(
r#"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
writable_roots = ["~/code"]
"#
.as_bytes(),
),
),
macos_managed_config_requirements_base64: None,
},
CloudRequirementsLoader::default(),
);
let response = service
.write_value(ConfigValueWriteParams {
file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()),
key_path: "model".to_string(),
value: serde_json::json!("updated"),
merge_strategy: MergeStrategy::Replace,
expected_version: None,
})
.await
.expect("write succeeds");
assert_eq!(response.status, WriteStatus::Ok);
assert_eq!(
std::fs::read_to_string(tmp.path().join(CONFIG_TOML_FILE)).expect("read config"),
"model = \"updated\"\n"
);
Ok(())
}
#[tokio::test]
async fn write_value_reports_override() {
let tmp = tempdir().expect("tempdir");