mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Constrain Windows sandbox requirements (#23766)
# Why Managed requirements can already constrain sandbox policy choices, but Windows sandbox implementation selection was still resolved independently from those requirements. That left the TUI able to continue through the unelevated fallback even when an organization wants to require the elevated Windows sandbox implementation. # What - Add `[windows].allowed_sandbox_implementations` requirements support for the Windows `elevated` and `unelevated` implementations. - Apply that allowlist during core config resolution so disallowed configured or feature-selected Windows sandbox implementations fall back to an allowed implementation with the existing requirements warning path. - Reuse the existing TUI Windows setup prompts to block disallowed unelevated continuation, keep required elevated setup in front of the user, and refuse to persist a TUI-selected Windows sandbox mode that requirements disallow. # Semantics | Allowed | Selected | Effective | | --- | --- | --- | | `["elevated"]` | `unelevated` / unset | `elevated` | | `["unelevated"]` | `elevated` / unset | `unelevated` | | `["elevated", "unelevated"]` | `elevated` | `elevated` | | `["elevated", "unelevated"]` | `unelevated` | `unelevated` | | `["elevated", "unelevated"]` | unset | `elevated` | Availability is handled by interactive setup surfaces after allowlist resolution. If the effective elevated implementation is not ready, elevated-only requirements block on setup. When unelevated is also allowed, the UI may offer the existing unelevated fallback. ## TUI Screens If elevated setup is not already complete: ``` Your organization requires the default Codex agent sandbox to continue. Set it up to protect your files and control network access. Learn more <https://developers.openai.com/codex/windows> › 1. Set up default sandbox (requires Administrator permissions) 2. Quit ``` If admin setup fails under `["elevated"]`: ``` Couldn't set up your sandbox with Administrator permissions Your organization requires the default sandbox before Codex can continue. Learn more <https://developers.openai.com/codex/windows> › 1. Try setting up admin sandbox again 2. Quit ``` # Next Steps - extend the requirements/readout surface, such as `configRequirements/read`, so clients can inspect the loaded `[windows].allowed_sandbox_implementations` requirement instead of inferring it from Windows setup state - consider extending `windowsSandbox/readiness` as well - update the App startup guide, setup flow, and banner surfaces so an elevated-only requirement omits any continue-unelevated escape hatch and blocks startup until a permitted implementation is ready; - preserve the existing unelevated fallback path when requirements allow it, including the `["unelevated"]` case where elevated is disallowed
This commit is contained in:
@@ -1103,6 +1103,7 @@ allowed_approval_policies = ["on-request"]
|
||||
allow_managed_hooks_only: None,
|
||||
allow_appshots: None,
|
||||
computer_use: None,
|
||||
windows: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -1164,6 +1165,7 @@ allowed_approval_policies = ["on-request"]
|
||||
allow_managed_hooks_only: None,
|
||||
allow_appshots: None,
|
||||
computer_use: None,
|
||||
windows: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -1374,6 +1376,7 @@ async fn load_config_layers_includes_cloud_requirements() -> anyhow::Result<()>
|
||||
allow_managed_hooks_only: None,
|
||||
allow_appshots: None,
|
||||
computer_use: None,
|
||||
windows: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
|
||||
@@ -8195,6 +8195,7 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset()
|
||||
allow_managed_hooks_only: None,
|
||||
allow_appshots: None,
|
||||
computer_use: None,
|
||||
windows: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -8918,6 +8919,7 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
|
||||
allow_managed_hooks_only: None,
|
||||
allow_appshots: None,
|
||||
computer_use: None,
|
||||
windows: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -8945,6 +8947,47 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn windows_sandbox_mode_falls_back_when_disallowed_by_requirements() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
std::fs::write(
|
||||
codex_home.path().join(CONFIG_TOML_FILE),
|
||||
r#"[windows]
|
||||
sandbox = "unelevated"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let requirements = codex_config::ConfigRequirementsToml {
|
||||
windows: Some(codex_config::WindowsRequirementsToml {
|
||||
allowed_sandbox_implementations: Some(vec![
|
||||
codex_config::types::WindowsSandboxModeToml::Elevated,
|
||||
]),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let config = ConfigBuilder::without_managed_config_for_tests()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.fallback_cwd(Some(codex_home.path().to_path_buf()))
|
||||
.cloud_requirements(CloudRequirementsLoader::new(async move {
|
||||
Ok(Some(requirements))
|
||||
}))
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
assert_eq!(
|
||||
config.permissions.windows_sandbox_mode,
|
||||
Some(codex_config::types::WindowsSandboxModeToml::Elevated)
|
||||
);
|
||||
assert!(
|
||||
config.startup_warnings.iter().any(|warning| warning
|
||||
.contains("Configured value for `windows.sandbox` is disallowed by requirements")),
|
||||
"{:?}",
|
||||
config.startup_warnings
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn danger_full_access_with_never_is_rejected_when_requirements_force_read_only()
|
||||
-> std::io::Result<()> {
|
||||
|
||||
@@ -2457,6 +2457,7 @@ impl Config {
|
||||
approval_policy: mut constrained_approval_policy,
|
||||
approvals_reviewer: mut constrained_approvals_reviewer,
|
||||
permission_profile: mut constrained_permission_profile,
|
||||
windows_sandbox_mode: mut constrained_windows_sandbox_mode,
|
||||
web_search_mode: mut constrained_web_search_mode,
|
||||
allow_managed_hooks_only: _,
|
||||
allow_appshots: _,
|
||||
@@ -2568,7 +2569,28 @@ impl Config {
|
||||
&mut startup_warnings,
|
||||
)?;
|
||||
let enable_network_proxy = features.enabled(Feature::NetworkProxy);
|
||||
let windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg);
|
||||
let configured_windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg);
|
||||
// Keep the configured mode separate so a requirement-constrained mode
|
||||
// does not look like it was explicitly selected in config.
|
||||
let selected_windows_sandbox_mode = configured_windows_sandbox_mode.or_else(|| {
|
||||
match WindowsSandboxLevel::from_features(&features) {
|
||||
WindowsSandboxLevel::Elevated => Some(WindowsSandboxModeToml::Elevated),
|
||||
WindowsSandboxLevel::RestrictedToken => Some(WindowsSandboxModeToml::Unelevated),
|
||||
WindowsSandboxLevel::Disabled => None,
|
||||
}
|
||||
});
|
||||
apply_requirement_constrained_value(
|
||||
"windows.sandbox",
|
||||
selected_windows_sandbox_mode,
|
||||
&mut constrained_windows_sandbox_mode,
|
||||
&mut startup_warnings,
|
||||
)?;
|
||||
let effective_windows_sandbox_mode = *constrained_windows_sandbox_mode.get();
|
||||
let windows_sandbox_mode = if constrained_windows_sandbox_mode.source.is_some() {
|
||||
effective_windows_sandbox_mode
|
||||
} else {
|
||||
configured_windows_sandbox_mode
|
||||
};
|
||||
let windows_sandbox_private_desktop = resolve_windows_sandbox_private_desktop(&cfg);
|
||||
let resolved_cwd = AbsolutePathBuf::try_from(normalize_for_native_workdir({
|
||||
use std::env;
|
||||
@@ -2626,10 +2648,10 @@ impl Config {
|
||||
));
|
||||
}
|
||||
|
||||
let windows_sandbox_level = match windows_sandbox_mode {
|
||||
let windows_sandbox_level = match effective_windows_sandbox_mode {
|
||||
Some(WindowsSandboxModeToml::Elevated) => WindowsSandboxLevel::Elevated,
|
||||
Some(WindowsSandboxModeToml::Unelevated) => WindowsSandboxLevel::RestrictedToken,
|
||||
None => WindowsSandboxLevel::from_features(&features),
|
||||
None => WindowsSandboxLevel::Disabled,
|
||||
};
|
||||
let memories_config: MemoriesConfig = cfg.memories.clone().unwrap_or_default().into();
|
||||
let memories_root = memory_root(&codex_home);
|
||||
|
||||
Reference in New Issue
Block a user