From 3939573e9941529f888f9828b0a8054b0b1434c7 Mon Sep 17 00:00:00 2001 From: meh Date: Mon, 10 Aug 2026 13:35:04 +0700 Subject: [PATCH 1/2] release: 0.4.17 --- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f23dc08..88388d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ appear in a patch rather than inflating the version toward 1.0 on a crate still shape. **Where that happens the entry says so at the top**, because a version number that under-signals is only acceptable if the changelog over-signals to compensate. +## 0.4.17 + +### Fixed + +- **`Permission::Auto` now means the same thing on both Codex transports.** + The app-server path grants `networkAccess: true` for Auto and withholds it + for Edit, while `codex exec` set no network configuration at all, so a caller + asking for Auto received the Edit posture whenever approvals were off. The + exec path now carries the documented + `sandbox_workspace_write.network_access` override. Edit stays gated. + ## 0.4.16 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 5924216..8421a6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agent-abstraction" -version = "0.4.16" +version = "0.4.17" edition = "2024" # The floor edition 2024 requires, and where the strictest dependencies (uuid, # getrandom) sit. Derived from the dependency graph rather than compile-tested. From 3044205901643ce032a4033caf76e929f10d061f Mon Sep 17 00:00:00 2001 From: meh Date: Mon, 10 Aug 2026 13:33:56 +0700 Subject: [PATCH 2/2] fix: give Codex Auto the same network posture on both transports The app-server path grants networkAccess for Auto and withholds it for Edit. The exec path set no network configuration, so the same Permission produced a different capability depending on whether approvals happened to be enabled for that run. codex exec has no network flag, so the documented sandbox_workspace_write.network_access override carries it. Edit stays gated, which is what keeps its approvals meaningful. --- src/agent.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/agent.rs b/src/agent.rs index df5a64f..6a5cf14 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -960,6 +960,18 @@ fn argv_codex(plan: &Plan) -> Vec { (Some(mode), true) => a.pair("-c", format!("sandbox_mode={mode}")), }; + // Auto means the same thing on both transports. + // + // The app-server path grants `networkAccess: true` for Auto and withholds + // it for Edit, so a caller asking for Auto over `codex exec` was quietly + // getting the Edit posture: same `Permission`, different capability, chosen + // by whether approvals happened to be enabled for that run. `codex exec` + // has no network flag, so the documented config key carries it, which is + // the same lever the CLI's own help points at. + if matches!(plan.permission, Permission::Auto) { + a.pair("-c", "sandbox_workspace_write.network_access=true"); + } + a.opt("--model", plan.model.as_ref()); // Verified against codex-cli 0.146.0: `codex exec` has no effort flag, it // is a config override, and `--strict-config` accepts this key. A bad value @@ -1691,6 +1703,32 @@ mod tests { )); } + /// Auto is one posture, not one posture per transport. + /// + /// The app-server path grants `networkAccess: true` for Auto and withholds + /// it for Edit. `codex exec` has no network flag, so without the config + /// override a caller asking for Auto silently received the Edit posture + /// whenever approvals were off. + #[test] + fn auto_grants_network_on_the_codex_exec_path_too() { + let mut p = plan("codex"); + p.permission = Permission::Auto; + let auto = Agent::Codex.argv(&p).expect("auto builds"); + assert!( + auto.iter() + .any(|arg| arg == "sandbox_workspace_write.network_access=true"), + "Auto must grant network on exec as it does on app-server: {auto:?}" + ); + + let mut p = plan("codex"); + p.permission = Permission::Edit; + let edit = Agent::Codex.argv(&p).expect("edit builds"); + assert!( + !edit.iter().any(|arg| arg.contains("network_access")), + "Edit keeps network gated so its approvals stay meaningful: {edit:?}" + ); + } + /// The failure mode this refusal exists to prevent is a silent one: an /// agent with no command vocabulary reads `/compact` as prose and answers a /// question *about* compaction, which looks from the outside exactly like