Skip to content

Commit 3d10ba9

Browse files
chore(cli) deprecate --full-auto (#20133)
## Summary Starts the process of getting rid of `--full-auto`, with some concessions: 1. Fully removes the command from the tui, since it just resolves to the default permissions there, and encourages users to use the one-time trust flow if they're not in a trusted repo. 2. Marks the command as deprecated in `codex exec`, in case users are actively relying on this. We'll remove in an upcoming n+X release. 3. Cleans up some of the `codex sandbox` cli logic, to keep supporting legacy sandbox policies for now. This isn't the cleanest setup, but I think it is worthwhile to warn users for one release before hard-removing it. ## Testing - [x] Updated unit tests
1 parent e1ec9e6 commit 3d10ba9

11 files changed

Lines changed: 181 additions & 95 deletions

File tree

codex-cli/scripts/run_in_container.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,4 @@ quoted_args=""
9292
for arg in "$@"; do
9393
quoted_args+=" $(printf '%q' "$arg")"
9494
done
95-
docker exec -it "$CONTAINER_NAME" bash -c "cd \"/app$WORK_DIR\" && codex --full-auto ${quoted_args}"
95+
docker exec -it "$CONTAINER_NAME" bash -c "cd \"/app$WORK_DIR\" && codex --sandbox workspace-write --ask-for-approval on-request ${quoted_args}"

codex-rs/README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,22 @@ To test to see what happens when a command is run under the sandbox provided by
5959

6060
```
6161
# macOS
62-
codex sandbox macos [--full-auto] [--log-denials] [COMMAND]...
62+
codex sandbox macos [--log-denials] [COMMAND]...
6363
6464
# Linux
65-
codex sandbox linux [--full-auto] [COMMAND]...
65+
codex sandbox linux [COMMAND]...
6666
6767
# Windows
68-
codex sandbox windows [--full-auto] [COMMAND]...
68+
codex sandbox windows [COMMAND]...
6969
7070
# Legacy aliases
71-
codex debug seatbelt [--full-auto] [--log-denials] [COMMAND]...
72-
codex debug landlock [--full-auto] [COMMAND]...
71+
codex debug seatbelt [--log-denials] [COMMAND]...
72+
codex debug landlock [COMMAND]...
7373
```
7474

75+
To try a writable legacy sandbox mode with these commands, pass an explicit config override such
76+
as `-c 'sandbox_mode="workspace-write"'`.
77+
7578
### Selecting a sandbox policy via `--sandbox`
7679

7780
The Rust CLI exposes a dedicated `--sandbox` (`-s`) flag that lets you pick the sandbox policy **without** having to reach for the generic `-c/--config` option:

codex-rs/cli/src/debug_sandbox.rs

Lines changed: 92 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ pub async fn run_command_under_seatbelt(
4242
codex_linux_sandbox_exe: Option<PathBuf>,
4343
) -> anyhow::Result<()> {
4444
let SeatbeltCommand {
45-
full_auto,
4645
allow_unix_sockets,
4746
log_denials,
4847
config_overrides,
4948
command,
5049
} = command;
5150
run_command_under_sandbox(
52-
full_auto,
5351
command,
5452
config_overrides,
5553
codex_linux_sandbox_exe,
@@ -73,12 +71,10 @@ pub async fn run_command_under_landlock(
7371
codex_linux_sandbox_exe: Option<PathBuf>,
7472
) -> anyhow::Result<()> {
7573
let LandlockCommand {
76-
full_auto,
7774
config_overrides,
7875
command,
7976
} = command;
8077
run_command_under_sandbox(
81-
full_auto,
8278
command,
8379
config_overrides,
8480
codex_linux_sandbox_exe,
@@ -94,12 +90,10 @@ pub async fn run_command_under_windows(
9490
codex_linux_sandbox_exe: Option<PathBuf>,
9591
) -> anyhow::Result<()> {
9692
let WindowsCommand {
97-
full_auto,
9893
config_overrides,
9994
command,
10095
} = command;
10196
run_command_under_sandbox(
102-
full_auto,
10397
command,
10498
config_overrides,
10599
codex_linux_sandbox_exe,
@@ -118,7 +112,6 @@ enum SandboxType {
118112
}
119113

120114
async fn run_command_under_sandbox(
121-
full_auto: bool,
122115
command: Vec<String>,
123116
config_overrides: CliConfigOverrides,
124117
codex_linux_sandbox_exe: Option<PathBuf>,
@@ -132,7 +125,6 @@ async fn run_command_under_sandbox(
132125
.parse_overrides()
133126
.map_err(anyhow::Error::msg)?,
134127
codex_linux_sandbox_exe,
135-
full_auto,
136128
)
137129
.await?;
138130

@@ -402,14 +394,6 @@ async fn run_command_under_windows_session(
402394
std::process::exit(exit_code);
403395
}
404396

405-
pub fn create_sandbox_mode(full_auto: bool) -> SandboxMode {
406-
if full_auto {
407-
SandboxMode::WorkspaceWrite
408-
} else {
409-
SandboxMode::ReadOnly
410-
}
411-
}
412-
413397
async fn spawn_debug_sandbox_child(
414398
program: PathBuf,
415399
args: Vec<String>,
@@ -579,12 +563,10 @@ mod windows_stdio_bridge {
579563
async fn load_debug_sandbox_config(
580564
cli_overrides: Vec<(String, TomlValue)>,
581565
codex_linux_sandbox_exe: Option<PathBuf>,
582-
full_auto: bool,
583566
) -> anyhow::Result<Config> {
584567
load_debug_sandbox_config_with_codex_home(
585568
cli_overrides,
586569
codex_linux_sandbox_exe,
587-
full_auto,
588570
/*codex_home*/ None,
589571
)
590572
.await
@@ -593,9 +575,14 @@ async fn load_debug_sandbox_config(
593575
async fn load_debug_sandbox_config_with_codex_home(
594576
cli_overrides: Vec<(String, TomlValue)>,
595577
codex_linux_sandbox_exe: Option<PathBuf>,
596-
full_auto: bool,
597578
codex_home: Option<PathBuf>,
598579
) -> anyhow::Result<Config> {
580+
// For legacy configs, `codex sandbox` historically defaulted to read-only
581+
// instead of inheriting ambient `sandbox_mode` settings from user/system
582+
// config. Keep that behavior unless this invocation explicitly passes a
583+
// legacy `sandbox_mode` CLI override, which is now the documented writable
584+
// replacement for the removed `--full-auto` flag.
585+
let uses_legacy_sandbox_mode_override = cli_overrides_use_legacy_sandbox_mode(&cli_overrides);
599586
let config = build_debug_sandbox_config(
600587
cli_overrides.clone(),
601588
ConfigOverrides {
@@ -606,19 +593,14 @@ async fn load_debug_sandbox_config_with_codex_home(
606593
)
607594
.await?;
608595

609-
if config_uses_permission_profiles(&config) {
610-
if full_auto {
611-
anyhow::bail!(
612-
"`codex sandbox --full-auto` is only supported for legacy `sandbox_mode` configs; choose a writable `[permissions]` profile instead"
613-
);
614-
}
596+
if config_uses_permission_profiles(&config) || uses_legacy_sandbox_mode_override {
615597
return Ok(config);
616598
}
617599

618600
build_debug_sandbox_config(
619601
cli_overrides,
620602
ConfigOverrides {
621-
sandbox_mode: Some(create_sandbox_mode(full_auto)),
603+
sandbox_mode: Some(SandboxMode::ReadOnly),
622604
codex_linux_sandbox_exe,
623605
..Default::default()
624606
},
@@ -652,9 +634,14 @@ fn config_uses_permission_profiles(config: &Config) -> bool {
652634
.is_some()
653635
}
654636

637+
fn cli_overrides_use_legacy_sandbox_mode(cli_overrides: &[(String, TomlValue)]) -> bool {
638+
cli_overrides.iter().any(|(key, _)| key == "sandbox_mode")
639+
}
640+
655641
#[cfg(test)]
656642
mod tests {
657643
use super::*;
644+
use pretty_assertions::assert_eq;
658645
use tempfile::TempDir;
659646

660647
fn escape_toml_path(path: &std::path::Path) -> String {
@@ -701,7 +688,7 @@ mod tests {
701688
let legacy_config = build_debug_sandbox_config(
702689
Vec::new(),
703690
ConfigOverrides {
704-
sandbox_mode: Some(create_sandbox_mode(/*full_auto*/ false)),
691+
sandbox_mode: Some(SandboxMode::ReadOnly),
705692
..Default::default()
706693
},
707694
Some(codex_home_path.clone()),
@@ -711,7 +698,6 @@ mod tests {
711698
let config = load_debug_sandbox_config_with_codex_home(
712699
Vec::new(),
713700
/*codex_linux_sandbox_exe*/ None,
714-
/*full_auto*/ false,
715701
Some(codex_home_path),
716702
)
717703
.await?;
@@ -735,25 +721,90 @@ mod tests {
735721
}
736722

737723
#[tokio::test]
738-
async fn debug_sandbox_rejects_full_auto_for_permission_profiles() -> anyhow::Result<()> {
724+
async fn debug_sandbox_honors_explicit_legacy_sandbox_mode() -> anyhow::Result<()> {
739725
let codex_home = TempDir::new()?;
740-
let sandbox_paths = TempDir::new()?;
741-
let docs = sandbox_paths.path().join("docs");
742-
let private = docs.join("private");
743-
write_permissions_profile_config(&codex_home, &docs, &private)?;
726+
let codex_home_path = codex_home.path().to_path_buf();
727+
let cli_overrides = vec![(
728+
"sandbox_mode".to_string(),
729+
TomlValue::String("workspace-write".to_string()),
730+
)];
744731

745-
let err = load_debug_sandbox_config_with_codex_home(
732+
let workspace_write_config = build_debug_sandbox_config(
733+
cli_overrides.clone(),
734+
ConfigOverrides::default(),
735+
Some(codex_home_path.clone()),
736+
)
737+
.await?;
738+
let read_only_config = build_debug_sandbox_config(
746739
Vec::new(),
740+
ConfigOverrides {
741+
sandbox_mode: Some(SandboxMode::ReadOnly),
742+
..Default::default()
743+
},
744+
Some(codex_home_path.clone()),
745+
)
746+
.await?;
747+
748+
let config = load_debug_sandbox_config_with_codex_home(
749+
cli_overrides,
747750
/*codex_linux_sandbox_exe*/ None,
748-
/*full_auto*/ true,
749-
Some(codex_home.path().to_path_buf()),
751+
Some(codex_home_path),
750752
)
751-
.await
752-
.expect_err("full-auto should be rejected for active permission profiles");
753+
.await?;
753754

754-
assert!(
755-
err.to_string().contains("--full-auto"),
756-
"unexpected error: {err}"
755+
if cfg!(target_os = "windows") {
756+
assert_eq!(
757+
workspace_write_config
758+
.permissions
759+
.file_system_sandbox_policy(),
760+
read_only_config.permissions.file_system_sandbox_policy(),
761+
"workspace-write downgrades to read-only when the Windows sandbox is disabled"
762+
);
763+
} else {
764+
assert_ne!(
765+
workspace_write_config
766+
.permissions
767+
.file_system_sandbox_policy(),
768+
read_only_config.permissions.file_system_sandbox_policy(),
769+
"test fixture should distinguish explicit workspace-write from read-only"
770+
);
771+
}
772+
assert_eq!(
773+
config.permissions.file_system_sandbox_policy(),
774+
workspace_write_config
775+
.permissions
776+
.file_system_sandbox_policy(),
777+
);
778+
779+
Ok(())
780+
}
781+
782+
#[tokio::test]
783+
async fn debug_sandbox_defaults_legacy_configs_to_read_only() -> anyhow::Result<()> {
784+
let codex_home = TempDir::new()?;
785+
let codex_home_path = codex_home.path().to_path_buf();
786+
787+
let read_only_config = build_debug_sandbox_config(
788+
Vec::new(),
789+
ConfigOverrides {
790+
sandbox_mode: Some(SandboxMode::ReadOnly),
791+
..Default::default()
792+
},
793+
Some(codex_home_path.clone()),
794+
)
795+
.await?;
796+
797+
let config = load_debug_sandbox_config_with_codex_home(
798+
Vec::new(),
799+
/*codex_linux_sandbox_exe*/ None,
800+
Some(codex_home_path),
801+
)
802+
.await?;
803+
804+
assert!(!config_uses_permission_profiles(&config));
805+
assert_eq!(
806+
config.permissions.file_system_sandbox_policy(),
807+
read_only_config.permissions.file_system_sandbox_policy(),
757808
);
758809

759810
Ok(())

codex-rs/cli/src/lib.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ pub use login::run_logout;
2121

2222
#[derive(Debug, Parser)]
2323
pub struct SeatbeltCommand {
24-
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
25-
#[arg(long = "full-auto", default_value_t = false)]
26-
pub full_auto: bool,
27-
2824
/// Allow the sandboxed command to bind/connect AF_UNIX sockets rooted at this path. Relative paths are resolved against the current directory. Repeat to allow multiple paths.
2925
#[arg(long = "allow-unix-socket", value_parser = parse_allow_unix_socket_path)]
3026
pub allow_unix_sockets: Vec<AbsolutePathBuf>,
@@ -48,10 +44,6 @@ fn parse_allow_unix_socket_path(raw: &str) -> Result<AbsolutePathBuf, String> {
4844

4945
#[derive(Debug, Parser)]
5046
pub struct LandlockCommand {
51-
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
52-
#[arg(long = "full-auto", default_value_t = false)]
53-
pub full_auto: bool,
54-
5547
#[clap(skip)]
5648
pub config_overrides: CliConfigOverrides,
5749

@@ -62,10 +54,6 @@ pub struct LandlockCommand {
6254

6355
#[derive(Debug, Parser)]
6456
pub struct WindowsCommand {
65-
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
66-
#[arg(long = "full-auto", default_value_t = false)]
67-
pub full_auto: bool,
68-
6957
#[clap(skip)]
7058
pub config_overrides: CliConfigOverrides,
7159

0 commit comments

Comments
 (0)