mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
42c80385cd6e2c8efc8b85c39bb9bde5edf01fc3
6049 Commits
-
[codex] Avoid PowerShell safety parsing off Windows (#24946)
## Summary This fixes BUGB-17567 by preventing non-Windows command safety classification from invoking the Windows PowerShell safelist/parser path. Previously, `is_known_safe_command` called the Windows PowerShell classifier on every platform. That classifier recognizes `pwsh`/`powershell` by basename and delegates script parsing to the PowerShell AST parser. The parser starts the supplied executable, so on macOS/Linux a repository-controlled `pwsh` path could execute during safety parsing before the normal sandboxed command execution path. The change gates the Windows PowerShell classifier and module behind `#[cfg(windows)]`. On macOS/Linux, PowerShell-looking commands are no longer auto-approved by the Windows classifier and instead fall through to the normal non-Windows safe-command logic. ## Validation - `/private/tmp/codex-tools/bin/just fmt` - `PATH=/private/tmp/codex-tools/bin:$PATH /private/tmp/codex-tools/bin/just test -p codex-shell-command` The focused test run passed 135 tests with 0 skipped and completed the crate bench-smoke step. ## Notes This PR is scoped to the BUGB-17567 macOS/Linux path. Windows still uses the PowerShell classifier; a separate hardening follow-up should ensure Windows safety parsing only executes a trusted PowerShell parser binary and does not spawn the command's `argv[0]` when that path may be repository-controlled.
Adrian ·
2026-05-29 03:00:35 +00:00 -
fix(config): use deny for Unix socket permissions (#24970)
## Why Unix socket permissions still accepted and displayed `"none"` while file permissions use the clearer `"deny"` spelling. This keeps network Unix socket policy vocabulary consistent with filesystem policy vocabulary. ## What changed - Replace the Unix socket permission variant and serialized spelling from `none` to `deny` across config, feature configuration, and network proxy types. - Update app-server v2 serialization, TUI debug output, focused tests, and generated schemas to expose `"deny"`. - Add coverage for denied Unix socket entries in managed requirements and profile overlay behavior. ## Security This is a vocabulary change for explicit Unix socket rejection, not a network access expansion. Denied entries continue to be omitted from the effective allowlist. ## Validation - `just fmt` - `just write-config-schema` - `just write-app-server-schema` - `just test -p codex-config -p codex-core -p codex-app-server-protocol -p codex-tui -E 'test(network_requirements_are_preserved_as_constraints_with_source) | test(network_permission_containers_project_allowed_and_denied_entries) | test(network_toml_overlays_unix_socket_permissions_by_path) | test(permissions_profiles_resolve_extends_parent_first_with_child_overrides) | test(network_requirements_serializes_canonical_and_legacy_fields) | test(debug_config_output_formats_unix_socket_permissions)'`\n- Automatic `bench-smoke` follow-up from `just test`\n- `cargo clippy -p codex-config -p codex-core -p codex-features -p codex-network-proxy -p codex-app-server-protocol -p codex-app-server -p codex-tui --all-targets -- -D warnings`
viyatb-oai ·
2026-05-28 23:53:26 +00:00 -
feat(app-server): migrate remote control to server tokens (#24141)
## Why `codex-backend` now authenticates remote-control server websocket connections with short-lived server tokens instead of the user's ChatGPT access token. `app-server` needs to mint and refresh those server tokens without persisting them, so a restart can reconnect from durable enrollment identity while keeping the bearer token memory-only. ## What Changed Updated the remote-control transport to consume `remote_control_token` and `expires_at` from server enroll responses and added `/server/refresh` support for persisted enrollments or expiring cached tokens. Websocket handshakes now send `Authorization: Bearer <remote_control_token>` with the existing server identity headers, and no longer send the ChatGPT bearer token or `chatgpt-account-id` on that websocket path. The in-memory enrollment state now owns the ephemeral server token cache, while SQLite still persists only `server_id`, `environment_id`, and `server_name`. Websocket `401`/`403` clears only the cached token for refresh on reconnect; websocket or refresh `404` clears stale persisted enrollment and re-enrolls. Response body previews redact `remote_control_token` before surfacing parse errors. ## Verification - `just test -p codex-app-server-transport` - Manual prod smoke with an isolated `CODEX_HOME`: `codex remote-control --json -c 'chatgpt_base_url="https://chatgpt.com/backend-api"'` reached `status:"connected"` with `environmentId:"env_i_6a17d9f1d764832986da2e80f4554f1b"`.
Anton Panasenko ·
2026-05-28 15:57:08 -07:00 -
Tighten hook output event schemas (#24962)
# Why Fixes #23993. Hook command output schemas are published as the contract for hook authors and schema-driven tooling. The event-specific output schemas previously described `hookSpecificOutput.hookEventName` as the global `HookEventNameWire` enum, so a `pre-tool-use.command.output` schema would validate mismatched values like `PostToolUse`. That made the schemas less precise than the intended event-specific contract. # What Constrain each hook-specific output schema to the matching literal `hookEventName` value, mirroring the existing input-schema shape. Also split `SubagentStartHookSpecificOutputWire` from the session-start output wire so `subagent-start.command.output.schema.json` can emit `const: "SubagentStart"` instead of sharing the session-start definition. # Verification - `cargo nextest run -p codex-hooks` - `just fix -p codex-hooks` - `just argument-comment-lint -p codex-hooks -- --all-targets`
Abhinav ·
2026-05-28 15:55:40 -07:00 -
windows-sandbox: fix capture cancellation test roots (#24974)
## Why The Windows Bazel job on `main` started failing after #24108 because one Windows-only capture test still passed `cwd.as_path()` to `run_windows_sandbox_capture`. That helper now expects the explicit `workspace_roots` slice introduced by #24108, so the Windows test target no longer compiled. ## What Changed - Updates `legacy_capture_cancellation_is_not_reported_as_timeout` to pass `workspace_roots_for(cwd.as_path()).as_slice()`, matching the adjacent capture test and the new runner signature. ## Verification - GitHub Actions CI is the important validation for this Windows-only compile path. - Created quickly to get Windows CI running while the separate Ubuntu `compact_resume_fork` timeout is still under investigation.
Michael Bolin ·
2026-05-28 15:51:27 -07:00 -
windows-sandbox: pass workspace roots to runner (#24108)
## Why #23813 switches the Windows sandbox runner path to `PermissionProfile`, but it still left one runtime anchor for resolving symbolic `:workspace_roots` entries. That is not enough once a turn has multiple effective workspace roots: exact entries and deny globs under `:workspace_roots` need to be materialized for every runtime root before the command runner chooses token mode or builds ACL plans. ## What Changed - Replaces the Windows runner/setup `permission_profile_cwd` plumbing with `workspace_roots: Vec<AbsolutePathBuf>`. - Resolves Windows-local `PermissionProfile` data with `materialize_project_roots_with_workspace_roots(...)` instead of the single-cwd helper. - Threads `Config::effective_workspace_roots()` through core execution, unified exec, TUI setup/read-grant flows, app-server setup, app-server `command/exec`, and `debug sandbox` on Windows. - Preserves those workspace roots through the zsh-fork escalation executor instead of rebuilding them from `sandbox_policy_cwd`. - Makes `ExecRequest::new(...)` and the remaining `build_exec_request(...)` helper path take `windows_sandbox_workspace_roots` explicitly so new call sites cannot silently fall back to `vec![cwd]`. - Clarifies the `debug sandbox` non-Windows comment: remaining cwd-dependent resolution still uses `sandbox_policy_cwd`, while `:workspace_roots` entries are already materialized from config roots. - Updates elevated runner IPC `SpawnRequest` to send `workspace_roots` and bumps the framed IPC protocol version to `3` for the payload shape change. - Adds Windows-local resolver coverage for expanding exact and glob `:workspace_roots` entries across multiple roots, plus core helper coverage proving explicit roots are preserved. ## Verification - `cargo check -p codex-windows-sandbox -p codex-core -p codex-tui -p codex-cli -p codex-app-server` - `cargo test -p codex-windows-sandbox` - `cargo test -p codex-core windows_sandbox` - `cargo test -p codex-core unix_escalation` - `cargo test -p codex-app-server windows_sandbox` - `cargo test -p codex-tui windows_sandbox` - `cargo test -p codex-cli debug_sandbox` - `just test -p codex-core unified_exec` - `just test -p codex-core build_exec_request_preserves_windows_workspace_roots` - `env -u CODEX_NETWORK_PROXY_ACTIVE -u CODEX_NETWORK_ALLOW_LOCAL_BINDING just test -p codex-app-server --lib command_exec` - `just test -p codex-windows-sandbox` - `just test -p codex-exec sandbox` - `just fix -p codex-core -p codex-app-server -p codex-windows-sandbox` A local macOS cross-check with `cargo check --target x86_64-pc-windows-msvc ...` did not reach crate Rust code because native dependencies require Windows SDK headers (`windows.h` / `assert.h`) in this environment; Windows CI remains the real target validation. Two local targeted filters compile but do not run assertions on macOS: `env -u CODEX_NETWORK_PROXY_ACTIVE -u CODEX_NETWORK_ALLOW_LOCAL_BINDING just test -p codex-app-server --lib command_exec_processor` matched zero tests, and `just test -p codex-linux-sandbox landlock` matched zero tests because the landlock suite is Linux-only.
Michael Bolin ·
2026-05-28 15:26:55 -07:00 -
Surface filesystem permission profiles in prompt context (#23924)
## Summary Some permission profiles can encode filesystem reads that should remain unavailable to the agent. Before this change, the model-visible context and automatic approval review prompt summarized the effective permissions as a legacy sandbox mode, which can omit permission-profile filesystem entries from escalation decisions. For example, a profile can grant workspace access while denying a private subtree across every workspace root: ```toml default_permissions = "restricted-workspace" [permissions.restricted-workspace.workspace_roots] "/Users/alice/project" = true "/Users/alice/other-project" = true [permissions.restricted-workspace.filesystem] ":minimal" = "read" [permissions.restricted-workspace.filesystem.":workspace_roots"] "." = "write" "private" = "deny" "private/**" = "deny" ``` The context window now describes the workspace roots and effective filesystem side of the `PermissionProfile` directly, with deny entries marked as non-escalatable: ```xml <environment_context> <cwd>/Users/alice/project</cwd> <shell>zsh</shell> <filesystem><workspace_roots><root>/Users/alice/project</root><root>/Users/alice/other-project</root></workspace_roots><permission_profile type="managed"><file_system type="restricted"><entry access="read"><special>:minimal</special></entry><entry access="write"><path>/Users/alice/project</path></entry><entry access="write"><path>/Users/alice/other-project</path></entry><entry access="deny" escalatable="false"><path>/Users/alice/project/private</path></entry><entry access="deny" escalatable="false"><path>/Users/alice/other-project/private</path></entry><entry access="deny" escalatable="false"><glob>/Users/alice/project/private/**</glob></entry><entry access="deny" escalatable="false"><glob>/Users/alice/other-project/private/**</glob></entry></file_system></permission_profile></filesystem> </environment_context> ``` Managed requirements can impose the same kind of deny-read restriction: ```toml [permissions.filesystem] deny_read = [ "/Users/alice/project/private", "/Users/alice/project/private/**", ] ``` The automatic approval review prompt also receives the parent turn's denied-read context, so review decisions can account for the active permission profile. ## What Changed - Render the effective filesystem profile in `<environment_context>`, including profile type, filesystem entries, workspace roots, and non-escalatable deny entries. - Persist effective `workspace_roots` in `TurnContextItem` so resumed/replayed context does not have to bind `:workspace_roots` through legacy `cwd` fallback. - Add explicit permission instructions that denied reads are policy restrictions, not escalation targets. - Pass the parent turn's denied-read context into automatic approval reviews. - Add targeted coverage for prompt rendering, workspace-root materialization, replay context, and review prompt context. - Keep the prompt-context test expectations platform-aware so the same filesystem rendering assertions pass on Unix and Windows paths. ## Testing - `just test -p codex-core context::environment_context::tests::serialize_environment_context_with_full_filesystem_profile` - `just test -p codex-core context::environment_context::tests::turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd` - `just test -p codex-core context::permissions_instructions::permissions_instructions_tests::builds_permissions_from_profile_with_denied_reads` - `just fix -p codex-core` I also attempted `just test -p codex-core`; the changed prompt-context tests passed, but the full local run did not complete cleanly in this sandboxed macOS environment due unrelated user-shell `CODEX_SANDBOX*` expectations and integration-test timeouts.
Michael Bolin ·
2026-05-28 14:56:53 -07:00 -
[codex] Add user input client ids (#24653)
## Summary Adds an optional `clientId` field to app-server v2 `UserInput` and carries it through the core `UserInput` model so clients can correlate echoed user input items without relying on payload equality. ## Details - Adds `client_id: Option<String>` to core `UserInput` variants. - Exposes the v2 app-server field as `clientId` on the wire and in generated TypeScript. - Preserves the id when converting between app-server v2 and core protocol types. - Regenerates app-server schema fixtures. ## Validation - `just fmt` - `just write-app-server-schema` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-protocol` - `just fix -p codex-app-server-protocol` - `just fix -p codex-protocol` - `git diff --check`
Alexi Christakis ·
2026-05-28 14:54:39 -07:00 -
fix(exec-server): reject websocket requests with Origin headers (#24947)
## Why `codex exec-server` has a local WebSocket listener, but it did not apply the same browser-origin request handling as the `app-server` WebSocket transport. Requests that carry an `Origin` header should not be upgraded by this local transport, keeping both local WebSocket servers consistent and avoiding unexpected browser-initiated connections. ## What changed - Added an Axum middleware guard in `codex-rs/exec-server/src/server/transport.rs` that returns `403 Forbidden` for requests carrying an `Origin` header. - Added an integration test in `codex-rs/exec-server/tests/websocket.rs` that covers rejection of an `Origin`-bearing WebSocket handshake. - Kept ordinary WebSocket clients unchanged: existing no-`Origin` initialization and process behavior remains covered by the crate tests. ## Validation - `just test -p codex-exec-server` test phase (`186 passed`; run outside the parent macOS sandbox so nested sandbox tests can execute) - `just clippy -p codex-exec-server`
viyatb-oai ·
2026-05-28 14:44:14 -07:00 -
fix: cancel Windows sandbox on network denial (#19880)
## Why When Guardian or the sandbox network proxy detects and denies a network attempt, core cancels the associated execution through `ExecExpiration`. The Windows sandbox capture path was only forwarding the timeout component of that expiration state. As a result, a sandboxed Windows command whose network attempt had already been denied could keep running until its timeout elapsed rather than terminating promptly in response to the denial. This change closes that cancellation-propagation gap for Windows sandbox execution. ## What changed - Added `WindowsSandboxCancellationToken` as the cancellation hook exposed to Windows capture backends. - Extracted the cancellation token from `ExecExpiration` in core and passed it to both the direct and elevated Windows sandbox capture paths alongside the existing timeout. - Updated direct capture to poll for either process exit, timeout, or cancellation and to terminate cancelled processes without reporting them as timed out. - Updated elevated capture to watch for cancellation and send the existing `Terminate` IPC frame to the elevated runner. The watcher parks for 50 ms between checks to bound response latency without a tight busy wait. - Added Windows regression coverage for a long-running PowerShell command: cancellation ends capture before its timeout and does not set `timed_out`. - Added a visible skip diagnostic when that PowerShell-dependent regression test cannot execute, and consolidated the duplicated expiration-policy branch identified in review. ## Security This improves enforcement after a denied network attempt has been attributed to a Windows sandboxed execution: the command no longer remains alive simply because Windows capture lost the cancellation signal. This PR does not claim to make Windows offline mode an airtight no-network or no-exfiltration boundary. It does not introduce AppContainer or change how network denial is detected; it makes an already-detected denial promptly stop the affected sandboxed command. ## Validation ### Commands run - `just fmt` - `cargo test -p codex-windows-sandbox` - `cargo test -p codex-core network_denial` - `cargo clippy -p codex-core -p codex-windows-sandbox --tests --no-deps -- -D warnings` - `just argument-comment-lint -p codex-windows-sandbox -p codex-core` The new capture regression is `cfg(target_os = "windows")`, so Windows CI is the execution coverage for that test path. The local macOS test runs validate the host-runnable crate and core network-denial behavior. --------- Co-authored-by: Codex <noreply@openai.com>
viyatb-oai ·
2026-05-28 21:28:06 +00:00 -
runtime: prepend zsh fork bin dir to PATH (#23768)
## Why #23756 makes packaged Codex builds include and default to the bundled zsh fork. The important reason to put that fork's directory at the front of `PATH` is to keep executable-level escalation working after a command leaves the original shell and later re-enters zsh through `env`. The expected chain is: 1. The zsh fork runs the top-level shell command. 2. That command launches another program, such as `python3`, while inheriting the `EXEC_WRAPPER` environment and the escalation socket fd. 3. That program spawns a shell script whose shebang is `#!/usr/bin/env zsh` rather than `#!/bin/zsh`, and it does not close the escalation fd. 4. `/usr/bin/env` resolves `zsh` through `PATH`, so it must find the packaged zsh fork before the system zsh. 5. Commands inside that nested script are intercepted by the zsh fork and can still request escalation from Codex. If `PATH` resolves `zsh` to the system shell instead, the nested script loses zsh-fork exec interception. Commands that should request escalation can then run only in the original sandbox, or fail there, without Codex ever receiving the approval request. Shell snapshots make this slightly more subtle: a snapshot can restore an older `PATH` after the child shell starts. This PR treats the zsh fork `PATH` prepend as an explicit environment override so snapshot wrapping preserves it. ## What Changed - Added shared zsh-fork runtime helpers that prepend the configured zsh executable parent directory to `PATH` without duplicate entries. - Applied the zsh fork `PATH` prepend to both zsh-fork `shell_command` launches and unified-exec zsh-fork launches before sandbox command construction. - Kept the shell-command zsh-fork backend API narrow: it derives the configured zsh path from session services and rebuilds its sandbox environment from `req.env`, rather than accepting a second, competing environment map or a separately threaded bin dir. - Kept Unix-only zsh-fork `PATH` mutation out of Windows clippy-visible mutability. - Added coverage for duplicate `PATH` entries, for preserving the zsh fork prepend through shell snapshot wrapping, and for the nested `python3` -> `#!/usr/bin/env zsh` escalation flow. ## Testing - `just fmt` - `just fix -p codex-core` I left final test validation to CI after the latest review-comment cleanup. Before that cleanup, `just test -p codex-core zsh_fork` passed locally for the zsh-fork-focused tests.
Michael Bolin ·
2026-05-28 14:10:40 -07:00 -
[codex] Remove Bedrock OSS models from catalog (#24960)
Remove the GPT OSS 120B and 20B entries from the Amazon Bedrock static model catalog, as they are no longer supported.
Celia Chen ·
2026-05-28 14:10:26 -07:00 -
[codex] Handle PowerShell UTF-8 setup failures (#24949)
Fixes #12496. ## Why Windows sandboxed PowerShell commands can run under `ConstrainedLanguage` on some machines, especially enterprise-managed Windows environments. In that mode, our PowerShell command prelude could fail before every command because it directly assigned `[Console]::OutputEncoding` to UTF-8. The actual user command still ran, but Codex surfaced noisy `Cannot set property. Property setting is supported only on core types in this language mode.` output for every shell call. ## What Changed - Makes the PowerShell UTF-8 output encoding prelude best-effort by wrapping the assignment in `try { ... } catch {}`. - Keeps the existing UTF-8 behavior when PowerShell allows the assignment. - Adds focused tests for adding the prelude and avoiding duplicate prelude insertion. ## Validation - `cargo fmt -p codex-shell-command` - `cargo check -p codex-shell-command` - `git diff --check` - Verified a local `ConstrainedLanguage` PowerShell probe prints only the command output with no property-setting error. - Verified `codex exec` from a temporary `chcp 437` context reports `utf-8` / `65001` and preserves non-ASCII output (`café`, `漢字`).
iceweasel-oai ·
2026-05-28 13:58:20 -07:00 -
fix(tui): prevent repository-configured code execution in /diff (#24954)
## Why `/diff` is intended to display working-tree changes, but its Git invocations honored repository-selected executable helpers. A repository could configure diff/text conversion helpers, clean/process filters, `core.fsmonitor`, or `post-index-change` hooks that execute when a user runs `/diff`. Fixes [PSEC-4395](https://linear.app/openai/issue/PSEC-4395/codex-cli-diff-executes-repository-selected-diff-helpers). ## What Changed - Pass `--no-textconv` and `--no-ext-diff` for tracked and untracked diff generation. - Discover configured `filter.<driver>.clean` and `.process` entries, then neutralize the selected drivers through structured `GIT_CONFIG_KEY_*` / `GIT_CONFIG_VALUE_*` overrides, including driver names containing `=`. - Run all `/diff` Git probes with `core.fsmonitor=false` and a null `core.hooksPath`. - Use short submodule reporting while ignoring dirty submodule worktrees, since inspecting a checked-out submodule for dirtiness can execute filters from that child repository. This intentionally omits dirty-only submodule markers in order to preserve the non-executing security boundary. - Add real-Git marker tests covering filters, fsmonitor, hooks, and configured helpers inside checked-out submodules. ## How to Test 1. In a repository with ordinary tracked and untracked edits, run `/diff`. 2. Confirm the normal working-tree diff is shown for top-level files. 3. Run the targeted tests below; they configure executable marker helpers for repository filters, fsmonitor, hooks, and a checked-out submodule, then verify `/diff` does not invoke them. 4. Confirm a dirty-only submodule does not cause Codex to enter the submodule and execute its configured helper. Targeted tests: - `just test -p codex-tui get_git_diff_` Validation note: `just test -p codex-tui` runs the new coverage, but this worktree currently also has two unrelated failing guardian tests: `app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` and `app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`.
Felipe Coury ·
2026-05-28 16:53:59 -03:00 -
Add
codex app-server --stdioalias (#24940)## Summary - Add `--stdio` as a direct alias for `codex app-server --listen stdio://`. - Keep `--stdio` and `--listen` mutually exclusive. - Update the app-server README to document both forms.
Adam Perry @ OpenAI ·
2026-05-28 12:43:30 -07:00 -
Add feature-gated standalone image generation extension (#24723)
## Why Add a standalone image generation path that can be exercised independently of hosted Responses image generation, while retaining the hosted tool as fallback unless the extension is actually available to the model. ## What changed - Added the `codex-image-generation-extension` crate with standalone generate/edit execution, prior-image selection for edits, model-visible image output, and local generated-image persistence. - Installed the extension in app-server behind the disabled-by-default `imagegenext` feature and backend eligibility checks. - Updated core tool planning so eligible `image_gen.imagegen` exposure replaces hosted `image_generation`, while unavailable configurations retain hosted fallback. - Added coverage for extension behavior, edit history reuse, feature gating, auth eligibility, and hosted-tool replacement. - The extension is installed through app-server only in this PR; other execution paths retain hosted image generation because hosted replacement occurs only when the standalone executor is actually registered and model-visible. - The initial extension contract intentionally fixes the image model to `gpt-image-2` and uses automatic image parameters. - Native generated-image history/card parity and rollout persistence cleanup are intentionally deferred follow-up work. ## Validation - `just test -p codex-image-generation-extension` - `just test -p codex-features` - `just test -p codex-core hosted_tools_follow_provider_auth_model_and_config_gates` - `just test -p codex-app-server` - `just fix -p codex-image-generation-extension -p codex-features -p codex-core -p codex-app-server` - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` --------- Co-authored-by: jif-oai <jif@openai.com>
Won Park ·
2026-05-28 11:44:55 -07:00 -
Wire task completion into thread-idle lifecycle (#24928)
## Why #24744 introduced the thread idle lifecycle hook so idle continuation can be owned by lifecycle contributors instead of hard-coded goal runtime plumbing. Task completion still called `goal_runtime_apply(GoalRuntimeEvent::MaybeContinueIfIdle)` directly, so the post-turn idle transition remained goal-specific and did not notify generic thread lifecycle contributors. ## What Changed - Add `Session::emit_thread_idle_lifecycle_if_idle()` to gate idle emission on both no active turn and no queued trigger-turn mailbox work. - Call that helper when a task clears the active turn, replacing the direct `GoalRuntimeEvent::MaybeContinueIfIdle` path. - Cover the behavior with `codex-core` session tests for emitting after task completion and suppressing idle emission while trigger-turn mailbox work is pending. ## Verification - New tests in `core/src/session/tests.rs` exercise the idle lifecycle emission and trigger-turn mailbox guard.
jif-oai ·
2026-05-28 20:05:41 +02:00 -
Revert "Add app-server startup benchmark crate" (#24937)
Reverts openai/codex#24651, broke musl job https://github.com/openai/codex/actions/runs/26585495205/job/78330166927
Adam Perry @ OpenAI ·
2026-05-28 17:49:41 +00:00 -
TUI: Unified mentions tweaks + polish mentions rendering (#23363)
This change keeps unified @mentions behind the mentions_v2 gate, moves the flag to under-development, and polishes mention rendering/history behavior. It also adds a few small improvements to the mentions feature around mention rendering and history round-tripping for plugin/tool mentions in message edit scenarios. Plugin selections now insert `@` mentions with better casing, and saved history preserves the visible sigil so recalled messages look the same as what the user typed. - Preserves `@` sigils when encoding/decoding mention history for tool/plugin paths. - Improves plugin mention insertion so display names/casing are reflected more cleanly in the composer. - Update composer to render user-entered plugin mentions in the same color as the mentions menu. ALso applies to recalled/edited messages. - Left/right arrows no longer switch unified-mention search modes after an @mention has already been accepted (Ex: arrowing left through a composed message that contains @mentions). - Keeps bound mentions stable around punctuation, so accepted `@` mentions do not reopen the popup and punctuated `$` mentions still persist to cross-session history. **Steps to test** - Ensure mentions_v2 is enabled through configuration or `--enable mentions_v2` - Type `@` in the TUI composer and verify filesystem/plugin/skill results are displayed in the unified mentions menu. - Select a plugin mention from the `@` popup and confirm the inserted text is an `@...` mention with casing, then recall/edit the message and confirm it still renders as `@...`. - Mention a skill and verify that skills still insert as `$skill` mentions rather than `@` mentions. - Verify punctuated mentions such as `@plugin.` and `($skill)` keep their bound mention behavior across editing and history recall.
canvrno-oai ·
2026-05-28 10:30:15 -07:00 -
chore: add GPT-5.5 to the Amazon Bedrock catalog (#24701)
## Summary Amazon Bedrock should expose GPT-5.5 alongside GPT-5.4, and the Bedrock GPT entries should stay aligned with the canonical bundled OpenAI model metadata instead of carrying a separate hand-written copy that can drift over time. This change will be merged when the model is online. This change: - Adds the Bedrock Mantle model id for `openai.gpt-5.5`. - Builds the Bedrock GPT-5.5 and GPT-5.4 catalog entries from the bundled OpenAI model catalog, then overrides the Bedrock-facing slug, explicit priority, and Bedrock-specific context windows. - Hardcodes both `context_window` and `max_context_window` to `272000` for Bedrock GPT-5.5 and GPT-5.4. - Keeps `openai.gpt-5.5` as the default Bedrock model ahead of `openai.gpt-5.4` and the Bedrock OSS models.
Celia Chen ·
2026-05-28 10:29:06 -07:00 -
[codex] Support ui visibility meta for tools (#24700)
## Summary Adds support for the same ui.visibility metadata as resources [spec](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#resource-discovery)
Gabriel Peal ·
2026-05-28 10:24:03 -07:00 -
Fix extension turn item emitter test event ordering (#24936)
## Why PR #24813 added extension `TurnItemEmitter` coverage and introduced a test that records a conversation history item before asserting extension-emitted turn item events. `record_conversation_items()` also emits a `RawResponseItem` event to observers. The test was reading from the same event receiver and expected the next event to be `ItemStarted`, so the test failed reliably once the setup history item was present. ## What Changed Update `passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call` to consume and assert the expected setup `RawResponseItem` before checking the extension `ItemStarted`, `WebSearchBegin`, `ItemCompleted`, and `WebSearchEnd` events. This is test-only and does not change extension runtime behavior. ## Verification - `cargo nextest run --no-fail-fast -p codex-core tools::handlers::extension_tools::tests::passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call`
Michael Bolin ·
2026-05-28 09:59:34 -07:00 -
Reap stale multi-agent slots (#24903)
## Summary - Let `close_agent` clean up an agent that is still registered in `AgentRegistry` even when its underlying thread is already missing. - Preserve the explicit-close boundary: for known stale thread-spawn agents, mark the persisted spawn edge `Closed`, then treat `ThreadNotFound` / `InternalAgentDied` as a successful close so the registry slot can be released. - Add a regression for MultiAgentV2 task-name targets where `close_agent("worker")` succeeds after the worker thread has already disappeared. ## Motivation A worker can disappear from `ThreadManager` while its metadata still exists in the root `AgentRegistry`. Before this change, the close tool failed while trying to subscribe to the missing thread status, so it never reached the cleanup path that releases the registered agent slot. With `agents.max_threads = 1`, an explicit close of that stale task-name agent could fail and leave the session unable to spawn a replacement. ## Scope This PR intentionally does not add automatic stale-agent reaping to `spawn_agent`, `resume_agent`, or `list_agents`. A thread being missing from `ThreadManager` is not the same as an explicit close: persisted open spawn edges are still the durable source of truth for resume and task-name ownership until `close_agent` is called. ## Validation - `just test -p codex-core -E 'test(multi_agent_v2_close_agent_reaps_stale_task_name_target) | test(resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown)'` - `just fix -p codex-core`jif-oai ·
2026-05-28 18:48:43 +02:00 -
Expose MCP server info as part of server status (#24698)
# Summary Expose MCP server info via App Server (when available) so apps can render a richer MCP experience
Gabriel Peal ·
2026-05-28 09:38:34 -07:00 -
feat(app-server): include turns page on thread resume (#23534)
## Summary The client currently calls `thread/resume` to establish live updates and immediately follows it with `thread/turns/list` to hydrate recent turns. This lets `thread/resume` return that page directly, eliminating a round trip and the ordering/deduplication gap between the two calls. Experimental clients opt in with `initialTurnsPage: { limit, sortDirection, itemsView }`. The response returns `initialTurnsPage` as a `TurnsPage`, including cursors for paging further back in history. Keeping the controls in a nested opt-in object provides the useful `thread/turns/list` knobs without spreading page-specific parameters across `thread/resume`. ## Verification - `just fmt` - `just write-app-server-schema --experimental` - `just write-app-server-schema` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-app-server thread_resume_initial_turns_page_matches_requested_turns_list_page --tests` - `cargo test -p codex-app-server thread_resume_rejoins_running_thread_even_with_override_mismatch --tests` - `just fix -p codex-app-server-protocol -p codex-app-server`Brent Traut ·
2026-05-28 09:18:13 -07:00 -
extension-api: add TurnItemEmitter to tool calls (#24813)
## Why Extension-contributed tools need to emit visible turn items through Codex's normal event and persistence pipeline. ## What - Add `TurnItemEmitter` to extension `ToolCall`s and route the core implementation through `Session::emit_turn_item_*`. - Hold weak session and turn references so retained tool calls cannot keep host state alive. - Provide a no-op emitter for extension test callers. ## Test Plan - `just test -p codex-core -E 'test(passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call)'` --------- Co-authored-by: jif-oai <jif@openai.com>
sayan-oai ·
2026-05-28 09:13:43 -07:00 -
Gate goal tools by thread eligibility (#24925)
## Why Goal tools create and update goal state for a persistent thread. The extension was only checking whether goals were enabled before advertising those tools, which meant they could be surfaced in contexts that should not receive thread goal controls: ephemeral threads without persistent thread state and review subagents. Those sessions can still run the goal extension lifecycle, but the thread tools should only be visible when the current thread can safely use them. ## What changed - Adds a `GoalRuntimeConfig` that separates goal enablement from whether goal tools are available for the current thread. - Computes tool eligibility on thread start from `persistent_thread_state_available` and `SessionSource`, hiding tools for review subagents. - Uses `GoalRuntimeHandle::tools_visible()` when contributing thread tools so enabled runtime state does not automatically imply tool exposure. - Adds backend coverage for hiding goal tools on ephemeral threads and review subagents. ## Testing - Added `goal_tools_hidden_for_ephemeral_threads`. - Added `goal_tools_hidden_for_review_subagents`.
jif-oai ·
2026-05-28 17:47:17 +02:00 -
Add app-server startup benchmark crate (#24651)
## Summary - Add a new `app-server-start-bench` crate to measure app-server startup performance - Wire the benchmark into the workspace and Bazel build so it can be run consistently - Update lockfiles and repo automation to account for the new package
Adam Perry @ OpenAI ·
2026-05-28 08:46:30 -07:00 -
[codex] Update OpenAI Docs skill (#24914)
## Summary - update the bundled `openai-docs` system skill to match the latest `openai-docs-plus` content from `skills-internal` - add the cached Codex manual fetch helper and expand the skill routing for Codex self-knowledge - keep the stable local skill identity and labels as `openai-docs` ## Why The built-in OpenAI Docs skill needed to reflect the current upstream guidance from `skills-internal` while preserving the local system-skill name used by Codex. ## Impact Codex now ships the newer OpenAI Docs skill behavior for Codex self-knowledge and manual-first documentation lookups. ## Validation - `just test -p codex-skills` - exact directory diff against transformed `skills-internal` `origin/main` was clean
Vaibhav Srivastav ·
2026-05-28 15:11:11 +00:00 -
pakrym-oai ·
2026-05-28 07:23:08 -07:00 -
Add turn error lifecycle contributor (#24916)
Summary - Add TurnErrorInput and TurnLifecycleContributor::on_turn_error to the extension API. - Emit the turn-error lifecycle from core turn error paths, including usage limit failures. - Add direct lifecycle coverage for the emitted error facts and stores. Tests - just fmt - git diff --check - Not run: full tests or clippy (per instructions)
jif-oai ·
2026-05-28 16:13:54 +02:00 -
Add thread start contributor facts (#24915)
Summary: add session source and persistent-state availability to ThreadStartInput; populate them from session init; update existing goal test harness constructors. Tests: just fmt; git diff --check. No full tests or clippy run per request.
jif-oai ·
2026-05-28 16:10:55 +02:00 -
[codex-cli] Refresh near-expiry ChatGPT access tokens before requests (#23546)
## Summary - refresh managed ChatGPT auth during auth resolution when its access token is inside ChatGPT web's five-minute near-expiry window - cover refresh-window decisions while preserving the existing expired-token refresh path ## Why Codex already resolves managed ChatGPT auth before outbound requests and refreshes expired access tokens there. This change adjusts the existing predicate to refresh a still-valid access token once it is within the same five-minute refresh window used by ChatGPT web, avoiding a request with a token about to expire. A cross-process serialization follow-up was explored in #24663 and closed for now; we do not currently suspect cross-process refresh races are a root cause of the refresh errors under investigation. External-token, API-key, and Agent Identity auth modes remain unchanged. ## Validation - `bazel test //codex-rs/login:login-all-test` - `just fmt` runs Rust formatting successfully, then its Python SDK Ruff step cannot install `openai-codex-cli-bin==0.131.0a4` on this Linux environment because no compatible wheel is published.
cooper-oai ·
2026-05-28 05:40:17 -07:00 -
Add Guardian review metrics (#24897)
## Why Guardian reviews already emit analytics events, but we do not expose aggregate OpenTelemetry metrics for review volume, latency, token usage, or terminal outcomes. That makes it harder to monitor Guardian behavior during rollouts and to compare review outcomes by source, action type, session kind, model, and failure mode. ## What Changed - Added Guardian review metric names for count, total duration, time to first token, and token usage in `codex-rs/otel`. - Added `core/src/guardian/metrics.rs` to convert `GuardianReviewAnalyticsResult` into sanitized metric tags covering decision, terminal status, failure reason, approval request source, reviewed action, session kind, risk/outcome, model, reasoning effort, and context/truncation state. - Emitted the new metrics from `track_guardian_review` for each terminal Guardian review result. ## Testing - Added `guardian_review_metrics_record_counts_durations_and_token_usage`, which verifies the emitted count, duration, TTFT, token usage histograms, and tag set through the in-memory metrics exporter.
jif-oai ·
2026-05-28 14:07:25 +02:00 -
Fix memories namespace for Responses API tools (#24898)
## Why Dedicated memories tools are exposed through a Responses API namespace tool. The namespace itself has to be a valid tool identifier, so `memories/` can fail validation before the model ever gets a chance to call the memory tools. ## What changed - Changed `MEMORY_TOOLS_NAMESPACE` from `memories/` to `memories`. - Added `memory_tool_namespace_matches_responses_api_identifier` so the namespace stays non-empty and limited to Responses-safe identifier characters. ## Verification - Added unit coverage for the namespace identifier shape in `codex-rs/ext/memories/src/tests.rs`.
jif-oai ·
2026-05-28 14:06:21 +02:00 -
[codex] Fix Guardian argument comment lint (#24902)
## Summary - Add the required `/*parent_thread_id*/` argument comment at the Guardian review session test callsite flagged by CI. ## Validation - `just fmt` - Not run: clippy/tests, per request; CI will cover them.
jif-oai ·
2026-05-28 13:38:48 +02:00 -
Thread Guardian cache key through session (#24895)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/session/session.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:40 +02:00 -
Assert Guardian prompt cache key reuse (#24894)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/tests.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:36 +02:00 -
Add Guardian review prompt cache key (#24893)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/review_session.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:25 +02:00 -
Export Guardian prompt cache key helper (#24892)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/guardian/mod.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:17 +02:00 -
Stabilize Guardian client cache key handling (#24891)
Split from the Guardian prompt cache key change. This PR only updates codex-rs/core/src/client.rs. Validation was not run per request; this branch is expected to rely on the companion split PRs.
jif-oai ·
2026-05-28 12:36:01 +02:00 -
Move memories root setup out of core config (#24758)
## Why Config loading should not create or write-authorize the memories root just because memory support exists. Memory startup is the code path that actually materializes that tree. ## What - Stop creating the memories root during Config load and remove it from legacy workspace-write projections. - Grant the memories root read access only when the memories feature and use_memories are enabled. - Create the memories root inside memories startup before seeding extension instructions. - Update config and startup tests around the ownership boundary. ## Tests - just fmt - just fix -p codex-core - just fix -p codex-memories-write - just test -p codex-core memory_tool_makes_memories_root_readable_without_creating_or_widening_writes workspace_write_includes_configured_writable_root_once_without_memories_root permission_profile_override_keeps_memories_root_out_of_legacy_projection permissions_profiles_allow_direct_write_roots_outside_workspace_root default_permissions_profile_populates_runtime_sandbox_policy - just test -p codex-memories-write memories_startup_creates_memory_root Note: a broader just test -p codex-core run is not clean in this sandbox; it hit missing test_stdio_server plus seatbelt, realtime, and environment-sensitive failures. The changed config tests above pass.
jif-oai ·
2026-05-28 11:51:24 +02:00 -
Treat refresh_token_reused 400s as relogin-required (#24830)
## Summary - classify known refresh-token terminal failures from `/oauth/token` as permanent even when the backend returns `400` - preserve the existing relogin-required message for `refresh_token_reused` instead of retrying and collapsing into a generic cloud requirements error - add regression coverage for `400 refresh_token_reused` ## Testing - `just fmt` - `cargo test -p codex-login`
alexsong-oai ·
2026-05-27 18:37:02 -07:00 -
[codex] Remove redundant SQLite dynamic tool storage (#24819)
## Why Dynamic tools are defined at thread start and already stored in rollout `SessionMeta`, which restores resumed and forked sessions. Persisting the same tools through SQLite creates a second runtime persistence path that is unnecessary prework for the explicit namespace refactor. ## What changed - Restore missing thread-start dynamic tools directly from rollout history, including when SQLite is enabled. - Remove SQLite dynamic-tool reads, writes, backfill, and thread metadata patch plumbing. - Add SQLite-enabled resume integration coverage that verifies a rollout-defined dynamic tool is still sent after resume. ## Compatibility The existing `thread_dynamic_tools` table is intentionally not dropped even though it's now unused. Older Codex binaries are allowed to open databases migrated by newer binaries and still reference this table; dropping it would break that mixed-version path. See [here](https://github.com/openai/codex/blob/main/codex-rs/state/src/migrations.rs#L10-L11). ## Verification - `just test -p codex-state -p codex-rollout -p codex-thread-store` - `just test -p codex-core --test all resume_restores_dynamic_tools_from_rollout_with_sqlite_enabled`
sayan-oai ·
2026-05-27 17:57:32 -07:00 -
[codex] Fix hyperlink-aware key-value table rendering (#24825)
## Why The key/value markdown table renderer added in #24636 still operates on `Line` values, while table cells and rendered table output now carry `HyperlinkLine`. That mismatch breaks `codex-tui` compilation on `main` and would risk losing semantic web-link annotations if corrected by flattening the values. ## What changed - Make key/value record rendering wrap and emit `HyperlinkLine` values consistently with the existing grid renderer. - Remap wrapped hyperlink ranges and shift them when value content is prefixed by record-mode indentation or labels. - Add focused coverage verifying key/value fallback output preserves web-link destinations. ## Verification - `just test -p codex-tui -E 'test(key_value_table_keeps_web_annotations) | test(/table_renders_(key_value_records_when_compact_fragmentation_is_systemic_snapshot|stacked_key_value_records_when_path_column_becomes_too_narrow_snapshot|records_when_multiple_prose_columns_are_starved_snapshot)/)'`
sayan-oai ·
2026-05-27 15:11:29 -07:00 -
Update rmcp to 1.7.0 (#24763)
WIll make it easier to uprev when the new draft spec is supported. Also updates reqwest where needed for compatibility but doesn't update it everywhere since this is already a large diff. The new version of rmcp handles certain kinds of authentication failures differently, this patch includes support for identifying the failing scope in a WWW-Authenticate header.
Adam Perry @ OpenAI ·
2026-05-27 14:52:06 -07:00 -
Allow API-key auth for remote exec-server registration (#24666)
## Overview Allow remote `codex exec-server` registration to use existing API-key auth while restricting where those credentials can be sent. - Accept `CodexAuth::ApiKey` for the normal `--remote` registration path. - Restrict API-key remote registration to HTTPS `openai.com` and `openai.org` hosts and subdomains, with explicit HTTP loopback support for local development. - Disable registry registration redirects so credentials cannot be forwarded to an unvalidated destination. - Retain `--use-agent-identity-auth` as the explicit Agent Identity path. - Document remote registration using `CODEX_API_KEY`. ## Big picture Callers can now provide an API key directly to `exec-server` registration without first establishing ChatGPT login state: ```sh CODEX_API_KEY="$OPENAI_API_KEY" \ codex exec-server \ --remote "https://<host>.openai.org/api" \ --environment-id "$ENVIRONMENT_ID" ``` ## Validation - `cargo fmt --all` (`just fmt` is not installed on this host) - `cargo test -p codex-cli -p codex-exec-server`
Steve Coffey ·
2026-05-27 21:17:38 +00:00 -
feat(tui): render cramped markdown tables as key-value records [2 of 2] (#24636)
## Stack - **Base: #24489 [1 of 2]** - render markdown tables in app style. - **Current: #24636 [2 of 2]** - render cramped markdown tables as key/value records. Review this PR against `fcoury/app-style-markdown-tables`; it contains only the fallback behavior for cramped tables. ## Why The row-separated markdown table rendering in #24489 remains readable while columns have usable room. Once long links or multiple prose-heavy columns are compressed into narrow allocations, however, the grid can turn words and paths into tall vertical strips that are difficult to scan. In those cases the content matters more than preserving the grid shape. ## What Changed <table> <tr><td> <p align="center"><b> Normal </b></p> <img width="1722" height="619" alt="CleanShot 2026-05-27 at 14 32 57" src="https://github.com/user-attachments/assets/d04f5fbd-6064-4acd-91bd-072d19b983df" /> </td></tr> <tr><td> <p align="center"><b> Narrow </b></p> <img width="863" height="1013" alt="CleanShot 2026-05-27 at 14 33 12" src="https://github.com/user-attachments/assets/6a7d2968-0a68-48fd-ab5d-209b3dbaf03e" /> </td></tr> <tr><td> <p align="center"><b> Very narrow </b></p> <img width="435" height="746" alt="CleanShot 2026-05-27 at 14 33 47" src="https://github.com/user-attachments/assets/f6a59e30-b1d2-4063-9c05-43933abc77d6" /> </td></tr> </table> - Detect tables whose grid allocation causes systemic token fragmentation or starves multiple prose-heavy columns. - Render those tables as repeated key/value records instead of retaining an unreadable grid. - Use aligned label/value records when there is useful horizontal room, and switch to a stacked narrow-record layout where each label is followed by a full-width value when width is especially constrained. - Preserve the themed label color, rich inline formatting, links, and the existing grid presentation for tables that remain readable. - Add snapshot coverage for path-heavy narrow tables, prose-heavy issue tables, systemic compact fragmentation, and a control case that should continue to render as a grid. ## How to Test 1. Start Codex from this branch and render a normal multi-column markdown table at a comfortable terminal width. Confirm it still appears as the styled row-separated grid from #24489. 2. Render a table containing a long linked record identifier or file-like value, then narrow the terminal until the grid would split the value into vertical fragments. Confirm it switches to key/value records, with labels above values at very narrow widths. 3. Render a table with multiple prose-heavy columns, such as an issue summary table with `Issue`, `Activity`, `Complexity`, and `Why start`. Confirm a cramped width switches to records rather than wrapping several columns into hard-to-read strips. 4. Render a compact table where only one value wraps mildly. Confirm it stays in grid form rather than switching prematurely. ## Validation - Ran `just test -p codex-tui` while developing the fallback and reviewed/accepted the intended new markdown-render snapshots. The command still reports two unrelated existing guardian feature-flag test failures outside this diff. - Ran `just fix -p codex-tui` and `just fmt` after the Rust changes were complete. - `just argument-comment-lint` cannot reach source linting locally because Bazel fails while resolving LLVM sanitizer headers; touched positional literal callsites were inspected manually and annotated where needed.
Felipe Coury ·
2026-05-27 20:27:55 +00:00 -
feat(tui): add OSC 8 web links to rich content (#24472)
## Why Wrapped URLs in rich TUI output, especially URLs rendered inside Markdown tables, are split across terminal rows. In terminals that support OSC 8 hyperlinks, treating each visible fragment as part of the complete destination enables reliable open-link and copy-link actions even after table layout wraps the URL. This addresses the semantic-link portion of #12200 and the behavior described in https://github.com/openai/codex/issues/12200#issuecomment-4535452980. It does not change ordinary drag-selection across bordered table rows. ## What Changed - Added shared TUI OSC 8 support that validates `http://` and `https://` destinations, sanitizes terminal payloads, and applies metadata separately from visible line width/layout. - Added semantic web-link annotations to assistant and proposed-plan Markdown, including explicit web links and bare web URLs in prose and table cells while excluding code and non-web Markdown destinations. - Preserved complete URL targets through table wrapping, narrow pipe fallback, streaming, transcript overlay rendering, history insertion, and resize replay. - Routed intentional Codex-owned links in notices, status/setup/app-link, feedback, onboarding, MCP/plugin help, memories, and update surfaces through the shared hyperlink handling. ## How to Test 1. Run Codex in a terminal with OSC 8 link support, such as Ghostty, and request an assistant response containing a Markdown table whose last column contains a long `https://` URL. 2. Make the terminal narrow enough for the URL to wrap across multiple bordered table rows. 3. Use the terminal's open-link or copy-link action on more than one wrapped URL fragment and confirm each fragment resolves to the complete original URL. 4. Resize the terminal after the table is rendered and repeat the link action to confirm the destination survives scrollback replay. 5. Open the transcript overlay while rich output is present and confirm web links remain interactive there. 6. As a regression check, render inline/fenced code containing URL text and a Markdown link such as `[https://example.com](mailto:support@example.com)`; confirm these do not acquire a web OSC 8 destination. Targeted automated coverage exercised Markdown links and exclusions, wrapped and pipe-fallback tables, streaming/transcript overlay propagation, status-link truncation, and rendered word-wrapping cell alignment. `just test -p codex-tui` was also run; it passed the hyperlink coverage and reproduced two unrelated existing guardian feature-flag test failures.
Felipe Coury ·
2026-05-27 20:14:55 +00:00 -
fix(linux-sandbox): preserve shell cleanup on interruption (#22729)
## Why Interrupted `shell_command` calls can race with the outer tool-dispatch cancellation path. When that happens, the runtime future may be dropped before the spawned process gets a chance to run `SIGTERM` cleanup. For bwrapd-backed Linux sandbox commands, that can leave synthetic protected-path mount bookkeeping such as `.git/.codex` registrations under `/tmp` behind after a TUI interruption. The relevant cancellation points are the outer dispatch race in [`core/src/tools/parallel.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/tools/parallel.rs#L91-L132) and the process shutdown logic in [`core/src/exec.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/exec.rs#L1367-L1393). ## What changed - Keep `shell_command` dispatch alive long enough for the runtime to finish cancellation cleanup instead of immediately returning the synthetic aborted response. - Fold shell-turn cancellation into the existing `ExecExpiration` path in [`core/src/tools/runtimes/shell.rs`](https://github.com/openai/codex/blob/bd184ba84703cc924921ed883f0cf17d3dba60ff/codex-rs/core/src/tools/runtimes/shell.rs#L267-L274), so cancellation and timeout behavior stay centralized. - On cancellation, send `SIGTERM` first, wait briefly for cleanup to run, then hard-kill any remaining descendants in the original process group. - Treat `ESRCH` as an already-gone process-group cleanup case in `codex-utils-pty`, which keeps best-effort teardown from surfacing a stale-process race as an error. ## Verification - `cargo test -p codex-core cancellation` - Added regression coverage for: - `shell_tool_cancellation_waits_for_runtime_cleanup` - `process_exec_tool_call_cancellation_allows_sigterm_cleanup`
viyatb-oai ·
2026-05-27 12:59:11 -07:00