Download codex-rs/config/src/requirements_layers/stack_tests.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 36.5 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/config/src/requirements_layers/stack_tests.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/config/src/requirements_layers/stack_tests.rs
-
curl -L -o stack_tests.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/config/src/requirements_layers/stack_tests.rs
36.5 kB
| 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 super::compose_requirements_with_hostname_resolver; | |
| use crate::ConfigRequirementsToml; | |
| use crate::ConfigRequirementsWithSources; | |
| use crate::RequirementSource; | |
| use crate::Sourced; | |
| use codex_protocol::protocol::AskForApproval; | |
| use codex_utils_absolute_path::AbsolutePathBuf; | |
| use pretty_assertions::assert_eq; | |
| use std::cell::Cell; | |
| use std::collections::BTreeMap; | |
| use tempfile::TempDir; | |
| use tempfile::tempdir; | |
| 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<RequirementsLayerEntry>, | |
| ) -> Result<Option<ConfigRequirementsToml>, RequirementsCompositionError> { | |
| Ok( | |
| compose_requirements_for_hostname(layers, /*hostname*/ None)? | |
| .map(ConfigRequirementsWithSources::into_toml), | |
| ) | |
| } | |
| fn compose_with_hook_directory_field( | |
| layers: Vec<RequirementsLayerEntry>, | |
| hook_directory_field: HookDirectoryField, | |
| ) -> Result<Option<ConfigRequirementsToml>, 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<str>) -> ConfigRequirementsToml { | |
| toml::from_str(contents.as_ref()).expect("parse expected requirements TOML") | |
| } | |
| fn empty_layers_compose_to_none() { | |
| let composed = compose(Vec::new()).expect("compose empty layers"); | |
| assert_eq!(composed, None); | |
| } | |
| fn cloud_auth_requirements_do_not_override_local_or_discard_other_policy() { | |
| let local = RequirementsLayerEntry::from_toml( | |
| RequirementSource::Unknown, | |
| r#"allowed_login_methods = ["api"] | |
| cli_auth_credentials_store = "keyring" | |
| chatgpt_base_url = "https://managed.example/backend-api/""#, | |
| ); | |
| for cloud_auth in [ | |
| r#"allowed_login_methods = ["api", "chatgpt"] | |
| allowed_chatgpt_workspaces = ["other"]"#, | |
| r#"allowed_login_methods = ["saml"] | |
| allowed_chatgpt_workspaces = "invalid" | |
| cli_auth_credentials_store = "invalid" | |
| chatgpt_base_url = false"#, | |
| ] { | |
| let cloud = layer( | |
| "req_cloud", | |
| "Cloud policy", | |
| &format!("{cloud_auth}\nallow_login_shell = false"), | |
| ); | |
| assert_eq!( | |
| compose(vec![local.clone(), cloud]) | |
| .expect("cloud auth cannot invalidate enterprise policy"), | |
| Some(expected_requirements( | |
| r#"allowed_login_methods = ["api"] | |
| cli_auth_credentials_store = "keyring" | |
| chatgpt_base_url = "https://managed.example/backend-api/" | |
| allow_login_shell = false"# | |
| )) | |
| ); | |
| } | |
| } | |
| 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 | |
| additional_developer_instructions = "Lower-priority instructions." | |
| [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 | |
| additional_developer_instructions = "" | |
| [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 | |
| additional_developer_instructions = "" | |
| [allowed_permission_profiles] | |
| ":danger-full-access" = false | |
| ":read-only" = true | |
| ":workspace" = false | |
| "# | |
| ) | |
| ); | |
| } | |
| fn new_thread_model_defaults_use_toml_priority() { | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| r#" | |
| [models.new_thread] | |
| model = "low-priority-model" | |
| model_reasoning_effort = "low" | |
| service_tier = "flex" | |
| "#, | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| r#" | |
| [models.new_thread] | |
| model = "high-priority-model" | |
| model_reasoning_effort = "high" | |
| service_tier = "fast" | |
| "#, | |
| ), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| [models.new_thread] | |
| model = "high-priority-model" | |
| model_reasoning_effort = "high" | |
| service_tier = "fast" | |
| "# | |
| ) | |
| ); | |
| } | |
| fn auto_review_required_models_are_unioned_without_overwriting_new_thread_defaults() { | |
| let low = layer( | |
| "req_low", | |
| "Low", | |
| r#"[auto_review] | |
| required_on_models = ["low-model", "shared-model"] | |
| [models.new_thread] | |
| model = "low-priority-model" | |
| model_reasoning_effort = "low""#, | |
| ); | |
| let high = layer( | |
| "req_high", | |
| "High", | |
| r#"[auto_review] | |
| required_on_models = ["high-model", "shared-model"] | |
| [models.new_thread] | |
| model = "high-priority-model""#, | |
| ); | |
| let expected_source = RequirementSource::composite([high.source.clone(), low.source.clone()]); | |
| let composed = compose_requirements_for_hostname( | |
| vec![ | |
| low, | |
| high, | |
| layer( | |
| "req_empty", | |
| "Empty", | |
| "[auto_review]\nrequired_on_models = []", | |
| ), | |
| ], | |
| /*hostname*/ None, | |
| ) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed.clone().into_toml(), | |
| expected_requirements( | |
| r#"[auto_review] | |
| required_on_models = ["high-model", "shared-model", "low-model"] | |
| [models.new_thread] | |
| model = "high-priority-model" | |
| model_reasoning_effort = "low""# | |
| ) | |
| ); | |
| assert_eq!( | |
| composed.auto_review.map(|auto_review| auto_review.source), | |
| Some(expected_source) | |
| ); | |
| } | |
| fn relative_paths_resolve_against_their_own_layer_base() { | |
| let low_dir = tempdir().expect("low-priority requirements directory"); | |
| let high_dir = tempdir().expect("high-priority requirements directory"); | |
| let low_base = AbsolutePathBuf::from_absolute_path(low_dir.path()).expect("absolute low base"); | |
| let high_base = | |
| AbsolutePathBuf::from_absolute_path(high_dir.path()).expect("absolute high base"); | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| "sqlite_home = \"state\"\nlog_dir = \"low-logs\"", | |
| ) | |
| .with_base_dir(low_base), | |
| layer( | |
| "req_high", | |
| "High", | |
| "log_dir = \"high-logs\"\nmodel_catalog_json = \"models.json\"", | |
| ) | |
| .with_base_dir(high_base), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed.sqlite_home.as_deref(), | |
| Some(low_dir.path().join("state").as_path()) | |
| ); | |
| assert_eq!( | |
| composed.log_dir.as_deref(), | |
| Some(high_dir.path().join("high-logs").as_path()) | |
| ); | |
| assert_eq!( | |
| composed.model_catalog_json.as_deref(), | |
| Some(high_dir.path().join("models.json").as_path()) | |
| ); | |
| } | |
| fn provider_auth_fragments_merge_without_losing_source_paths_or_explicit_values() { | |
| let low_dir = tempdir().expect("low-priority requirements directory"); | |
| let high_dir = tempdir().expect("high-priority requirements directory"); | |
| let absolute_cwd = toml::Value::String(low_dir.path().display().to_string()).to_string(); | |
| for (cwd_override, expected_cwd) in [ | |
| (String::new(), low_dir.path().join("auth")), | |
| ( | |
| "cwd = 'other-auth'".to_string(), | |
| high_dir.path().join("other-auth"), | |
| ), | |
| ( | |
| format!("cwd = {absolute_cwd}"), | |
| low_dir.path().to_path_buf(), | |
| ), | |
| ] { | |
| let composed = compose(vec![ | |
| layer( | |
| "low", | |
| "Command", | |
| r#" | |
| [model_providers.gateway] | |
| name = "Gateway" | |
| [model_providers.gateway.auth] | |
| command = "get-token" | |
| args = ["--token"] | |
| cwd = "auth" | |
| timeout_ms = 7000 | |
| refresh_interval_ms = 12345 | |
| "#, | |
| ) | |
| .with_base_dir(AbsolutePathBuf::from_absolute_path(low_dir.path()).unwrap()), | |
| layer( | |
| "high", | |
| "Timeout", | |
| &format!("[model_providers.gateway.auth]\ntimeout_ms = 10000\n{cwd_override}"), | |
| ) | |
| .with_base_dir(AbsolutePathBuf::from_absolute_path(high_dir.path()).unwrap()), | |
| ]) | |
| .expect("merge partial auth before parsing") | |
| .expect("requirements present"); | |
| let expected_cwd = toml::Value::String(expected_cwd.display().to_string()); | |
| assert_eq!( | |
| composed, | |
| expected_requirements(format!( | |
| r#" | |
| [model_providers.gateway] | |
| name = "Gateway" | |
| [model_providers.gateway.auth] | |
| command = "get-token" | |
| args = ["--token"] | |
| cwd = {expected_cwd} | |
| timeout_ms = 10000 | |
| refresh_interval_ms = 12345 | |
| "#, | |
| )) | |
| ); | |
| } | |
| } | |
| fn provider_auth_missing_command_is_rejected_after_composition() { | |
| let err = compose(vec![ | |
| layer("low", "Name", "[model_providers.gateway]\nname = 'Gateway'"), | |
| layer( | |
| "high", | |
| "Timeout", | |
| "[model_providers.gateway.auth]\ntimeout_ms = 10000", | |
| ), | |
| ]) | |
| .expect_err("merged auth still needs a command"); | |
| assert!(matches!( | |
| err, | |
| RequirementsCompositionError::ComposedParse { message } | |
| if message.contains("missing field `command`") | |
| )); | |
| } | |
| 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)) | |
| ); | |
| } | |
| 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(), | |
| }, | |
| )) | |
| ); | |
| } | |
| 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" | |
| "# | |
| ) | |
| ); | |
| } | |
| fn feature_aliases_merge_with_layer_precedence() { | |
| for (low_key, high_key) in [ | |
| ("features", "feature_requirements"), | |
| ("feature_requirements", "features"), | |
| ] { | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| &format!("[{low_key}]\nchronicle = true\nshell_snapshot = false"), | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| &format!("[{high_key}]\nchronicle = false\napps = false"), | |
| ), | |
| ]) | |
| .expect("compose mixed feature aliases"); | |
| assert_eq!( | |
| composed, | |
| Some(expected_requirements( | |
| "[features]\nchronicle = false\nshell_snapshot = false\napps = false" | |
| )) | |
| ); | |
| } | |
| } | |
| 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]), | |
| ) | |
| ); | |
| } | |
| 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" | |
| "# | |
| ) | |
| ); | |
| } | |
| 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" | |
| "# | |
| ) | |
| ); | |
| } | |
| fn browser_and_computer_use_requirements_use_regular_toml_merge() { | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| r#" | |
| allow_browser_and_computer_use = true | |
| [browser_use] | |
| allow_history_access = true | |
| allow_global_persistent_approval = true | |
| [browser_use.default_origin_policy] | |
| access = "allow" | |
| access_approval_lifetime = "thread" | |
| [browser_use.origins."https://example.com"] | |
| access = "deny" | |
| downloads = "allow" | |
| [computer_use] | |
| allow_locked_computer_use = true | |
| default_app_access = "allow" | |
| [computer_use.macos.bundle_ids] | |
| "com.apple.Safari" = "deny" | |
| [computer_use.windows.aumids] | |
| "Microsoft.Paint_8wekyb3d8bbwe!App" = "allow" | |
| "#, | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| r#" | |
| allow_browser_and_computer_use = false | |
| [browser_use] | |
| allow_history_access = false | |
| allow_global_persistent_approval = false | |
| [browser_use.default_origin_policy] | |
| persistent_approval = false | |
| access_approval_lifetime = "turn" | |
| [browser_use.origins."https://example.com"] | |
| downloads = "deny" | |
| uploads = "deny" | |
| [computer_use] | |
| allow_persistent_approval = false | |
| [computer_use.macos.bundle_ids] | |
| "com.apple.Safari" = "allow" | |
| [[computer_use.windows.exes]] | |
| publisher_name = "CN=Google LLC" | |
| product_name = "Google Chrome" | |
| binary_name = "chrome.exe" | |
| access = "deny" | |
| "#, | |
| ), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| allow_browser_and_computer_use = false | |
| [browser_use] | |
| allow_history_access = false | |
| allow_global_persistent_approval = false | |
| [browser_use.default_origin_policy] | |
| access = "allow" | |
| persistent_approval = false | |
| access_approval_lifetime = "turn" | |
| [browser_use.origins."https://example.com"] | |
| access = "deny" | |
| downloads = "deny" | |
| uploads = "deny" | |
| [computer_use] | |
| allow_locked_computer_use = true | |
| allow_persistent_approval = false | |
| default_app_access = "allow" | |
| [computer_use.macos.bundle_ids] | |
| "com.apple.Safari" = "allow" | |
| [computer_use.windows.aumids] | |
| "Microsoft.Paint_8wekyb3d8bbwe!App" = "allow" | |
| [[computer_use.windows.exes]] | |
| publisher_name = "CN=Google LLC" | |
| product_name = "Google Chrome" | |
| binary_name = "chrome.exe" | |
| access = "deny" | |
| "# | |
| ) | |
| ); | |
| } | |
| fn webmcp_requirements_preserve_managed_layer_precedence() { | |
| for (lower, higher, expected) in [ | |
| ("true", "[browser_use]", true), | |
| ("false", "[browser_use]", false), | |
| ("true", "[browser_use]\nallow_webmcp = false", false), | |
| ("false", "[browser_use]\nallow_webmcp = true", true), | |
| ] { | |
| let lower = format!("[browser_use]\nallow_webmcp = {lower}"); | |
| let composed = compose(vec![ | |
| layer("req_low", "Low", &lower), | |
| layer("req_high", "High", higher), | |
| ]) | |
| .expect("compose managed WebMCP policy"); | |
| assert_eq!( | |
| composed, | |
| Some(ConfigRequirementsToml { | |
| browser_use: Some(crate::BrowserUseRequirementsToml { | |
| allow_webmcp: Some(expected), | |
| ..Default::default() | |
| }), | |
| ..Default::default() | |
| }), | |
| ); | |
| } | |
| } | |
| 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"] | |
| "# | |
| ) | |
| ); | |
| } | |
| 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"] | |
| "# | |
| ) | |
| ); | |
| } | |
| 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"] | |
| "# | |
| ) | |
| ); | |
| } | |
| fn hostname_resolver_is_not_called_without_remote_sandbox_config() { | |
| let calls = Cell::<usize>::default(); | |
| let composed = compose_requirements_with_hostname_resolver( | |
| vec![layer( | |
| "req", | |
| "No remote selector", | |
| r#" | |
| allowed_sandbox_modes = ["read-only"] | |
| "#, | |
| )], | |
| || { | |
| calls.set(calls.get() + 1); | |
| Some("build-01.example.com".to_string()) | |
| }, | |
| ) | |
| .expect("compose requirements") | |
| .expect("requirements present") | |
| .into_toml(); | |
| assert_eq!(calls.get(), 0); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| allowed_sandbox_modes = ["read-only"] | |
| "# | |
| ) | |
| ); | |
| } | |
| fn hostname_resolver_is_called_once_for_multiple_remote_sandbox_layers() { | |
| let calls = Cell::<usize>::default(); | |
| let composed = compose_requirements_with_hostname_resolver( | |
| vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| r#" | |
| [[remote_sandbox_config]] | |
| hostname_patterns = ["build-*.example.com"] | |
| allowed_sandbox_modes = ["read-only"] | |
| "#, | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| r#" | |
| [[remote_sandbox_config]] | |
| hostname_patterns = ["build-*.example.com"] | |
| allowed_sandbox_modes = ["workspace-write"] | |
| "#, | |
| ), | |
| ], | |
| || { | |
| calls.set(calls.get() + 1); | |
| Some("build-01.example.com".to_string()) | |
| }, | |
| ) | |
| .expect("compose requirements") | |
| .expect("requirements present") | |
| .into_toml(); | |
| assert_eq!(calls.get(), 1); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| allowed_sandbox_modes = ["workspace-write"] | |
| "# | |
| ) | |
| ); | |
| } | |
| 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" | |
| "# | |
| ) | |
| ); | |
| } | |
| 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)")); | |
| } | |
| 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)")); | |
| } | |
| 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" | |
| "# | |
| ) | |
| ); | |
| } | |
| 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" | |
| "# | |
| )) | |
| ); | |
| } | |
| 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:?}] | |
| "# | |
| )) | |
| ); | |
| } | |
| 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")); | |
| } | |
| fn marketplace_allowed_sources_use_default_toml_merge() { | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| r#" | |
| [marketplaces] | |
| restrict_to_allowed_sources = true | |
| [marketplaces.allowed_sources.shared] | |
| source = "git" | |
| url = "https://github.com/example/old.git" | |
| ref = "main" | |
| [marketplaces.allowed_sources.other] | |
| source = "git" | |
| url = "https://github.com/example/other.git" | |
| "#, | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| r#" | |
| [marketplaces.allowed_sources.shared] | |
| ref = "release" | |
| "#, | |
| ), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| [marketplaces] | |
| restrict_to_allowed_sources = true | |
| [marketplaces.allowed_sources.shared] | |
| source = "git" | |
| url = "https://github.com/example/old.git" | |
| ref = "release" | |
| [marketplaces.allowed_sources.other] | |
| source = "git" | |
| url = "https://github.com/example/other.git" | |
| "#, | |
| ) | |
| ); | |
| } | |
| fn marketplace_source_switch_uses_default_toml_merge() { | |
| let composed = compose(vec![ | |
| layer( | |
| "req_low", | |
| "Low", | |
| r#" | |
| [marketplaces.allowed_sources.company] | |
| source = "git" | |
| url = "https://github.com/example/plugins.git" | |
| ref = "main" | |
| "#, | |
| ), | |
| layer( | |
| "req_high", | |
| "High", | |
| r#" | |
| [marketplaces.allowed_sources.company] | |
| source = "host_pattern" | |
| host_pattern = '^github\.example\.com$' | |
| "#, | |
| ), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| [marketplaces.allowed_sources.company] | |
| source = "host_pattern" | |
| url = "https://github.com/example/plugins.git" | |
| ref = "main" | |
| host_pattern = '^github\.example\.com$' | |
| "#, | |
| ) | |
| ); | |
| } | |
| fn marketplace_allowed_source_rejects_unknown_fields() { | |
| let err = compose(vec![layer( | |
| "req_bad", | |
| "Bad marketplace layer", | |
| r#" | |
| [marketplaces] | |
| restrict_to_allowed_sources = true | |
| [marketplaces.allowed_sources.invalid] | |
| source = "git" | |
| url = "https://github.com/example/plugins.git" | |
| reff = "main" | |
| "#, | |
| )]) | |
| .expect_err("invalid marketplace rule should fail"); | |
| assert!(err.to_string().contains("Bad marketplace layer (req_bad)")); | |
| assert!(err.to_string().contains("unknown field `reff`")); | |
| } | |
| fn local_marketplace_path_is_not_resolved_during_requirements_merge() { | |
| let base_dir = TempDir::new().expect("create requirements base directory"); | |
| let base_dir = AbsolutePathBuf::try_from(base_dir.path().to_path_buf()) | |
| .expect("absolute requirements base directory"); | |
| let composed = compose(vec![ | |
| layer( | |
| "req_local", | |
| "Local marketplace path", | |
| r#" | |
| [marketplaces] | |
| restrict_to_allowed_sources = true | |
| [marketplaces.allowed_sources.local] | |
| source = "local" | |
| path = "../plugins" | |
| "#, | |
| ) | |
| .with_base_dir(base_dir), | |
| ]) | |
| .expect("compose requirements") | |
| .expect("requirements present"); | |
| assert_eq!( | |
| composed, | |
| expected_requirements( | |
| r#" | |
| [marketplaces] | |
| restrict_to_allowed_sources = true | |
| [marketplaces.allowed_sources.local] | |
| source = "local" | |
| path = "../plugins" | |
| "#, | |
| ) | |
| ); | |
| } | |