use super::super::RequirementsLayerEntry; use super::super::hooks::HookDirectoryField; use super::RequirementsCompositionError; use super::compose_requirements_for_hostname; use super::compose_requirements_for_hostname_and_hook_directory; use crate::ConfigRequirementsToml; use crate::ConfigRequirementsWithSources; use crate::RequirementSource; use crate::ShellEnvironmentPolicyRequirementsToml; use crate::Sourced; use codex_protocol::config_types::ShellEnvironmentPolicyRule; use codex_protocol::protocol::AskForApproval; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; use std::collections::BTreeMap; fn layer(id: &str, name: &str, contents: &str) -> RequirementsLayerEntry { RequirementsLayerEntry::from_toml( RequirementSource::EnterpriseManaged { id: id.to_string(), name: name.to_string(), }, contents, ) } fn compose( layers: Vec, ) -> Result, RequirementsCompositionError> { Ok( compose_requirements_for_hostname(layers, /*hostname*/ None)? .map(ConfigRequirementsWithSources::into_toml), ) } fn compose_with_hook_directory_field( layers: Vec, hook_directory_field: HookDirectoryField, ) -> Result, RequirementsCompositionError> { Ok(compose_requirements_for_hostname_and_hook_directory( layers, /*hostname*/ None, hook_directory_field, )? .map(ConfigRequirementsWithSources::into_toml)) } fn expected_requirements(contents: impl AsRef) -> ConfigRequirementsToml { toml::from_str(contents.as_ref()).expect("parse expected requirements TOML") } #[test] fn empty_layers_compose_to_none() { let composed = compose(Vec::new()).expect("compose empty layers"); assert_eq!(composed, None); } #[test] fn top_level_values_use_toml_priority() { let composed = compose(vec![ layer( "req_low", "Low", r#" allowed_approval_policies = ["on-request"] allowed_sandbox_modes = ["workspace-write"] default_permissions = ":workspace" allow_remote_control = true [allowed_permission_profiles] ":read-only" = true ":workspace" = true "#, ), layer( "req_high", "High", r#" allowed_approval_policies = ["never"] allowed_sandbox_modes = ["read-only"] default_permissions = ":read-only" allow_remote_control = false [allowed_permission_profiles] ":danger-full-access" = false ":workspace" = false "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" allowed_approval_policies = ["never"] allowed_sandbox_modes = ["read-only"] default_permissions = ":read-only" allow_remote_control = false [allowed_permission_profiles] ":danger-full-access" = false ":read-only" = true ":workspace" = false "# ) ); } #[test] fn composition_strategy_applies_to_non_cloud_layers() { let mdm_source = RequirementSource::MdmManagedPreferences { domain: "com.openai.codex".to_string(), key: "requirements_toml_base64".to_string(), }; let system_file = if cfg!(windows) { "C:\\requirements.toml" } else { "/etc/codex/requirements.toml" }; let system_source = RequirementSource::SystemRequirementsToml { file: AbsolutePathBuf::from_absolute_path(system_file).expect("absolute path"), }; let high_path = if cfg!(windows) { "C:\\secret" } else { "/secret" }; let low_path = if cfg!(windows) { "C:\\other-secret" } else { "/other-secret" }; let composed = compose_requirements_for_hostname( vec![ RequirementsLayerEntry::from_toml( system_source, format!( r#" allowed_approval_policies = ["on-request"] allow_remote_control = true [features] shared = false system = true [[rules.prefix_rules]] pattern = [{{ token = "npm" }}] decision = "prompt" [permissions.filesystem] deny_read = [{low_path:?}] "# ), ), RequirementsLayerEntry::from_toml( mdm_source.clone(), format!( r#" allowed_approval_policies = ["never"] allow_remote_control = false [features] shared = true [[rules.prefix_rules]] pattern = [{{ token = "git" }}] decision = "forbidden" [permissions.filesystem] deny_read = [{high_path:?}] "# ), ), ], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.clone().into_toml(), expected_requirements(format!( r#" allowed_approval_policies = ["never"] allow_remote_control = false [features] shared = true system = true [[rules.prefix_rules]] pattern = [{{ token = "git" }}] decision = "forbidden" [[rules.prefix_rules]] pattern = [{{ token = "npm" }}] decision = "prompt" [permissions.filesystem] deny_read = [{high_path:?}, {low_path:?}] "# )) ); assert_eq!( composed.allowed_approval_policies, Some(Sourced::new( vec![AskForApproval::Never], mdm_source.clone() )) ); assert_eq!( composed.allow_remote_control, Some(Sourced::new(/*value*/ false, mdm_source)) ); } #[test] fn single_regular_layer_keeps_enterprise_managed_source() { let composed = compose_requirements_for_hostname( vec![layer( "req_1", "Security baseline", r#" allow_managed_hooks_only = true "#, )], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.allow_managed_hooks_only, Some(Sourced::new( /*value*/ true, RequirementSource::EnterpriseManaged { id: "req_1".to_string(), name: "Security baseline".to_string(), }, )) ); } #[test] fn regular_toml_merge_recurses_into_tables() { let composed = compose(vec![ layer( "req_low", "Low", r#" [features] beta = false shared = false [apps.connector_1] enabled = false [apps.connector_1.tools.search] approval_mode = "prompt" [apps.connector_1.tools.list] approval_mode = "prompt" "#, ), layer( "req_high", "High", r#" [features] alpha = true shared = true [apps.connector_1] enabled = true [apps.connector_1.tools.search] approval_mode = "approve" "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [features] alpha = true beta = false shared = true [apps.connector_1] enabled = true [apps.connector_1.tools.list] approval_mode = "prompt" [apps.connector_1.tools.search] approval_mode = "approve" "# ) ); } #[test] fn merged_table_source_is_composite_in_priority_order() { let high_source = RequirementSource::EnterpriseManaged { id: "req_high".to_string(), name: "High".to_string(), }; let low_source = RequirementSource::EnterpriseManaged { id: "req_low".to_string(), name: "Low".to_string(), }; let composed = compose_requirements_for_hostname( vec![ RequirementsLayerEntry::from_toml( low_source.clone(), r#" [features] beta = true "#, ), RequirementsLayerEntry::from_toml( high_source.clone(), r#" [features] alpha = true "#, ), ], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.feature_requirements.expect("features"), Sourced::new( crate::FeatureRequirementsToml { entries: BTreeMap::from([("alpha".to_string(), true), ("beta".to_string(), true),]), }, RequirementSource::composite([high_source, low_source]), ) ); } #[test] fn mcp_requirements_use_regular_toml_merge() { let composed = compose(vec![ layer( "req_low", "Low", r#" [mcp_servers.shared.identity] command = "low-mcp" [mcp_servers.low.identity] url = "https://low.example.com/mcp" "#, ), layer( "req_high", "High", r#" [mcp_servers.shared.identity] command = "high-mcp" "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [mcp_servers.low.identity] url = "https://low.example.com/mcp" [mcp_servers.shared.identity] command = "high-mcp" "# ) ); } #[test] fn network_maps_use_regular_toml_merge() { let composed = compose(vec![ layer( "req_low", "Low", r#" [experimental_network.domains] "example.com" = "deny" "low.example.com" = "deny" "internal.example.com" = "allow" [experimental_network.unix_sockets] "/tmp/shared.sock" = "deny" "/tmp/low.sock" = "allow" "/tmp/admin.sock" = "allow" "#, ), layer( "req_high", "High", r#" [experimental_network.domains] "example.com" = "allow" "high.example.com" = "allow" "internal.example.com" = "deny" [experimental_network.unix_sockets] "/tmp/shared.sock" = "allow" "/tmp/high.sock" = "allow" "/tmp/admin.sock" = "deny" "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [experimental_network.domains] "example.com" = "allow" "high.example.com" = "allow" "internal.example.com" = "deny" "low.example.com" = "deny" [experimental_network.unix_sockets] "/tmp/admin.sock" = "deny" "/tmp/high.sock" = "allow" "/tmp/low.sock" = "allow" "/tmp/shared.sock" = "allow" "# ) ); } #[test] fn windows_requirements_use_regular_toml_merge() { let composed = compose(vec![ layer( "req_low", "Low", r#" [windows] allowed_sandbox_implementations = ["unelevated"] "#, ), layer( "req_high", "High", r#" [windows] allowed_sandbox_implementations = ["elevated"] "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [windows] allowed_sandbox_implementations = ["elevated"] "# ) ); } #[test] fn remote_sandbox_config_is_applied_per_layer() { let composed = compose_requirements_for_hostname( vec![ layer( "req_low", "Low", r#" allowed_sandbox_modes = ["read-only"] "#, ), layer( "req_high", "High", r#" [[remote_sandbox_config]] hostname_patterns = ["build-*.example.com"] allowed_sandbox_modes = ["workspace-write"] "#, ), ], Some("BUILD-01.EXAMPLE.COM."), ) .expect("compose requirements") .expect("requirements present") .into_toml(); assert_eq!( composed, expected_requirements( r#" allowed_sandbox_modes = ["workspace-write"] "# ) ); } #[test] fn unmatched_remote_sandbox_config_does_not_shadow_lower_layers() { let composed = compose_requirements_for_hostname( vec![ layer( "req_low", "Low", r#" allowed_sandbox_modes = ["read-only"] "#, ), layer( "req_high", "High", r#" [[remote_sandbox_config]] hostname_patterns = ["mac-*.example.com"] allowed_sandbox_modes = ["workspace-write"] "#, ), ], Some("linux-01.example.com"), ) .expect("compose requirements") .expect("requirements present") .into_toml(); assert_eq!( composed, expected_requirements( r#" allowed_sandbox_modes = ["read-only"] "# ) ); } #[test] fn rules_are_appended_in_priority_order() { let composed = compose(vec![ layer( "req_low", "Low", r#" [[rules.prefix_rules]] pattern = [{ token = "npm" }] decision = "prompt" "#, ), layer( "req_high", "High", r#" [[rules.prefix_rules]] pattern = [{ token = "git" }] decision = "forbidden" "#, ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [[rules.prefix_rules]] pattern = [{ token = "git" }] decision = "forbidden" [[rules.prefix_rules]] pattern = [{ token = "npm" }] decision = "prompt" "# ) ); } #[test] fn hooks_append_groups_and_reject_conflicting_managed_dirs() { let composed = compose_with_hook_directory_field( vec![ layer( "req_low", "Low", r#" [hooks] managed_dir = "/managed/hooks" [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "#, ), layer( "req_high", "High", r#" [hooks] managed_dir = "/managed/hooks" [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" "#, ), ], HookDirectoryField::ManagedDir, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [hooks] managed_dir = "/managed/hooks" [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "# ) ); let err = compose_with_hook_directory_field( vec![ layer( "req_low", "Low", r#" [hooks] managed_dir = "/managed/low" "#, ), layer( "req_high", "High", r#" [hooks] managed_dir = "/managed/high" "#, ), ], HookDirectoryField::ManagedDir, ) .expect_err("conflicting managed dirs should fail closed"); assert!(err.to_string().contains("hooks.managed_dir")); assert!(err.to_string().contains("High (req_high)")); assert!(err.to_string().contains("Low (req_low)")); } #[test] fn active_windows_managed_dir_conflicts_fail_closed() { let err = compose_with_hook_directory_field( vec![ layer( "req_low", "Low", r#" [hooks] windows_managed_dir = 'C:\managed\low' "#, ), layer( "req_high", "High", r#" [hooks] windows_managed_dir = 'C:\managed\high' "#, ), ], HookDirectoryField::WindowsManagedDir, ) .expect_err("conflicting windows managed dirs should fail closed"); assert!(err.to_string().contains("hooks.windows_managed_dir")); assert!(err.to_string().contains("High (req_high)")); assert!(err.to_string().contains("Low (req_low)")); } #[test] fn inactive_hook_dir_conflicts_do_not_fail_composition() { let composed = compose_with_hook_directory_field( vec![ layer( "req_low", "Low", r#" [hooks] managed_dir = "/managed/hooks" windows_managed_dir = 'C:\managed\low' [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "#, ), layer( "req_high", "High", r#" [hooks] managed_dir = "/managed/hooks" windows_managed_dir = 'C:\managed\high' [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" "#, ), ], HookDirectoryField::ManagedDir, ) .expect("inactive windows managed dir conflict should not fail") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [hooks] managed_dir = "/managed/hooks" windows_managed_dir = 'C:\managed\high' [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "# ) ); let composed = compose_with_hook_directory_field( vec![ layer( "req_low", "Low", r#" [hooks] managed_dir = "/managed/low" windows_managed_dir = 'C:\managed\hooks' [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "#, ), layer( "req_high", "High", r#" [hooks] managed_dir = "/managed/high" windows_managed_dir = 'C:\managed\hooks' [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" "#, ), ], HookDirectoryField::WindowsManagedDir, ) .expect("inactive managed dir conflict should not fail") .expect("requirements present"); assert_eq!( composed, expected_requirements( r#" [hooks] managed_dir = "/managed/high" windows_managed_dir = 'C:\managed\hooks' [[hooks.PreToolUse]] matcher = "Edit" [[hooks.PreToolUse.hooks]] type = "command" command = "high" [[hooks.PreToolUse]] matcher = "Bash" [[hooks.PreToolUse.hooks]] type = "command" command = "low" "# ) ); } #[test] fn permissions_deny_read_unions_while_profiles_use_regular_toml_merge() { let high_path = if cfg!(windows) { "C:\\secret" } else { "/secret" }; let low_path = if cfg!(windows) { "C:\\other-secret" } else { "/other-secret" }; let composed = compose(vec![ layer( "req_low", "Low", &format!( r#" [permissions.filesystem] deny_read = [{high_path:?}, {low_path:?}] [permissions.managed-standard] description = "Low profile" extends = ":workspace" "# ), ), layer( "req_high", "High", &format!( r#" [permissions.filesystem] deny_read = [{high_path:?}] [permissions.managed-standard] description = "High profile" "# ), ), ]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements(format!( r#" [permissions.filesystem] deny_read = [{high_path:?}, {low_path:?}] [permissions.managed-standard] description = "High profile" extends = ":workspace" "# )) ); } #[test] fn deny_read_only_layers_do_not_leave_empty_permissions_tables() { let path = if cfg!(windows) { "C:\\secret" } else { "/secret" }; let composed = compose(vec![layer( "req_high", "High", &format!( r#" [permissions.filesystem] deny_read = [{path:?}] "# ), )]) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed, expected_requirements(format!( r#" [permissions.filesystem] deny_read = [{path:?}] "# )) ); } #[test] fn parse_error_names_layer() { let err = compose(vec![layer( "req_bad", "Bad layer", "allowed_approval_policies = [1]", )]) .expect_err("invalid layer should fail"); assert!(err.to_string().contains("Bad layer (req_bad)")); assert!(err.to_string().contains("allowed_approval_policies")); } #[test] fn managed_config_table_is_composed_and_sourced() { let high_source = RequirementSource::EnterpriseManaged { id: "req_high".to_string(), name: "High".to_string(), }; let low_source = RequirementSource::EnterpriseManaged { id: "req_low".to_string(), name: "Low".to_string(), }; let composed = compose_requirements_for_hostname( vec![ RequirementsLayerEntry::from_toml( low_source.clone(), r#" [allowed_login_methods] chatgpt = true api = true "#, ), RequirementsLayerEntry::from_toml( high_source.clone(), r#" [allowed_login_methods] api = false "#, ), ], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.allowed_login_methods, Some(Sourced::new( BTreeMap::from([("api".to_string(), false), ("chatgpt".to_string(), true),]), RequirementSource::composite([high_source, low_source]), )) ); } #[test] fn otel_exporters_replace_atomically_across_layers() { let high_source = RequirementSource::EnterpriseManaged { id: "req_high".to_string(), name: "High".to_string(), }; let low_source = RequirementSource::EnterpriseManaged { id: "req_low".to_string(), name: "Low".to_string(), }; let composed = compose_requirements_for_hostname( vec![ RequirementsLayerEntry::from_toml( low_source.clone(), r#" [otel] log_user_prompt = true environment = "low" exporter = { otlp-http = { endpoint = "https://logs.low.example", protocol = "binary", headers = { Authorization = "old-secret" } } } trace_exporter = { otlp-http = { endpoint = "https://traces.low.example", protocol = "json", headers = { Trace = "old-trace" } } } metrics_exporter = { otlp-grpc = { endpoint = "https://metrics.low.example", headers = { Metrics = "old-metrics" } } } [otel.span_attributes] region = "us" team = "low" [otel.tracestate.vendor] low = "one" shared = "low" "#, ), RequirementsLayerEntry::from_toml( high_source.clone(), r#" [otel] environment = "high" exporter = { otlp-grpc = { endpoint = "https://logs.high.example" } } trace_exporter = { otlp-http = { endpoint = "https://traces.high.example", protocol = "binary" } } metrics_exporter = "none" [otel.span_attributes] team = "high" [otel.tracestate.vendor] high = "two" shared = "high" "#, ), ], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.otel, Some(Sourced::new( expected_requirements( r#" [otel] log_user_prompt = true environment = "high" exporter = { otlp-grpc = { endpoint = "https://logs.high.example" } } trace_exporter = { otlp-http = { endpoint = "https://traces.high.example", protocol = "binary" } } metrics_exporter = "none" [otel.span_attributes] region = "us" team = "high" [otel.tracestate.vendor] high = "two" low = "one" shared = "high" "#, ) .otel .expect("expected OTEL requirements"), RequirementSource::composite([high_source, low_source]), )) ); } #[test] fn shell_environment_rules_compose_by_pattern() { let high_source = RequirementSource::EnterpriseManaged { id: "req_high".to_string(), name: "High".to_string(), }; let low_source = RequirementSource::EnterpriseManaged { id: "req_low".to_string(), name: "Low".to_string(), }; let composed = compose_requirements_for_hostname( vec![ RequirementsLayerEntry::from_toml( low_source.clone(), r#" [shell_environment_policy.rules] "FLIP_*" = "exclude" "KEEP_*" = "include" "#, ), RequirementsLayerEntry::from_toml( high_source.clone(), r#" [shell_environment_policy.rules] "ADD_*" = "exclude" "FLIP_*" = "include" "#, ), ], /*hostname*/ None, ) .expect("compose requirements") .expect("requirements present"); assert_eq!( composed.shell_environment_policy, Some(Sourced::new( ShellEnvironmentPolicyRequirementsToml { rules: Some(BTreeMap::from([ ("ADD_*".to_string(), ShellEnvironmentPolicyRule::Exclude,), ("FLIP_*".to_string(), ShellEnvironmentPolicyRule::Include,), ("KEEP_*".to_string(), ShellEnvironmentPolicyRule::Include,), ])), ..Default::default() }, RequirementSource::composite([high_source, low_source]), )) ); }