mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Add a CLI command to uninstall the legacy Windows sandbox (#50437)
## What changed Add `codex sandbox uninstall` to remove machine-wide legacy Windows sandbox accounts and network rules with administrator privileges. Run cleanup without loading configuration, preserving Codex home, sandbox directories, and filesystem permissions. Reject the command on other platforms. Keep commands after `--` forwarded to the sandbox, including `codex sandbox -- uninstall --help`. ## Testing Add parsing coverage for the uninstall subcommand and command separator. Add an integration test verifying that help and invalid arguments work with malformed configuration and leave configuration and credentials unchanged. GitOrigin-RevId: d2b02ef7bc0a05742dd5eb3c47292ad517d46664
This commit is contained in:
@@ -76,6 +76,7 @@ mod queue_cmd;
|
||||
mod remote_control_cmd;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod sandbox_setup;
|
||||
mod sandbox_uninstall;
|
||||
mod state_db_recovery;
|
||||
#[cfg(not(windows))]
|
||||
mod wsl_paths;
|
||||
@@ -189,7 +190,7 @@ enum Subcommand {
|
||||
Doctor(DoctorCommand),
|
||||
|
||||
/// Run commands within a Codex-provided sandbox.
|
||||
Sandbox(HostSandboxArgs),
|
||||
Sandbox(SandboxCommand),
|
||||
|
||||
/// Debugging tools.
|
||||
Debug(DebugCommand),
|
||||
@@ -459,6 +460,20 @@ impl clap::FromArgMatches for SessionTuiCli {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct SandboxCommand {
|
||||
#[command(flatten)]
|
||||
host: HostSandboxArgs,
|
||||
|
||||
#[command(subcommand)]
|
||||
subcommand: Option<SandboxSubcommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
enum SandboxSubcommand {
|
||||
Uninstall(sandbox_uninstall::SandboxUninstallCommand),
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
type HostSandboxArgs = codex_cli::SeatbeltCommand;
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -1652,7 +1667,10 @@ async fn cli_main(
|
||||
codex_cloud_tasks::run_main(cloud_cli, arg0_paths.codex_linux_sandbox_exe.clone())
|
||||
.await?;
|
||||
}
|
||||
Some(Subcommand::Sandbox(mut sandbox_cli)) => {
|
||||
Some(Subcommand::Sandbox(SandboxCommand {
|
||||
host: mut sandbox_cli,
|
||||
subcommand,
|
||||
})) => {
|
||||
let config_profile = sandbox_cli
|
||||
.config_profile
|
||||
.as_ref()
|
||||
@@ -1680,6 +1698,9 @@ async fn cli_main(
|
||||
root_remote_auth_token_env.as_deref(),
|
||||
"sandbox",
|
||||
)?;
|
||||
if let Some(SandboxSubcommand::Uninstall(command)) = subcommand {
|
||||
return command.run();
|
||||
}
|
||||
let loader_overrides = loader_overrides_for_profile(config_profile)?;
|
||||
#[cfg(target_os = "macos")]
|
||||
codex_cli::run_command_under_seatbelt(
|
||||
@@ -3552,6 +3573,38 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sandbox_uninstall_respects_command_separator() {
|
||||
let cli = MultitoolCli::try_parse_from(["codex", "sandbox", "uninstall"]).expect("parse");
|
||||
assert!(matches!(
|
||||
cli.subcommand,
|
||||
Some(Subcommand::Sandbox(SandboxCommand {
|
||||
subcommand: Some(SandboxSubcommand::Uninstall(_)),
|
||||
..
|
||||
}))
|
||||
));
|
||||
|
||||
for args in [
|
||||
vec!["codex", "sandbox", "--", "uninstall", "--help"],
|
||||
vec![
|
||||
"codex",
|
||||
"sandbox",
|
||||
"--profile",
|
||||
"uninstall",
|
||||
"--",
|
||||
"uninstall",
|
||||
"--help",
|
||||
],
|
||||
] {
|
||||
let cli = MultitoolCli::try_parse_from(args).expect("parse forwarded command");
|
||||
let Some(Subcommand::Sandbox(command)) = cli.subcommand else {
|
||||
panic!("expected sandbox command");
|
||||
};
|
||||
assert!(command.subcommand.is_none());
|
||||
assert_eq!(command.host.command, vec!["uninstall", "--help"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
#[test]
|
||||
fn sandbox_parses_permission_profile() {
|
||||
@@ -3565,7 +3618,7 @@ mod tests {
|
||||
])
|
||||
.expect("parse");
|
||||
|
||||
let Some(Subcommand::Sandbox(command)) = cli.subcommand else {
|
||||
let Some(Subcommand::Sandbox(SandboxCommand { host: command, .. })) = cli.subcommand else {
|
||||
panic!("expected sandbox command");
|
||||
};
|
||||
|
||||
@@ -3586,7 +3639,7 @@ mod tests {
|
||||
])
|
||||
.expect("parse");
|
||||
|
||||
let Some(Subcommand::Sandbox(command)) = cli.subcommand else {
|
||||
let Some(Subcommand::Sandbox(SandboxCommand { host: command, .. })) = cli.subcommand else {
|
||||
panic!("expected sandbox command");
|
||||
};
|
||||
|
||||
@@ -3609,7 +3662,7 @@ mod tests {
|
||||
MultitoolCli::try_parse_from(["codex", "sandbox", "-P", ":workspace", "--", "echo"])
|
||||
.expect("parse");
|
||||
|
||||
let Some(Subcommand::Sandbox(command)) = cli.subcommand else {
|
||||
let Some(Subcommand::Sandbox(SandboxCommand { host: command, .. })) = cli.subcommand else {
|
||||
panic!("expected sandbox command");
|
||||
};
|
||||
|
||||
@@ -3624,7 +3677,7 @@ mod tests {
|
||||
MultitoolCli::try_parse_from(["codex", "sandbox", "--profile", "work", "--", "echo"])
|
||||
.expect("parse");
|
||||
|
||||
let Some(Subcommand::Sandbox(command)) = cli.subcommand else {
|
||||
let Some(Subcommand::Sandbox(SandboxCommand { host: command, .. })) = cli.subcommand else {
|
||||
panic!("expected sandbox command");
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//! Uninstalls the legacy Windows sandbox without loading config or removing user data.
|
||||
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[command(
|
||||
about = "Remove the legacy Windows sandbox's machine-wide accounts and network rules",
|
||||
after_help = "Run as administrator after stopping apps using the legacy sandbox and its provisioning service, if installed.\nPreserves Codex home, including sandbox directories and filesystem permissions."
|
||||
)]
|
||||
pub(crate) struct SandboxUninstallCommand {}
|
||||
|
||||
impl SandboxUninstallCommand {
|
||||
pub(crate) fn run(self) -> anyhow::Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
codex_windows_sandbox::clean_up_legacy_windows_sandbox()
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
anyhow::bail!("`codex sandbox uninstall` is only supported on Windows")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user