mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Always use private desktops for legacy Windows sandboxes (#46554)
## What changed - Remove the private-desktop opt-out from elevated and unelevated Windows sandbox launches. - Remove `windows.sandbox_private_desktop` and its managed requirement and API fields. Warn users to remove the obsolete setting. - Require a private desktop name when launching through the Windows sandbox wrapper and command runner. ## Testing Add coverage for the obsolete-setting migration warning and update wrapper tests to verify a live private desktop is passed and a missing desktop name is rejected. GitOrigin-RevId: c7135f8d211aac8d812180691c2c1e433d77cde4
This commit is contained in:
@@ -178,7 +178,6 @@ pub struct ConfigRequirements {
|
||||
pub auto_review_required_models: Option<Sourced<BTreeSet<String>>>,
|
||||
pub permission_profile: ConstrainedWithSource<PermissionProfile>,
|
||||
pub windows_sandbox_mode: ConstrainedWithSource<Option<WindowsSandboxModeToml>>,
|
||||
pub windows_sandbox_private_desktop: Option<Sourced<bool>>,
|
||||
pub web_search_mode: ConstrainedWithSource<WebSearchMode>,
|
||||
pub allow_managed_hooks_only: Option<Sourced<bool>>,
|
||||
pub allow_appshots: Option<Sourced<bool>>,
|
||||
@@ -234,7 +233,6 @@ impl Default for ConfigRequirements {
|
||||
Constrained::allow_any(/*initial_value*/ None),
|
||||
/*source*/ None,
|
||||
),
|
||||
windows_sandbox_private_desktop: None,
|
||||
web_search_mode: ConstrainedWithSource::new(
|
||||
Constrained::allow_any(WebSearchMode::Cached),
|
||||
/*source*/ None,
|
||||
@@ -869,7 +867,6 @@ impl fmt::Display for WebSearchModeRequirement {
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct WindowsRequirementsToml {
|
||||
pub allowed_sandbox_implementations: Option<Vec<WindowsSandboxImplementationToml>>,
|
||||
pub sandbox_private_desktop: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -881,7 +878,7 @@ pub enum WindowsSandboxImplementationToml {
|
||||
|
||||
impl WindowsRequirementsToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.allowed_sandbox_implementations.is_none() && self.sandbox_private_desktop.is_none()
|
||||
self.allowed_sandbox_implementations.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1614,16 +1611,6 @@ impl ConfigRequirementsToml {
|
||||
if let Some(enabled) = self.feedback.as_ref().and_then(|feedback| feedback.enabled) {
|
||||
config.feedback.get_or_insert_default().enabled = Some(enabled);
|
||||
}
|
||||
if let Some(sandbox_private_desktop) = self
|
||||
.windows
|
||||
.as_ref()
|
||||
.and_then(|windows| windows.sandbox_private_desktop)
|
||||
{
|
||||
config
|
||||
.windows
|
||||
.get_or_insert_default()
|
||||
.sandbox_private_desktop = Some(sandbox_private_desktop);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the exact managed field affected by editing `segments`.
|
||||
@@ -1635,7 +1622,7 @@ impl ConfigRequirementsToml {
|
||||
}) {
|
||||
return Some("model_providers");
|
||||
}
|
||||
let managed_fields: [(bool, &[&str], &'static str); 10] = [
|
||||
let managed_fields: [(bool, &[&str], &'static str); 9] = [
|
||||
(
|
||||
self.model_provider.is_some(),
|
||||
&["model_provider"],
|
||||
@@ -1666,14 +1653,6 @@ impl ConfigRequirementsToml {
|
||||
&["feedback", "enabled"],
|
||||
"feedback.enabled",
|
||||
),
|
||||
(
|
||||
self.windows
|
||||
.as_ref()
|
||||
.and_then(|windows| windows.sandbox_private_desktop)
|
||||
.is_some(),
|
||||
&["windows", "sandbox_private_desktop"],
|
||||
"windows.sandbox_private_desktop",
|
||||
),
|
||||
(
|
||||
self.cli_auth_credentials_store.is_some(),
|
||||
&["cli_auth_credentials_store"],
|
||||
@@ -1915,74 +1894,62 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
|
||||
/*source*/ None,
|
||||
),
|
||||
};
|
||||
let (windows_sandbox_mode, windows_sandbox_private_desktop) = match windows {
|
||||
let windows_sandbox_mode = match windows {
|
||||
Some(Sourced {
|
||||
value:
|
||||
WindowsRequirementsToml {
|
||||
allowed_sandbox_implementations,
|
||||
sandbox_private_desktop,
|
||||
allowed_sandbox_implementations: Some(implementations),
|
||||
},
|
||||
source: requirement_source,
|
||||
}) => {
|
||||
let sandbox_private_desktop = sandbox_private_desktop
|
||||
.map(|value| Sourced::new(value, requirement_source.clone()));
|
||||
let sandbox_mode = match allowed_sandbox_implementations {
|
||||
Some(implementations) => {
|
||||
if implementations.is_empty() {
|
||||
return Err(ConstraintError::empty_field(
|
||||
"windows.allowed_sandbox_implementations",
|
||||
));
|
||||
}
|
||||
// Prefer elevated when both Windows sandbox implementations are allowed.
|
||||
let initial_value = if implementations
|
||||
.contains(&WindowsSandboxImplementationToml::Elevated)
|
||||
{
|
||||
WindowsSandboxModeToml::Elevated
|
||||
} else {
|
||||
WindowsSandboxModeToml::Unelevated
|
||||
};
|
||||
if implementations.is_empty() {
|
||||
return Err(ConstraintError::empty_field(
|
||||
"windows.allowed_sandbox_implementations",
|
||||
));
|
||||
}
|
||||
// Prefer elevated when both Windows sandbox implementations are allowed.
|
||||
let initial_value =
|
||||
if implementations.contains(&WindowsSandboxImplementationToml::Elevated) {
|
||||
WindowsSandboxModeToml::Elevated
|
||||
} else {
|
||||
WindowsSandboxModeToml::Unelevated
|
||||
};
|
||||
|
||||
let requirement_source_for_error = requirement_source.clone();
|
||||
let constrained = Constrained::new(
|
||||
Some(initial_value),
|
||||
move |candidate| match candidate {
|
||||
Some(WindowsSandboxModeToml::Mxc) => Ok(()),
|
||||
Some(WindowsSandboxModeToml::Elevated)
|
||||
if implementations
|
||||
.contains(&WindowsSandboxImplementationToml::Elevated) =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
Some(WindowsSandboxModeToml::Unelevated)
|
||||
if implementations.contains(
|
||||
&WindowsSandboxImplementationToml::Unelevated,
|
||||
) =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(ConstraintError::InvalidValue {
|
||||
field_name: "windows.sandbox",
|
||||
candidate: format!("{candidate:?}"),
|
||||
allowed: format!("{implementations:?}"),
|
||||
requirement_source: requirement_source_for_error.clone(),
|
||||
}),
|
||||
},
|
||||
)?;
|
||||
ConstrainedWithSource::new(constrained, Some(requirement_source))
|
||||
}
|
||||
None => ConstrainedWithSource::new(
|
||||
Constrained::allow_any(/*initial_value*/ None),
|
||||
/*source*/ None,
|
||||
),
|
||||
};
|
||||
(sandbox_mode, sandbox_private_desktop)
|
||||
let requirement_source_for_error = requirement_source.clone();
|
||||
let constrained =
|
||||
Constrained::new(Some(initial_value), move |candidate| match candidate {
|
||||
Some(WindowsSandboxModeToml::Mxc) => Ok(()),
|
||||
Some(WindowsSandboxModeToml::Elevated)
|
||||
if implementations
|
||||
.contains(&WindowsSandboxImplementationToml::Elevated) =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
Some(WindowsSandboxModeToml::Unelevated)
|
||||
if implementations
|
||||
.contains(&WindowsSandboxImplementationToml::Unelevated) =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(ConstraintError::InvalidValue {
|
||||
field_name: "windows.sandbox",
|
||||
candidate: format!("{candidate:?}"),
|
||||
allowed: format!("{implementations:?}"),
|
||||
requirement_source: requirement_source_for_error.clone(),
|
||||
}),
|
||||
})?;
|
||||
ConstrainedWithSource::new(constrained, Some(requirement_source))
|
||||
}
|
||||
None => (
|
||||
ConstrainedWithSource::new(
|
||||
Constrained::allow_any(/*initial_value*/ None),
|
||||
/*source*/ None,
|
||||
),
|
||||
None,
|
||||
Some(Sourced {
|
||||
value:
|
||||
WindowsRequirementsToml {
|
||||
allowed_sandbox_implementations: None,
|
||||
},
|
||||
..
|
||||
})
|
||||
| None => ConstrainedWithSource::new(
|
||||
Constrained::allow_any(/*initial_value*/ None),
|
||||
/*source*/ None,
|
||||
),
|
||||
};
|
||||
let exec_policy = match rules {
|
||||
@@ -2126,7 +2093,6 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
|
||||
auto_review_required_models,
|
||||
permission_profile,
|
||||
windows_sandbox_mode,
|
||||
windows_sandbox_private_desktop,
|
||||
web_search_mode,
|
||||
allow_managed_hooks_only,
|
||||
allow_appshots,
|
||||
@@ -2219,10 +2185,6 @@ mod tests {
|
||||
feedback: Some(FeedbackConfigToml {
|
||||
enabled: Some(false),
|
||||
}),
|
||||
windows: Some(WindowsRequirementsToml {
|
||||
sandbox_private_desktop: Some(false),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let cases: &[(&[&str], Option<&str>)] = &[
|
||||
@@ -2240,16 +2202,8 @@ mod tests {
|
||||
),
|
||||
(&["allow_login_shell"], Some("allow_login_shell")),
|
||||
(&["feedback", "enabled"], Some("feedback.enabled")),
|
||||
(
|
||||
&["windows", "sandbox_private_desktop"],
|
||||
Some("windows.sandbox_private_desktop"),
|
||||
),
|
||||
(&[], Some("sqlite_home")),
|
||||
(&["feedback"], Some("feedback.enabled")),
|
||||
(
|
||||
&["windows", "sandbox_private_desktop", "value"],
|
||||
Some("windows.sandbox_private_desktop"),
|
||||
),
|
||||
(&["feedback", "other"], None),
|
||||
(&["windows", "sandbox"], None),
|
||||
];
|
||||
@@ -2846,8 +2800,7 @@ mod tests {
|
||||
enabled: Some(false),
|
||||
};
|
||||
let windows = WindowsRequirementsToml {
|
||||
allowed_sandbox_implementations: None,
|
||||
sandbox_private_desktop: Some(true),
|
||||
allowed_sandbox_implementations: Some(vec![WindowsSandboxImplementationToml::Elevated]),
|
||||
};
|
||||
let enforce_residency = ResidencyRequirement::Us;
|
||||
let enforce_source = source.clone();
|
||||
|
||||
@@ -268,6 +268,9 @@ pub(crate) fn ignored_config_warning(
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice()
|
||||
{
|
||||
["windows", "sandbox_private_desktop"] => {
|
||||
" Remove windows.sandbox_private_desktop; legacy Windows sandboxes always use a private desktop."
|
||||
}
|
||||
["network_proxy"] => {
|
||||
" Use [permissions.<name>.network] for network settings, or [experimental_network] in requirements.toml for enforced network policy."
|
||||
}
|
||||
|
||||
@@ -201,3 +201,20 @@ include_view_image_tool = false
|
||||
"Codex is ignoring 3 unrecognized configuration settings. Check for typos or deprecated settings.\n enterprise-managed (Defaults, cfg): `model_providers.custom.unknown_timeout` is ignored.\n session-flags: `model_providers.custom.unknown_timeout` is ignored.\n session-flags: `profiles.work.features.include_view_image_tool` is ignored. Use [features].view_image to configure the image tool."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn removed_private_desktop_setting_has_migration_hint() {
|
||||
let config = ConfigLayerStack::new(
|
||||
vec![layer(
|
||||
ConfigLayerSource::SessionFlags,
|
||||
"[windows]\nsandbox_private_desktop = false",
|
||||
)],
|
||||
ConfigRequirements::default(),
|
||||
ConfigRequirementsToml::default(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ignored_config_warning(&config, &[]).unwrap(),
|
||||
"Codex is ignoring 1 unrecognized configuration setting. Check for typos or deprecated settings.\n session-flags: `windows.sandbox_private_desktop` is ignored. Remove windows.sandbox_private_desktop; legacy Windows sandboxes always use a private desktop."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,9 +170,6 @@ pub enum WindowsSandboxModeToml {
|
||||
#[schemars(deny_unknown_fields)]
|
||||
pub struct WindowsToml {
|
||||
pub sandbox: Option<WindowsSandboxModeToml>,
|
||||
/// Defaults to `true` for legacy sandboxes and `false` for MXC. Set to `false`
|
||||
/// to launch the final sandboxed child process on `Winsta0\\Default`.
|
||||
pub sandbox_private_desktop: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, JsonSchema)]
|
||||
|
||||
Reference in New Issue
Block a user