From 1427b3c00ea5db0574c46ea91fdd4530a7310177 Mon Sep 17 00:00:00 2001 From: daniel-oai Date: Tue, 3 Mar 2026 14:43:43 -0800 Subject: [PATCH] Narrow managed feature requirements diff --- .../json/codex_app_server_protocol.schemas.json | 9 --------- .../json/codex_app_server_protocol.v2.schemas.json | 9 --------- .../json/v2/ConfigRequirementsReadResponse.json | 9 --------- .../schema/typescript/v2/ConfigRequirements.ts | 2 +- codex-rs/app-server-protocol/src/protocol/v2.rs | 1 - codex-rs/app-server/README.md | 2 +- codex-rs/app-server/src/config_api.rs | 11 ----------- codex-rs/config/src/config_requirements.rs | 5 +++++ codex-rs/core/src/config/mod.rs | 6 ++++++ codex-rs/core/src/features.rs | 3 +++ 10 files changed, 16 insertions(+), 41 deletions(-) diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index c614b6dbaf..ddeee0ce73 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -8963,15 +8963,6 @@ "type": "null" } ] - }, - "features": { - "additionalProperties": { - "type": "boolean" - }, - "type": [ - "object", - "null" - ] } }, "type": "object" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index b38ee1bf31..1bd5733364 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -2857,15 +2857,6 @@ "type": "null" } ] - }, - "features": { - "additionalProperties": { - "type": "boolean" - }, - "type": [ - "object", - "null" - ] } }, "type": "object" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json index f6173f8a4f..651e035e9c 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json @@ -81,15 +81,6 @@ "type": "null" } ] - }, - "features": { - "additionalProperties": { - "type": "boolean" - }, - "type": [ - "object", - "null" - ] } }, "type": "object" diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ConfigRequirements.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ConfigRequirements.ts index 0dbc130782..f99c880697 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ConfigRequirements.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ConfigRequirements.ts @@ -6,4 +6,4 @@ import type { AskForApproval } from "./AskForApproval"; import type { ResidencyRequirement } from "./ResidencyRequirement"; import type { SandboxMode } from "./SandboxMode"; -export type ConfigRequirements = {allowedApprovalPolicies: Array | null, allowedSandboxModes: Array | null, allowedWebSearchModes: Array | null, features: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null}; +export type ConfigRequirements = {allowedApprovalPolicies: Array | null, allowedSandboxModes: Array | null, allowedWebSearchModes: Array | null, enforceResidency: ResidencyRequirement | null}; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 5b00869ef9..8f0b37beef 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -611,7 +611,6 @@ pub struct ConfigRequirements { pub allowed_approval_policies: Option>, pub allowed_sandbox_modes: Option>, pub allowed_web_search_modes: Option>, - pub features: Option>, pub enforce_residency: Option, #[experimental("configRequirements/read.network")] pub network: Option, diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 83dd941fc5..9ec4821e8d 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -163,7 +163,7 @@ Example with notification opt-out: - `externalAgentConfig/import` — apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home). - `config/value/write` — write a single config key/value to the user's config.toml on disk. - `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk. -- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), managed feature disables (`features`), `enforceResidency`, and `network` constraints. +- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), `enforceResidency`, and `network` constraints. ### Example: Start or resume a thread diff --git a/codex-rs/app-server/src/config_api.rs b/codex-rs/app-server/src/config_api.rs index f043e71505..c9317ac9f5 100644 --- a/codex-rs/app-server/src/config_api.rs +++ b/codex-rs/app-server/src/config_api.rs @@ -127,9 +127,6 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR } normalized }), - features: requirements - .features - .map(|features| features.entries.into_iter().collect()), enforce_residency: requirements .enforce_residency .map(map_residency_requirement_to_api), @@ -215,9 +212,6 @@ mod tests { allowed_web_search_modes: Some(vec![ codex_core::config_loader::WebSearchModeRequirement::Cached, ]), - features: Some(codex_core::config_loader::RequirementsFeaturesToml { - entries: [("unified_exec".to_string(), false)].into_iter().collect(), - }), mcp_servers: None, rules: None, enforce_residency: Some(CoreResidencyRequirement::Us), @@ -253,10 +247,6 @@ mod tests { mapped.allowed_web_search_modes, Some(vec![WebSearchMode::Cached, WebSearchMode::Disabled]), ); - assert_eq!( - mapped.features, - Some([("unified_exec".to_string(), false)].into_iter().collect()) - ); assert_eq!( mapped.enforce_residency, Some(codex_app_server_protocol::ResidencyRequirement::Us), @@ -285,7 +275,6 @@ mod tests { allowed_approval_policies: None, allowed_sandbox_modes: None, allowed_web_search_modes: Some(Vec::new()), - features: None, mcp_servers: None, rules: None, enforce_residency: None, diff --git a/codex-rs/config/src/config_requirements.rs b/codex-rs/config/src/config_requirements.rs index 976df706f6..3d822700eb 100644 --- a/codex-rs/config/src/config_requirements.rs +++ b/codex-rs/config/src/config_requirements.rs @@ -144,6 +144,11 @@ pub struct NetworkRequirementsToml { pub allow_local_binding: Option, } +/// Raw `[features]` entries from managed requirements. +/// +/// The keys stay as strings here so `codex-config` does not need its own copy +/// of the feature registry; `codex-core` validates them against the canonical +/// runtime feature list when building the effective config. #[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq, Serialize)] pub struct RequirementsFeaturesToml { #[serde(flatten)] diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 53095dc03b..efee447ebf 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -814,6 +814,12 @@ where Ok(()) } +/// Applies disable-only managed feature requirements after local config, +/// profile settings, and CLI/legacy feature overrides have been merged. +/// +/// This lives in `codex-core` instead of `codex-config` so validation can rely +/// on the single canonical feature registry in `features.rs` without mirroring +/// that registry across crates. fn apply_requirement_feature_constraints( features: &mut Features, requirement_features: Option<&Sourced>, diff --git a/codex-rs/core/src/features.rs b/codex-rs/core/src/features.rs index 2cef350c15..b384827675 100644 --- a/codex-rs/core/src/features.rs +++ b/codex-rs/core/src/features.rs @@ -360,6 +360,9 @@ impl Features { self.enabled.iter().copied().collect() } + /// Clears feature flags whose prerequisites were disabled later in config + /// resolution, such as when managed requirements turn off a base feature + /// after local feature maps have already been applied. pub(crate) fn normalize_dependencies(&mut self) { if self.enabled(Feature::JsReplToolsOnly) && !self.enabled(Feature::JsRepl) { tracing::warn!("js_repl_tools_only requires js_repl; disabling js_repl_tools_only");