Enforce exact values from managed config requirements (#34597)

## What changed

- Apply managed values for `sqlite_home`, `log_dir`, `model_catalog_json`,
  `check_for_update_on_startup`, `allow_login_shell`, the report-submission
  opt-in, and `windows.sandbox_private_desktop` to the runtime configuration,
  with source-aware warnings when they override configured values.
- Expose these values through `configRequirements/read`, return them from
  `config/read`, include them in session config locks, and show their sources in
  the TUI config debug view.
- Reject app-server writes that overlap an exact managed requirement with
  `configRequirementReadonly` while leaving unrelated sibling keys writable.

## Testing

- Cover runtime overrides, requirement API mapping, config reads and writes,
  session lock serialization, cross-platform path URIs, and debug output.

GitOrigin-RevId: d4e23b6fd7775c1a6dfe2eab313cdcee50b07081
This commit is contained in:
Abhinav authored and copyberry committed 2026-07-21 19:08:58 +00:00
1 parent 7442f5f932
commit ee71c4a90f
34 files changed
+1566 -71

No files matched your search

@@ -12,6 +12,7 @@ use codex_protocol::config_types::WebSearchMode;
use codex_protocol::config_types::WebSearchToolConfig;
use codex_protocol::openai_models::ReasoningEffort;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -337,6 +338,7 @@ pub struct ConfigWriteResponse {
#[ts(export_to = "v2/")]
pub enum ConfigWriteErrorCode {
ConfigLayerReadonly,
ConfigRequirementReadonly,
ConfigVersionConflict,
ConfigValidationError,
ConfigPathNotFound,
@@ -392,6 +394,16 @@ pub struct ConfigRequirements {
#[experimental("configRequirements/read.network")]
pub network: Option<NetworkRequirements>,
pub models: Option<ModelsRequirements>,
#[schemars(with = "Option<String>")]
pub sqlite_home: Option<PathUri>,
#[schemars(with = "Option<String>")]
pub log_dir: Option<PathUri>,
#[schemars(with = "Option<String>")]
pub model_catalog_json: Option<PathUri>,
pub check_for_update_on_startup: Option<bool>,
pub allow_login_shell: Option<bool>,
pub feedback: Option<FeedbackRequirements>,
pub windows_sandbox_private_desktop: Option<bool>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
@@ -410,6 +422,13 @@ pub struct NewThreadModelDefaults {
pub service_tier: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct FeedbackRequirements {
pub enabled: Option<bool>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -1807,11 +1807,46 @@ fn config_requirements_granular_allowed_approval_policy_is_marked_experimental()
enforce_residency: None,
network: None,
models: None,
sqlite_home: None,
log_dir: None,
model_catalog_json: None,
check_for_update_on_startup: None,
allow_login_shell: None,
feedback: None,
windows_sandbox_private_desktop: None,
});
assert_eq!(reason, Some("askForApproval.granular"));
}
#[test]
fn config_requirements_read_accepts_foreign_path_uris() {
let response: ConfigRequirementsReadResponse = serde_json::from_value(json!({
"requirements": {
"sqliteHome": "file:///C:/Users/alice/.codex/state",
"logDir": "file:///C:/Users/alice/.codex/logs",
"modelCatalogJson": "file:///C:/Users/alice/.codex/models.json"
}
}))
.expect("requirements response with foreign paths should deserialize");
let requirements = response
.requirements
.expect("requirements should be present");
assert_eq!(
requirements.sqlite_home,
Some(PathUri::parse("file:///C:/Users/alice/.codex/state").expect("valid URI"))
);
assert_eq!(
requirements.log_dir,
Some(PathUri::parse("file:///C:/Users/alice/.codex/logs").expect("valid URI"))
);
assert_eq!(
requirements.model_catalog_json,
Some(PathUri::parse("file:///C:/Users/alice/.codex/models.json").expect("valid URI"))
);
}
#[test]
fn client_request_thread_start_granular_approval_policy_is_marked_experimental() {
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(