From 4c783be52de02a1093709246273fc288bd79d43f Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Mon, 4 May 2026 23:37:20 -0500 Subject: [PATCH] =?UTF-8?q?fix(yolo):=20drop=20sandbox=20to=20DangerFullAc?= =?UTF-8?q?cess=20=E2=80=94=20no=20guardrails=20as=20advertised?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User report: YOLO mode was still routing shell commands through the WorkspaceWrite sandbox, which intercepted legitimate outside-workspace writes (package installs, sub-agent workspaces, package-manager state under ~/.cache, brew, npm install -g, pipx, …) and forced approval round-trips. That contradicts the YOLO contract — the user opted into "no guardrails" and instead got a guardrail. YOLO already auto-approves all tools and enables trust mode. The sandbox was the last residual restriction. Drop it. Change in `Engine::build_tool_context`: split the previously-merged `AppMode::Agent | AppMode::Yolo` arm into two: * **Agent** keeps `WorkspaceWrite { writable_roots, network_access: true, … }` — interactive mode with explicit per-tool approval, so the sandbox plus the approval flow form a defense-in-depth layer. * **Yolo** uses `DangerFullAccess` — no sandbox. The user has opted into auto-approval + trust mode + no sandbox as one consistent posture. Plan mode unchanged (read-only, no shell tool registered). Updated `agent_and_yolo_modes_elevate_shell_sandbox_to_allow_network` to pin the new YOLO contract: `DangerFullAccess` specifically, not just "has network access." Verified locally: * `cargo fmt --all -- --check` clean. * `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` clean. * `cargo test --workspace --all-features --locked` — green (the snapshot::repo flake still flakes in batch but passes in isolation; unrelated). Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/tui/src/core/engine.rs | 26 +++++++++++++++++++------- crates/tui/src/core/engine/tests.rs | 18 +++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/crates/tui/src/core/engine.rs b/crates/tui/src/core/engine.rs index 2f7ef663..2cd07872 100644 --- a/crates/tui/src/core/engine.rs +++ b/crates/tui/src/core/engine.rs @@ -1294,13 +1294,14 @@ impl Engine { // registered, so leaving the sandbox policy at the seatbelt-strict // default is fine. AppMode::Plan => ctx, - // Agent and Yolo both register the shell tool. The sandbox-default - // policy denies all outbound network — including DNS — which - // breaks ordinary developer commands (cargo fetch, npm install, - // curl, yt-dlp, …) without buying the user any safety the - // application-level NetworkPolicy / approval flow doesn't already - // provide. Elevate to workspace-write + network. (#273) - AppMode::Agent | AppMode::Yolo => { + // Agent registers the shell tool and runs each command through + // the per-mode sandbox + per-tool approval flow. The sandbox + // default would deny all outbound network — including DNS — + // which breaks ordinary developer commands (cargo fetch, npm + // install, curl, yt-dlp, …) without buying the user any safety + // the approval flow doesn't already provide. Elevate to + // workspace-write + network. (#273) + AppMode::Agent => { ctx.with_elevated_sandbox_policy(crate::sandbox::SandboxPolicy::WorkspaceWrite { writable_roots: vec![self.session.workspace.clone()], network_access: true, @@ -1308,6 +1309,17 @@ impl Engine { exclude_slash_tmp: false, }) } + // YOLO is the explicit "no guardrails" mode — auto-approve all + // tools, trust mode on, no sandbox. Workspace-write was still + // intercepting commands that wanted to write outside the + // workspace (rare but legitimate: pipx install, npm install + // -g, brew, package-manager state under ~/.cache, sub-agent + // workspaces, …) which forced approval round-trips and + // contradicts the YOLO contract. The user opted into YOLO + // deliberately; trust them. + AppMode::Yolo => { + ctx.with_elevated_sandbox_policy(crate::sandbox::SandboxPolicy::DangerFullAccess) + } } } diff --git a/crates/tui/src/core/engine/tests.rs b/crates/tui/src/core/engine/tests.rs index 5179d97a..37f83a88 100644 --- a/crates/tui/src/core/engine/tests.rs +++ b/crates/tui/src/core/engine/tests.rs @@ -390,12 +390,20 @@ fn agent_and_yolo_modes_elevate_shell_sandbox_to_allow_network() { ); let yolo_ctx = engine.build_tool_context(AppMode::Yolo, false); + let yolo_policy = yolo_ctx + .elevated_sandbox_policy + .as_ref() + .expect("Yolo mode should elevate the sandbox policy"); + assert!(yolo_policy.has_network_access()); + // v0.8.11: YOLO drops to DangerFullAccess (no sandbox) so the user + // is not bounced through approval round-trips for legitimate + // outside-workspace writes (package installs, sub-agent + // workspaces, ~/.cache mutations, etc.). YOLO is opt-in and + // already enables trust mode + auto-approve; the sandbox was the + // last guardrail and contradicts the contract. assert!( - yolo_ctx - .elevated_sandbox_policy - .as_ref() - .expect("Yolo mode should elevate the sandbox policy") - .has_network_access(), + matches!(yolo_policy, crate::sandbox::SandboxPolicy::DangerFullAccess), + "Yolo mode must use DangerFullAccess (no sandbox); got {yolo_policy:?}", ); // Plan mode is read-only investigation and does not register the shell