guix_mirror_bot pushed a commit to branch master
in repository guix.
commit 29b91c4914549cf484c117a86639bc6b6ae98743
Author: Sergio Pastor Pérez <[email protected]>
AuthorDate: Tue Sep 1 11:28:42 2026 +0200
gnu: Remove codex.
* gnu/packages/codex.scm (codex): Delete variable.
* gnu/packages/patches/codex-0.144.1-disable-code-mode.patch: Delete file.
* gnu/packages/patches/codex-0.144.1-remove-libwebrtc.patch: Likewise.
* gnu/packages/patches/codex-0.144.1-remove-patch-sections.patch: Likewise.
*
gnu/packages/patches/codex-0.144.1-test-disable-network-model-refresh.patch:
Likewise.
*
gnu/packages/patches/codex-0.144.1-test-selected-capability-readiness.patch:
Likewise.
* gnu/packages/patches/codex-0.144.1-test-shebangs.patch: Likewise.
* gnu/packages/patches/codex-0.144.1-test-timeout.patch: Likewise.
* gnu/local.mk (dist_patch_DATA): Remove deleted files.
Signed-off-by: Liliana Marie Prikler <[email protected]>
Fixes: guix/guix#10943
Merges: guix/guix#10963
---
gnu/local.mk | 7 -
gnu/packages/codex.scm | 989 ---------------------
.../patches/codex-0.144.1-disable-code-mode.patch | 302 -------
.../patches/codex-0.144.1-remove-libwebrtc.patch | 16 -
.../codex-0.144.1-remove-patch-sections.patch | 29 -
....144.1-test-disable-network-model-refresh.patch | 179 ----
....144.1-test-selected-capability-readiness.patch | 33 -
.../patches/codex-0.144.1-test-shebangs.patch | 45 -
.../patches/codex-0.144.1-test-timeout.patch | 20 -
9 files changed, 1620 deletions(-)
diff --git a/gnu/local.mk b/gnu/local.mk
index f22bdd1927c..9cafec0824c 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1142,13 +1142,6 @@ dist_patch_DATA =
\
%D%/packages/patches/clog-fix-shared-build.patch \
%D%/packages/patches/clucene-gcc-14.patch \
%D%/packages/patches/clucene-pkgconfig.patch \
- %D%/packages/patches/codex-0.144.1-disable-code-mode.patch \
- %D%/packages/patches/codex-0.144.1-remove-libwebrtc.patch \
- %D%/packages/patches/codex-0.144.1-remove-patch-sections.patch \
- %D%/packages/patches/codex-0.144.1-test-disable-network-model-refresh.patch
\
- %D%/packages/patches/codex-0.144.1-test-selected-capability-readiness.patch
\
- %D%/packages/patches/codex-0.144.1-test-shebangs.patch \
- %D%/packages/patches/codex-0.144.1-test-timeout.patch \
%D%/packages/patches/codex-acp-0.11.1-disable-code-mode.patch \
%D%/packages/patches/codex-acp-0.11.1-remove-patch-sections.patch \
%D%/packages/patches/cogl-fix-double-free.patch \
diff --git a/gnu/packages/codex.scm b/gnu/packages/codex.scm
index 7cd2a7688fa..ea7deb24a70 100644
--- a/gnu/packages/codex.scm
+++ b/gnu/packages/codex.scm
@@ -58,995 +58,6 @@
#:use-module (gnu packages version-control)
#:use-module (gnu packages virtualization))
-(define-public codex
- (package
- (name "codex")
- (version "0.144.1")
- (source
- (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://github.com/openai/codex")
- (commit "44918ea10c0f99151c6710411b4322c2f5c96bea")))
- (file-name (git-file-name name version))
- (sha256
- (base32 "0icwnvss0zswsp0vz2cffzr4xq46zfv634cl9phn40kjhsl2ny18"))
- (modules '((guix build utils)))
- (snippet '(begin
- ;; Bundled bubblewrap source tree; includes a
- ;; compiled BPF blob (demos/flatpak.bpf).
- (delete-file-recursively "codex-rs/vendor/bubblewrap")))
- (patches (search-patches
- "codex-0.144.1-disable-code-mode.patch"
- "codex-0.144.1-remove-patch-sections.patch"
- "codex-0.144.1-remove-libwebrtc.patch"
- "codex-0.144.1-test-disable-network-model-refresh.patch"
- "codex-0.144.1-test-selected-capability-readiness.patch"
- "codex-0.144.1-test-shebangs.patch"
- "codex-0.144.1-test-timeout.patch"))))
- (build-system cargo-build-system)
- (arguments
- (list
- #:rust rust-1.94
- #:install-source? #f
- ;; exec-server is library-only in this release (no [[bin]] in
- ;; exec-server/Cargo.toml); cargo install --path exec-server fails
- ;; with "no packages found with binaries or examples". Drop it
- ;; from the install paths -- the library is consumed via the
- ;; workspace by other binaries here, not installed standalone.
- #:cargo-install-paths '(list "cli" "exec"
- "linux-sandbox" "mcp-server"
- "app-server" "tui")
- ;; schema_fixtures_match_generated (upstream fixture is stale:
- ;; FileChange::Update in codex-protocol gained old_content,
- ;; new_content, move_path fields but the committed JSON schema
- ;; fixture was not regenerated).
- #:cargo-test-flags '(list "--workspace"
- "--exclude" "codex-app-server-protocol"
- "--exclude" "codex-code-mode"
- "--exclude" "codex-code-mode-host"
- ;;; BEGIN rustdoc absent from rust-1.94
- ;; rust-1.94 installs rustc and cargo but
- ;; not rustdoc. Select the ordinary test
- ;; targets explicitly, excluding doctests.
- "--lib" "--bins" "--tests"
- ;;; END rustdoc absent from rust-1.94
- "--"
- ;;; BEGIN Landlock returns NotEnforced
- ;;; in the build container; the sandbox
- ;;; binary panics instead of cleanly
- ;;; denying filesystem access.
- ;; Sandbox denial and escalation tests.
- "--skip"
"sandbox_denied_shell_returns_original_output"
- ;; Sandbox denial and escalation tests.
- "--skip"
"shell_escalated_permissions_rejected_then_ok"
- ;; Sandbox denial and escalation tests.
- "--skip" "unified_exec_runs_under_sandbox"
- ;; codex-exec:
spawn_command_under_linux_sandbox
- ;; panics with LandlockRestrict (exit 101).
- "--skip" "python_getpwuid_works_under_sandbox"
- ;; Same as above.
- "--skip"
"python_multiprocessing_lock_works_under_sandbox"
- ;; Same as above.
- "--skip"
"sandbox_distinguishes_command_and_policy_cwds"
- ;; linux-sandbox: process_exec_tool_call
- ;; invokes Landlock; same panic.
- "--skip" "test_writable_root"
- ;; Same as above.
- "--skip" "test_timeout"
- ;; Same as above.
- "--skip" "test_root_read"
- ;; Same as above.
- "--skip" "test_dev_null_write"
- ;; Same as above.
- "--skip" "test_no_new_privs_is_enabled"
- ;; One scenario runs through Landlock
- ;; which panics; cargo --skip cannot
- ;; target individual scenarios.
- "--skip" "approval_matrix_covers_all_modes"
- ;; Landlock panic triggers escalation-retry
- ;; which interferes with the approval cache.
- "--skip"
"approving_apply_patch_for_session_skips_future_prompts_for_same_file"
- ;; These tests expect to interrupt a
- ;; long-running 'sleep 60' and receive
- ;; TurnAborted. What happens:
- ;;
- ;; 1. ReadOnly wraps the command with
- ;; codex-linux-sandbox (Landlock-based).
- ;; 2. Landlock is unavailable, so the
- ;; sandbox binary exits instantly.
- ;; 3. Orchestrator gets SandboxErr::Denied.
- ;; wants_no_sandbox_approval(OnRequest)
- ;; returns false, so no escalation --
- ;; denial returned directly.
- ;; 4. ToolEmitter::finish sends the error
- ;; to the mock model.
- ;; 5. Second mock SSE response fires,
- ;; turn finishes with TurnComplete.
- ;; 6. Op::Interrupt arrives 100 ms later,
- ;; but the turn is already done --
- ;; TurnAborted is never emitted,
- ;; test times out.
- ;;
- ;; The similar interrupt_long_running_tool_
- ;; emits_turn_aborted passes because it
- ;; sends the interrupt with no delay and
- ;; has only one mock response (so the turn
- ;; cannot complete first).
- "--skip"
"interrupt_persists_turn_aborted_marker_in_next_request"
- ;; Same causal chain as above.
- "--skip"
"interrupt_tool_records_history_entries"
- ;; WorkspaceWrite sandbox policy wraps
- ;; commands with codex-linux-sandbox;
- ;; Landlock panics, command never runs,
- ;; exit_code is None instead of Some(0).
- "--skip"
"request_permissions_grants_apply_to_later_exec_command_calls"
- ;; Same root cause.
- "--skip"
"request_permissions_grants_apply_to_later_shell_command_calls"
- ;; Same root cause.
- "--skip"
"partial_request_permissions_grants_do_not_preapprove_new_permissions"
- ;;; END Landlock
- ;;; BEGIN mcp_process.rs initialize
- ;;; assertion expects "version":"0.0.0"
- ;;; but the server returns "0.120.0".
- "--skip"
"test_codex_tool_passes_base_instructions"
- "--skip"
"test_shell_command_approval_triggers_elicitation"
- "--skip"
"test_patch_approval_triggers_elicitation"
- ;;; END version mismatch
- ;;; BEGIN Test isolation bug:
- ;;; unique_temp_dir() in
- ;;; state/src/runtime.rs names dirs
- ;;; using nanosecond timestamps, so
- ;;; parallel tests can collide. The
- ;;; SQLite migration runs CREATE TABLE
- ;;; threads (without IF NOT EXISTS),
- ;;; so the second init panics with
- ;;; "table threads already exists".
- "--skip" "init_removes_legacy_state_db_files"
- "--skip" "upsert_and_get_thread_memory"
- "--skip"
"get_last_n_thread_memories_for_cwd_matches_exactly"
- "--skip"
"upsert_thread_memory_errors_for_unknown_thread"
- "--skip"
"get_last_n_thread_memories_for_cwd_zero_returns_empty"
- "--skip"
"get_last_n_thread_memories_for_cwd_does_not_prefix_match"
- "--skip"
"deleting_thread_cascades_thread_memory"
- ;;; END SQLite test isolation
- ;;; BEGIN unchanged filesystem mtime
- ;; This test overwrites an imported
- ;; session immediately and expects
- ;; detection to hash it again. When
- ;; both writes receive the same mtime,
- ;; the mtime fast path treats the source
- ;; as unchanged and returns no session.
- "--skip"
"redetects_sessions_when_source_contents_change_after_import"
- ;;; END unchanged filesystem mtime
- ;;; BEGIN bare 'sh' after env_clear().
- ;; These tests spawn 'sh' after
- ;; env_clear() with an empty env map;
- ;; glibc execvp uses confstr(_CS_PATH)
- ;; ("/bin:/usr/bin") when PATH is
- ;; unset, but /bin/sh does not exist
- ;; in the build container.
- "--skip"
"cancellation_expiration_keeps_process_alive_until_terminated"
- "--skip"
"timeout_or_cancellation_reports_cancellation_without_timeout_exit_code"
- ;;; END bare 'sh' after env_clear()
- ;;; BEGIN Guile 3.0.9 system* inherits ignored
SIGINT
- ;; Guile 3.0.9's system* temporarily sets
- ;; SIGINT to SIG_IGN while it waits for the
- ;; command ("Make sure the child can't kill
- ;; us"). The test command inherits that
- ;; disposition through cargo, and Codex's
- ;; pipe backend does not reset it before
- ;; exec. Its shell SIGINT trap cannot run.
- "--skip"
"exec_process_signal_interrupts_process"
- ;;; END Guile 3.0.9 system* inherits ignored
SIGINT
- ;; Proxy baseline_policy returns 403
- ;; "not_allowed_local" for example.com;
- ;; test expects 200.
- "--skip"
"managed_network_proxy_decider_survives_full_access_start"
- ;;; BEGIN bash_snapshot_script() uses
- ;;; "compgen -e" to list exports but
- ;;; bash-minimal lacks programmable
- ;;; completion; export section is empty.
- ;; stdout.contains("VALID_NAME") fails.
- "--skip"
"bash_snapshot_filters_invalid_exports"
- ;; stdout.contains("MULTILINE_CERT") fails.
- "--skip"
"bash_snapshot_preserves_multiline_exports"
- ;; snapshot.contains("PATH") fails.
- "--skip"
"linux_bash_snapshot_includes_sections"
- ;;; END compgen
- ;; substitute* patches PAGER to store
- ;; path of cat; test expects bare "cat".
- "--skip" "unified_exec_env_injects_defaults"
- ;;; BEGIN V8 disabled (codex-code-mode
- ;;; default-features = false).
- ;; codex-core: missing process-host fallback
- ;; executes JavaScript in the V8 session.
- "--skip"
"missing_process_host_falls_back_to_in_process_session"
- ;; codex-core: wait tracing terminates a cell
- ;; through the code-mode runtime.
- "--skip"
"missing_code_mode_wait_traces_only_the_wait_tool_call"
- "--skip" "suite::code_mode::"
- "--skip" "suite::code_mode_elicitation::"
- "--skip"
"suite::v2::imagegen_extension::standalone_image_generation_is_callable_from_code_mode_only"
- ;;; END V8 disabled
- ;;; BEGIN same compgen root cause:
- ;;; assert_posix_snapshot_sections
- ;;; asserts snapshot.contains("PATH").
- ;;; END compgen / shell snapshot
- ;;; BEGIN inaccessible snapshot under sh
- ;;; bash-minimal lacks "compgen -e", so the
- ;;; generated snapshot has no PATH section
- ;;; and these tests fail their snapshot
- ;;; assertions. They also expose a separate
- ;;; restricted-bwrap failure.
- "--skip"
"linux_shell_command_uses_shell_snapshot"
- "--skip"
"linux_unified_exec_uses_shell_snapshot"
- "--skip"
"shell_command_snapshot_still_intercepts_apply_patch"
- ;;; END inaccessible snapshot under sh
- ;;; BEGIN These sandbox tests set
- ;;; exclude_slash_tmp: true which makes
- ;;; bwrap exclude /tmp from its mount
- ;;; namespace. Since Guix builds under
- ;;; /tmp, the codex-linux-sandbox binary
- ;;; becomes invisible to bwrap even though
- ;;; the test adds the helper dir as a
- ;;; filesystem carve-out -- the parent /tmp
- ;;; bind-mount is absent so the carve-out
- ;;; has nothing to carve out of.
- "--skip"
"sandbox_reenables_writable_subpaths_under_unreadable_parents"
- "--skip"
"managed_proxy_mode_routes_through_bridge_and_blocks_direct_egress"
- ;;; END exclude_slash_tmp
- ;; Expects 3 TerminalInteraction events
- ;; across timed poll windows; under CPU
- ;; contention events merge into 2.
- "--skip"
"unified_exec_terminal_interaction_captures_delayed_output"
- ;;; BEGIN assert_parallel_duration
- ;;; requires < 1600 ms for parallel ops.
- ;; Two 300 ms test_sync_tool calls.
- "--skip" "read_file_tools_run_in_parallel"
- ;; Two "sleep 0.25" shell commands.
- "--skip" "shell_tools_run_in_parallel"
- ;; One test_sync_tool + one shell sleep.
- "--skip" "mixed_parallel_tools_run_in_parallel"
- ;;; END assert_parallel_duration
- ;; Asserts elapsed >= 4500 ms and
- ;; < 5800 ms for a 5 s timeout; under
- ;; contention elapsed drifts past 5800.
- "--skip"
"remote_models_request_times_out_after_5s"
- ;;; BEGIN delayed auto-environment filesystem
probes
- ;; This test adds a one-second delay in each
- ;; direction to every exec-server WebSocket
- ;; RPC, but allows only 60 seconds for
- ;; thread/start. Auto-environment startup
- ;; serially probes .git, AGENTS files, and
- ;; plugin metadata through many ancestors;
- ;; each missing-path request/response costs
- ;; about two seconds, so it cannot finish.
- "--skip"
"builder_interposes_fixed_delay_for_auto_env"
- ;;; END delayed auto-environment filesystem
probes
- ;; Queued inter-agent mail must be
- ;; injected between the reasoning/
- ;; commentary item and the gate release;
- ;; under contention the gate fires before
- ;; the mail is processed, so the snapshot
- ;; shows the stale function_call instead
- ;; of the expected mail message.
- "--skip"
"queued_inter_agent_mail_triggers_follow_up_after_commentary_message_item"
- ;; Same root cause: snapshot mismatch at
- ;; pending_input.rs assert_two_responses_
- ;; input_snapshot; expects mail at position
- ;; 04 but gets function_call/shell instead.
- "--skip"
"queued_inter_agent_mail_triggers_follow_up_after_reasoning_item"
- ;;; BEGIN tracing callsite cache race
- ;; These tests install a thread-local tracing
- ;; subscriber, then rebuild tracing's
- ;; process-global callsite-interest cache.
- ;; Parallel tests can disable the request span,
- ;; causing the parent trace context to be sent.
- "--skip"
"process_start_propagates_caller_trace_context_across_background_task"
- "--skip"
"rpc_client_propagates_current_trace_context"
- ;;; END tracing callsite cache race
- ;;; BEGIN DNS for hostnames like
- ;;; example.com fails in the build
- ;;; sandbox. host_resolves_to_non_
- ;;; public_ip() in runtime.rs treats
- ;;; failed DNS as non-public and
- ;;; returns NotAllowedLocal, so tests
- ;;; expecting Allowed or Decider get
- ;;; Deny/BaselinePolicy instead.
- "--skip"
"host_blocked_requires_allowlist_match"
- "--skip"
"add_allowed_domain_removes_matching_deny_entry"
- "--skip"
"host_blocked_subdomain_wildcards_exclude_apex"
- "--skip"
"host_blocked_global_wildcard_allowlist_allows_public_hosts_except_denylist"
- "--skip"
"evaluate_host_policy_emits_domain_event_for_decider_ask"
- "--skip"
"evaluate_host_policy_emits_domain_event_for_decider_allow_override"
- "--skip"
"http_connect_accept_blocks_in_limited_mode"
- "--skip"
"http_connect_accept_allows_allowlisted_host_in_full_mode"
- "--skip"
"mitm_policy_blocks_disallowed_method_and_records_telemetry"
- "--skip"
"http_connect_accept_blocks_hooked_host_in_full_mode_without_mitm_state"
- "--skip"
"http_connect_accept_defers_brokered_host_mitm_until_protocol_detection"
- "--skip"
"http_connect_accept_passes_environment_id_to_decider"
- "--skip"
"mitm_policy_allows_matching_hooked_write_in_full_mode"
- "--skip"
"mitm_policy_blocks_hook_miss_for_hooked_host_and_records_telemetry_in_full_mode"
- "--skip"
"mitm_policy_blocks_matching_hooked_write_in_limited_mode"
- "--skip"
"evaluate_host_policy_emits_execution_id_for_baseline_allow"
- "--skip"
"handle_socks5_tcp_blocks_hooked_non_https_host_in_full_mode"
- "--skip"
"handle_socks5_tcp_blocks_limited_mode_without_mitm_state"
- "--skip"
"handle_socks5_tcp_detects_tls_for_brokered_nonstandard_port_in_full_mode"
- "--skip"
"handle_socks5_tcp_uses_mitm_for_hooked_host_in_full_mode"
- "--skip"
"handle_socks5_tcp_uses_mitm_in_limited_mode"
- ;; These tests bind their servers to
- ;; 127.0.0.1 but construct WebSocket URLs
- ;; using the hostname "localhost".
- ;; connect_tcp() passes that hostname to
- ;; tokio::net::lookup_host, which requires
- ;; a name resolver unavailable in the
- ;; build container.
- "--skip"
"public_connector_uses_factory_and_exposes_stream_and_sink"
- "--skip"
"direct_route_connects_secure_websocket"
- "--skip"
"http_proxy_tunnels_secure_websocket_before_handshake"
- "--skip"
"https_proxy_tunnels_secure_websocket_before_handshake"
- ;;; END DNS failure / NotAllowedLocal
- ;;; BEGIN Flaky: wiremock mock expects
- ;;; 1 POST to /codex/safety/arc but
- ;;; receives 0. Passes in some builds,
- ;;; fails in others with identical code
- ;;; and env. The identical custom_
- ;;; variant always passes; only the
- ;;; CODEX_APPS_MCP_SERVER_NAME variant
- ;;; flakes, suggesting a timing race
- ;;; in the async POST under contention.
- "--skip"
"approve_mode_blocks_when_arc_returns_interrupt_for_model"
- "--skip"
"approve_mode_blocks_when_arc_returns_interrupt_without_annotations"
- ;;; END ARC monitor flake
- ;;; BEGIN nss-certs sets SSL_CERT_FILE
- ;;; which makes build_reqwest_client load
- ;;; 171 CA certs via add_root_certificate.
- ;;; This changes the reqwest TLS backend
- ;;; configuration; the ARC safety POST to
- ;;; the localhost mock server never arrives
- ;;; (wiremock expects 1 request, gets 0).
- "--skip"
"approve_mode_blocks_when_arc_returns_interrupt_for_model"
- "--skip"
"approve_mode_blocks_when_arc_returns_interrupt_without_annotations"
- ;;; END nss-certs / ARC monitor
- ;; Upstream bug: JsonRpcConnection has
- ;; no websocket keepalive or read timeout.
- ;; When the exec-server is killed, the
- ;; client's reader task blocks on
- ;; websocket_reader.next() forever because
- ;; TCP doesn't detect the dead peer without
- ;; a write or keepalive probe. Previously
- ;; masked because empty env made "sleep 10"
- ;; fail instantly; with PATH the process
- ;; lives long enough to hit the deadlock.
- "--skip"
"remote_exec_process_reports_transport_disconnect"
- ;; 500 ms timeout on MCP list response
- ;; (mcp_server_status.rs timeout at
- ;; Duration::from_millis(500)). With
- ;; nss-certs TLS now works, so the
- ;; startup plugin sync HTTP requests
- ;; (chatgpt.com, api.github.com) wait
- ;; for TCP timeout instead of failing
- ;; instantly at TLS, eating the budget.
- "--skip"
"mcp_server_status_list_tools_and_auth_only_skips_slow_inventory_calls"
- ;;; BEGIN Stack overflow in 'current_thread'
- ;;; tokio runtime. The sibling tests in
- ;;; tracing_tests.rs use the local helper
- ;;; run_current_thread_test_with_stack
- ;;; (4 MiB) but this one uses bare
- ;;; #[tokio::test] on the 2 MiB default
- ;;; test-thread stack, and TurnStart's
- ;;; future graph exceeds it. With
- ;;; RUST_MIN_STACK raised the overflow is
- ;;; gone but the test then deterministically
- ;;; times out waiting for a span tagged
- ;;; codex.op = "user_input" on the remote
- ;;; trace that upstream never emits on that
- ;;; trace in our environment.
- "--skip"
"turn_start_jsonrpc_span_parents_core_turn_spans"
- ;;; END tracing test stack/timeout
- ;;; BEGIN The upstream loader resolves the
- ;;; MCP OAuth credentials store mode by
- ;;; calling
- ;;; resolve_mcp_oauth_credentials_store_mode
- ;;; with env!("CARGO_PKG_VERSION") -- which
- ;;; in the released 0.142.0 tarball is
- ;;; "0.142.0". These fixture tests
- ;;; construct the expected Config by
- ;;; passing the LOCAL_DEV_BUILD_VERSION
- ;;; constant ("0.0.0") to the same
- ;;; resolver, and the resolver only returns
- ;;; File for "0.0.0" -- Auto otherwise.
- ;;; Upstream CI builds from a checkout
- ;;; still carrying version = "0.0.0" so the
- ;;; tests pass there; they cannot pass
- ;;; against a released tag.
- "--skip"
"test_precedence_fixture_with_gpt3_profile"
- "--skip"
"test_precedence_fixture_with_gpt5_profile"
- "--skip"
"test_precedence_fixture_with_o3_profile"
- "--skip"
"test_precedence_fixture_with_zdr_profile"
- ;;; END LOCAL_DEV_BUILD_VERSION fixture
mismatch
- ;;; BEGIN Verifies that Codex's user-shell
- ;;; spawn produces a child where
- ;;; CODEX_SANDBOX_NETWORK_DISABLED is unset
- ;;; (asserts stdout == "not-set"). We
- ;;; deliberately set that env var at the
- ;;; check phase to trigger upstream's
- ;;; skip_if_no_network! guards; the var then
- ;;; leaks into the spawned shell and the
- ;;; assertion fails. The guix skip is a
- ;;; direct cost of the network-gate fix --
- ;;; trading one broken test for two that
- ;;; now skip cleanly.
- "--skip"
"user_shell_command_does_not_set_network_sandbox_env_var"
- ;;; END CODEX_SANDBOX_NETWORK_DISABLED leak
- ;;; BEGIN The exec-server/tests/file_system
- ;;; integration tests invoke the real
- ;;; system bwrap, which tries to execvp the
- ;;; test binary at the cargo target path
- ;;; under the build dir. Same root cause
- ;;; as the existing
- ;;;
sandbox_reenables_writable_subpaths_under_unreadable_parents
- ;;; skip: guix builds live under /tmp but
- ;;; bwrap's mount namespace excludes /tmp,
- ;;; making the binary invisible inside the
- ;;; namespace.
- "--skip"
"file_system_copy_preserves_symlink_source"
- "--skip"
"file_system_copy_rejects_symlink_escape_destination"
- "--skip"
"file_system_copy_rejects_symlink_escape_source"
- "--skip"
"file_system_create_directory_rejects_symlink_escape"
- "--skip"
"file_system_read_directory_rejects_symlink_escape"
- "--skip"
"file_system_remove_rejects_symlink_escape"
- "--skip"
"file_system_remove_removes_symlink_not_target"
- "--skip"
"file_system_sandboxed_read_allows_readable_root"
- "--skip"
"file_system_sandboxed_read_rejects_symlink_escape"
- "--skip"
"file_system_sandboxed_read_rejects_symlink_parent_dotdot_escape"
- "--skip"
"file_system_sandboxed_write_allows_additional_write_root"
- "--skip"
"file_system_sandboxed_write_rejects_symlink_escape"
- "--skip"
"file_system_sandboxed_write_rejects_unwritable_path"
- ;;; END bwrap-cant-see-/tmp file_system tests
- ;;; BEGIN Landlock is unavailable on Guix,
- ;;; so the sandbox cannot deny network
- ;;; syscalls. These tests expect
- ;;; SandboxErr::Denied for the nc, ping,
- ;;; ssh, getent, and dev_tcp_redirection
- ;;; commands but those commands instead
- ;;; block on connect() until the test's 2s
- ;;; timeout fires (Timeout, exit 124).
- ;;; Same root cause as the Landlock skips
- ;;; at the top of this list; newer test
- ;;; names.
- "--skip" "sandbox_blocks_nc"
- "--skip" "sandbox_blocks_ping"
- "--skip" "sandbox_blocks_dev_tcp_redirection"
- "--skip" "sandbox_blocks_getent"
- "--skip" "sandbox_blocks_ssh"
- ;;; END Landlock network block
- ;;; BEGIN Requires github.com network access.
- ;;; With no "extraKnownMarketplaces" entry
- ;;; in settings.json,
- ;;; collect_marketplace_import_sources
- ;;; inserts a fallback entry for the
- ;;; "claude-plugins-official" marketplace
- ;;; pointing at the github shorthand
- ;;; "anthropics/claude-plugins-official".
- ;;; add_marketplace -> parse_marketplace_source
- ;;; expands that to a github.com/.git URL
- ;;; and clone_git_source runs 'git clone'.
- ;;; The Guix build sandbox has no network,
- ;;; so the clone fails and the marketplace
- ;;; lands in failed_marketplaces. No mock
- ;;; cloner is injected via
- ;;; ExternalAgentConfigService::new_for_test,
- ;;; so there is no in-tree way to satisfy
- ;;; the test offline.
- "--skip"
"import_plugins_infers_external_official_marketplace_when_missing_from_settings"
- ;;; END github.com network access
- ;;; BEGIN Async race between the rollout
- ;;; writer task and a direct SQLite read.
- ;;; The test calls
- ;;; update_memory_settings_with_app_server,
- ;;; which routes through the in-memory
- ;;; thread path on the app-server's
- ;;; ThreadMemoryModeSet handler ->
- ;;; Session::set_thread_memory_mode ->
- ;;; persist_thread_memory_mode_update,
- ;;; which writes a RolloutItem::SessionMeta
- ;;; with the new mode to the rollout file
- ;;; via recorder.record_items + flush. The
- ;;; rollout writer task then asynchronously
- ;;; calls sync_thread_state_after_write,
- ;;; which calls state_db::apply_rollout_items
- ;;; to mirror the SessionMeta into SQLite.
- ;;; flush() only awaits the rollout-file
- ;;; write, not the subsequent SQLite sync.
- ;;; The test opens a fresh StateRuntime and
- ;;; reads get_thread_memory_mode
- ;;; immediately, so it observes the creation
- ;;; default of "enabled" written by
- ;;; upsert_thread_with_creation_memory_mode
- ;;; instead of the new "disabled". Upstream
- ;;; CI wins this race; we lose.
- "--skip"
"update_memory_settings_updates_current_thread_memory_mode"
- ;;; END memory-mode rollout/sqlite race
- ;;; BEGIN The Stopwatch::new constructor in
- ;;; codex_shell_escalation anchors
- ;;; T0 = Instant::now() at construction;
- ;;; the spawned cancellation task fires at
- ;;; T0 + limit. The test captures
- ;;; start = Instant::now() at T1 > T0 (after
- ;;; cancellation_token() returns) and
- ;;; asserts start.elapsed() >= limit,
- ;;; i.e. (T0 + limit) - T1 >= limit, which
- ;;; is always false by the offset T1 - T0.
- ;;; The test only passes when scheduler
- ;;; jitter on the sleep wakeup happens to
- ;;; exceed that offset. Upstream wins the
- ;;; race; we don't always.
- "--skip"
"cancellation_receiver_fires_after_limit"
- ;;; END Stopwatch construction/start offset
race
- ;;; BEGIN invalid remote-control auth-wakeup
test
- ;;;
remote_control_waits_for_account_id_before_enrolling
- ;;; tries to prove that auth_manager.reload()
- ;;; wakes the remote-control worker before
- ;;; REMOTE_CONTROL_ACCOUNT_ID_RETRY_INTERVAL.
- ;;; It does this by first waiting 100 ms for
- ;;; "no request", then rewriting auth.json,
- ;;; calling reload(), and waiting another
- ;;; 100 ms for the enroll request.
- ;;;
- ;;; That is not a valid assertion of the
- ;;; intended behavior. The retry sleep starts
- ;;; when the worker first observes the missing
- ;;; account id, before the test's first
- ;;; 100 ms wait completes. A larger second
- ;;; timeout can therefore overlap the existing
- ;;; one-second fallback retry and pass even if
- ;;; the auth-change watch never woke the task.
- ;;; The test also has no synchronization point
- ;;; proving the worker is actually parked on
- ;;; auth_change_rx.changed() before reload().
- "--skip"
"remote_control_waits_for_account_id_before_enrolling"
- ;;; END invalid remote-control auth-wakeup test
- ;;; BEGIN invalid remote-control timeout tests
- ;;; These are tests, not production behavior.
- ;;;
request_timeout_before_response_headers_is_transient
- ;;; tries to prove that a reqwest timeout
before
- ;;; response headers is classified as a
- ;;; transient remote-control server error.
- ;;; response_body_timeout_is_transient tries to
- ;;; prove the same classification for a timeout
- ;;; while reading the response body after a
- ;;; partial HTTP 200 response.
- ;;;
- ;;; Both tests use timed_out_request. That
- ;;; helper starts a fake TCP server and races
- ;;; the intended server setup against a 100 ms
- ;;; client timeout. The client is supposed to
- ;;; time out; the invalid test assumption is
- ;;; that the spawned fake server task has
always
- ;;; reached the later wait point before that
- ;;; timeout fires. For the header-timeout test
- ;;; that means after listener.accept(); for the
- ;;; body-timeout test that means after
- ;;; listener.accept() and
- ;;; stream.write_all(partial_response).
- ;;;
- ;;; If the client times out before the fake
- ;;; server reaches that point,
timed_out_request
- ;;; has already received the timeout error the
- ;;; test wants to assert. It then tries to
- ;;; clean up by sending request_done_tx and
- ;;; awaiting server_task. But request_done_tx
- ;;; is only observed after the fake server has
- ;;; completed the accept/partial-response
setup;
- ;;; it cannot wake listener.accept() or an
- ;;; earlier write. server_task.await can
- ;;; therefore hang before either test reaches
- ;;; assert_transient_timeout.
- "--skip"
"request_timeout_before_response_headers_is_transient"
- "--skip" "response_body_timeout_is_transient"
- ;;; END invalid remote-control timeout tests
- ;;; BEGIN Order-brittle thread-name websocket
- ;;; notification test.
- ;;;
thread_name_updated_broadcasts_for_loaded_threads
- ;;; resumes a stored thread, reads only the
- ;;; thread/resume response, renames the thread,
- ;;; reads the thread/name/updated
notifications,
- ;;; and then asserts both websocket clients are
- ;;; silent.
- ;;;
- ;;; The resume path can emit an additional
- ;;; thread/goal/cleared snapshot notification
- ;;; after the resume response when the resumed
- ;;; thread has no stored goal.
- ;;; The test does not drain or expect that
- ;;; valid post-resume notification, so the
- ;;; final silence assertion can fail on
- ;;; thread/goal/cleared even though the thread
- ;;; rename broadcast itself succeeded.
- "--skip"
"thread_name_updated_broadcasts_for_loaded_threads"
- ;;; END Order-brittle thread-name websocket
notification test
- ;;; BEGIN Order-brittle app-list notification
- ;;; tests. Codex fetches its apps list from
- ;;; two sources in parallel (installed apps
- ;;; via MCP, available apps via HTTP)
- ;;; and emits an "app/list/updated"
- ;;; notification as each source finishes.
- ;;; The tests use server-side delays
- ;;; (0 ms for MCP, 300 ms for HTTP) to force
- ;;; the MCP source to finish first, then
- ;;; assert a strict two-notification
- ;;; sequence.
- ;;; The implementation is order-agnostic
- ;;; (apps_processor.rs suppresses the
- ;;; HTTP-only interim; final merged
- ;;; state is identical either way).
- ;;; When the HTTP source wins the race, only
- ;;; the final merged notification fires, so
- ;;; the test sees one notification instead of
- ;;; two and fails the assertion against the
- ;;; expected first (accessible-only)
- ;;; notification.
- "--skip"
"list_apps_emits_updates_and_returns_after_both_lists_load"
- "--skip"
"list_apps_force_refetch_patches_updates_from_cached_snapshots"
- ;;; END Order-brittle app-list notification
tests
- ;;; BEGIN Skip .git creators. Otherwise other
- ;;; 8 tests would have their context poisoned.
- ;;; The other tests care about .git not being
- ;;; there.
- "--skip" "turn_interrupt_aborts_running_turn"
- "--skip"
"sandbox_with_network_proxy_blocks_direct_loopback_access"
- "--skip"
"zsh_fork_inner_allowed_script_inherits_active_permission_profile"
- "--skip"
"permission_request_hook_allows_network_approval_without_prompt"
- "--skip"
"guardian_receives_exact_triggers_for_concurrent_network_requests"
- "--skip"
"guardian_receives_exact_trigger_for_single_network_request"
- "--skip"
"approved_network_host_for_one_environment_still_prompts_in_another"
- "--skip"
"unified_exec_network_denial_emits_failed_background_end_event"
- "--skip"
"unified_exec_short_lived_network_denial_emits_failed_end_event"
- ;;; END Skip .git creators.
- )
- #:phases
- #~(modify-phases %standard-phases
- (add-after 'unpack 'chdir-to-workspace
- (lambda _
- (chdir "codex-rs")))
- (add-after 'chdir-to-workspace 'update-version-in-snapshots
- (lambda _
- ;; Snapshot test files contain hardcoded 0.0.0 version strings.
- ;; Update them to match the actual package version.
- (let ((snap-files (find-files "." "\\.snap$")))
- (substitute* snap-files
- (("\\(v0\\.0\\.0\\) ") "(v0.144.1) ")
- (("Update available! 0\\.0\\.0 -> 9\\.9\\.9 ")
- "Update available! 0.144.1 -> 9.9.9")
- (("Update available! 0\\.0\\.0 -> 9\\.9\\.9")
- "Update available! 0.144.1 -> 9.9.9")))))
- (add-after 'chdir-to-workspace 'patch-git-deps-to-vendor
- (lambda _
- ;; Replace git dependencies with version references so cargo
- ;; resolves them from the vendored sources.
- (substitute* "Cargo.toml"
- (("crossterm = \\{ git = [^}]+\\}")
- "crossterm = { version = \"0.28.1\" }")
- (("ratatui = \\{ git = [^}]+\\}")
- "ratatui = { version = \"0.29.0\" }")
- (("tokio-tungstenite = \\{ git = [^}]+\\}")
- "tokio-tungstenite = { version = \"0.28.0\" }")
- (("tungstenite = \\{ git = [^}]+\\}")
- "tungstenite = { version = \"0.27.0\" }")
- (("nucleo = \\{ git = [^}]+\\}")
- "nucleo = { version = \"0.5.0\" }")
- (("runfiles = \\{ git = [^}]+\\}")
- "runfiles = { version = \"0.1.0\" }"))
- ;; Remove workspace members that have unbuildable deps
- ;; (v8-poc requires V8). code-mode stays a workspace member
- ;; so its codex-protocol resolves to the same local copy as
- ;; the rest of the build; disabling its default features
- ;; (below) avoids pulling in V8.
- (substitute* "Cargo.toml"
- (("\"v8-poc\",") ""))
- ;; Disable V8 runtime in codex-code-mode by turning off
- ;; default features. Keep path= so code-mode is resolved
- ;; from the local source tree and shares codex-protocol
- ;; (and other workspace crates) with the rest of the build;
- ;; resolving it from the vendor instead introduces a
- ;; duplicate codex-protocol and causes E0308 type
- ;; mismatches in codex-tools.
- (substitute* "Cargo.toml"
- (("codex-code-mode = \\{ path = \"code-mode\" \\}")
- "codex-code-mode = { path = \"code-mode\", default-features =
false }"))))
- (add-after 'patch-git-deps-to-vendor 'add-version-to-workspace-deps
- (lambda _
- ;; Keep internal workspace path dependencies local, while giving
- ;; Cargo explicit versions for resolver/vendor normalization.
- (let ((cargo-files (find-files "." "^Cargo\\.toml$")))
- (substitute* cargo-files
- ;; Handle inline deps: name = { path = "..." }
-
(("(codex[_-][a-z0-9_-]+|app_test_support|core_test_support|mcp_test_support) =
\\{ path = " all name)
- (string-append name " = { version = \"0.144.1\", path = "))
- ;; Handle inline deps with package: name = { package =
"...", path = "..." }
-
(("(codex[_-][a-z0-9_-]+|app_test_support|core_test_support|mcp_test_support) =
\\{ package = " all name)
- (string-append name " = { version = \"0.144.1\", package =
"))
- ;; Handle section deps: [dependencies.X] with path = "..."
- (("^(path = \"\\.\\./[^\"]*\")" all path-line)
- (string-append path-line "\nversion = \"0.144.1\""))))))
- (add-after 'chdir-to-workspace 'use-gnu-store-in-sandbox
- (lambda _
- ;; LINUX_PLATFORM_DEFAULT_READ_ROOTS in linux-sandbox/src/
- ;; bwrap.rs is the read-only baseline that codex's bwrap
- ;; sandbox bind-mounts so commands can read /usr/bin/ls,
- ;; libc, etc. Upstream lists "/nix/store" for NixOS;
- ;; Guix's equivalent is "/gnu/store". Without this swap,
- ;; the codex sandbox cannot locate any binaries on a Guix
- ;; system because every "system" path resolves into
- ;; /gnu/store/<hash>-pkg/bin/...
- (substitute* "linux-sandbox/src/bwrap.rs"
- (("\"/nix/store\"") "\"/gnu/store\""))))
- (add-after 'chdir-to-workspace 'patch-hardcoded-paths
- (lambda* (#:key inputs #:allow-other-keys)
- (let ((bash-bin (string-append
- (assoc-ref inputs "bash-minimal") "/bin"))
- (coreutils-bin (string-append
- (assoc-ref inputs "coreutils") "/bin"))
- (git-bin (string-append
- (assoc-ref inputs "git-minimal") "/bin"))
- (sed-bin (string-append
- (assoc-ref inputs "sed") "/bin"))
- ;; Include .policy files: the execpolicy-legacy
- ;; crate embeds default.policy via include_str!
- ;; at compile time, so its paths must also be
- ;; patched.
- (rs-files (find-files "." "\\.(rs|policy)$")))
- (substitute* rs-files
- (("\"/bin/bash\"")
- (string-append "\"" bash-bin "/bash\""))
- (("\"/bin/sh\"")
- (string-append "\"" bash-bin "/sh\""))
- (("\"/usr/bin/bash\"")
- (string-append "\"" bash-bin "/bash\""))
- (("\"/usr/bin/sh\"")
- (string-append "\"" bash-bin "/sh\""))
- ;;; bash/sh with inline arguments, e.g. "/bin/bash -i".
- (("\"/bin/bash ")
- (string-append "\"" bash-bin "/bash "))
- (("\"/bin/sh ")
- (string-append "\"" bash-bin "/sh "))
- ;; Single-quoted paths in test assertion strings,
- ;; e.g. "exec '/bin/bash' -c ...". Must match the
- ;; double-quoted substitutions above so both sides
- ;; of assert_eq!/contains use the store path.
- (("'/bin/bash'")
- (string-append "'" bash-bin "/bash'"))
- (("'/bin/sh'")
- (string-append "'" bash-bin "/sh'"))
- ;; coreutils.
- (("\"/bin/(cat|cp|date|echo|head|ls|rm|sleep|true|touch)\""
all cmd)
- (string-append "\"" coreutils-bin "/" cmd "\""))
- ;; coreutils.
- (("\"/usr/bin/(cat|cp|head|ls|touch|true)\"" all cmd)
- (string-append "\"" coreutils-bin "/" cmd "\""))
- ;; coreutils with inline arguments
- ;; like "/bin/echo END-EVENT".
- (("\"/bin/(cat|cp|date|echo|head|ls|rm|sleep|true|touch) "
all cmd)
- (string-append "\"" coreutils-bin "/" cmd " "))
- (("\"/usr/bin/git\"")
- (string-append "\"" git-bin "/git\""))
- (("\"/usr/bin/sed\"")
- (string-append "\"" sed-bin "/sed\"")))
- ;; Bare Command::new("git") and Command::new("ls")
- ;; in codex source files that exec internally.
- (substitute* (find-files "git-utils" "\\.rs$")
- (("Command::new\\(\"git\"\\)")
- (string-append "Command::new(\"" git-bin "/git\")")))
- (substitute* "tui/src/get_git_diff.rs"
- (("Command::new\\(\"git\"\\)")
- (string-append "Command::new(\"" git-bin "/git\")")))
- (substitute* "core/src/turn_diff_tracker.rs"
- (("Command::new\\(\"git\"\\)")
- (string-append "Command::new(\"" git-bin "/git\")")))
- (substitute* "cloud-tasks/src/env_detect.rs"
- (("Command::new\\(\"git\"\\)")
- (string-append "Command::new(\"" git-bin "/git\")")))
- (substitute* "core-plugins/src/startup_sync.rs"
- (("\"git\",")
- (string-append "\"" git-bin "/git\",")))
- (substitute* "file-search/src/lib.rs"
- (("Command::new\\(\"ls\"\\)")
- (string-append "Command::new(\"" coreutils-bin "/ls\")")))
- ;; Neutralize pager with absolute path to cat.
- (substitute* "core/src/unified_exec/process_manager.rs"
- (("\"PAGER\", \"cat\"")
- (string-append "\"PAGER\", \"" coreutils-bin "/cat\""))
- (("\"GIT_PAGER\", \"cat\"")
- (string-append "\"GIT_PAGER\", \"" coreutils-bin "/cat\""))
- (("\"GH_PAGER\", \"cat\"")
- (string-append "\"GH_PAGER\", \"" coreutils-bin "/cat\"")))
- ;; Bare /bin/sleep in the exec-server test (without
- ;; surrounding double quotes, so the main pattern does
- ;; not match).
- (substitute*
- "exec-server/tests/exec_process.rs"
- (("/bin/sleep")
- (string-append coreutils-bin "/sleep")))
- ;; The encrypted-relay test clears the child
- ;; environment, so its bare "true" has no PATH
- ;; through which it could be resolved.
- (substitute*
- "exec-server/tests/relay.rs"
- (("\"true\"")
- (string-append "\"" coreutils-bin "/true\"")))
- ;; Bare /bin/sleep inside a format! string
- ;; (no surrounding double quotes, so the main
- ;; pattern does not match).
- (substitute*
- "shell-escalation/src/unix/escalate_server.rs"
- (("/bin/sleep")
- (string-append coreutils-bin "/sleep")))
- ;; @SHELL@ placeholder from test-shebangs patch
- (substitute*
- (list "rmcp-client/src/program_resolver.rs"
- "tui/src/external_editor.rs")
- (("@SHELL@")
- (string-append bash-bin "/sh")))
- ;; Shebangs inside raw string literals (r#"..."#)
- ;; that are written to scripts at runtime. The
- ;; main "/bin/sh" patterns only match double-quoted
- ;; occurrences; these shebangs have no surrounding
- ;; double quotes.
- (substitute*
- (list "cli/src/doctor.rs"
- "core-plugins/src/npm_source_tests.rs"
- "core-plugins/src/remote_bundle.rs"
- "core-plugins/src/startup_sync_tests.rs"
- "core/src/git_info_tests.rs"
-
"core/src/tools/runtimes/shell/unix_escalation_tests.rs"
- "core/tests/suite/client.rs"
- "core/tests/suite/guardian_review.rs"
- "core/tests/suite/skill_approval.rs"
- "core/tests/suite/user_notification.rs"
- "exec-server/tests/file_system_unix.rs"
- "git-utils/src/baseline.rs"
- "git-utils/src/info.rs"
- "login/src/auth/auth_tests.rs"
- "models-manager/src/manager_tests.rs"
- "sandboxing/src/bwrap_tests.rs"
- "shell-command/src/command_safety/is_safe_command.rs"
- "tui/src/get_git_diff.rs")
- (("#!/bin/bash")
- (string-append "#!" bash-bin "/bash"))
- (("#!/bin/sh")
- (string-append "#!" bash-bin "/sh")))
- ;; Test helpers pass env: Default::default() to the
- ;; spawn code which calls env_clear(), leaving
- ;; processes with no PATH. Inject the build-time
- ;; PATH so tests find coreutils, bash, etc.
- (substitute* (find-files "." "\\.rs$")
- (("env: Default::default\\(\\)")
- (string-append
- "env: std::env::var(\"PATH\")"
- ".into_iter()"
- ".map(|p| (\"PATH\".to_string(), p))"
- ".collect()")))
- ;; Test-only absolute path; bare name works via PATH.
- (substitute* "exec-server/tests/exec_process.rs"
- (("\"/usr/bin/python3\"")
- "\"python3\""))
- ;; Same empty-env issue but in JSON literals
- ;; (serde_json::json! macro).
- (substitute* "exec-server/tests/process.rs"
- (("\"env\": \\{\\}")
- (string-append
- "\"env\": {\"PATH\": \""
- (getenv "PATH")
- "\"}"))))))
- (add-before 'build 'set-bubblewrap-source
- (lambda* (#:key inputs #:allow-other-keys)
- (setenv "CODEX_BWRAP_SOURCE_DIR"
- (string-append
- (assoc-ref inputs "bubblewrap-source")
- "/"))))
- (add-before 'build 'create-node-version-file
- (lambda _
- (call-with-output-file "guix-vendor/node-version.txt"
- (lambda (port)
- (display "22.22.0" port)))))
- (add-before 'check 'increase-open-file-limit
- (lambda _
- ;; The app-server integration suite runs hundreds of Tokio
- ;; runtimes, mock HTTP servers, and app-server subprocesses under
- ;; libtest. On large builders, the default soft nofile limit of
- ;; 1024 is not enough and failures cascade as EMFILE.
- (call-with-values (lambda () (getrlimit 'nofile))
- (lambda (soft hard)
- (let ((target (if hard (min hard 65536) 65536)))
- (when (and soft (< soft target))
- (setrlimit 'nofile target hard)
- (format #t
- "increased maximum number of open files from ~d
to ~d~%"
- soft target)))))))
- (add-before 'check 'set-home
- (lambda _
- ;; HOME must not be a prefix of /tmp, otherwise
- ;; the TUI's path shortener replaces /tmp/... with
- ;; ~/... and 30 snapshot tests fail.
- (setenv "HOME" "/tmp/guix-home")
- (mkdir-p "/tmp/guix-home")
- (setenv "USER" "nixbld")
- ;; fetch_ide_context_uses_unregistered_request_route:
- ;; IDE-context IPC rejects sockets in group-writable
- ;; temporary directories.
- (umask #o077)
- ;; Default libtest thread stack is 2 MiB, which is not
- ;; enough for tokio current_thread tests that drive
- ;; codex-core's full turn pipeline. Upstream gates such
- ;; tests through run_current_thread_test_with_stack (4 MiB)
- ;; in app-server/src/message_processor/tracing_tests.rs;
- ;; raise the global default so future additions that
- ;; forget the wrapper still pass.
- (setenv "RUST_MIN_STACK" "8388608")
- ;; Prevent fanout on huge servers.
- (setenv "TOKIO_WORKER_THREADS" "3")
- ;; Set Codex's no-network marker so upstream tests using
- ;; skip_if_no_network! return early.
- (setenv "CODEX_SANDBOX_NETWORK_DISABLED" "1")))
- (replace 'check
- (lambda* (#:key tests? parallel-build? cargo-test-flags
- #:allow-other-keys)
- (when tests?
- ;; Do not let libtest use all build cores here. Most
- ;; app-server integration tests start a real app-server
- ;; process, and each initialized server creates two
- ;; notify/inotify watchers (SkillsWatcher and FsWatchManager).
- ;; Linux's default fs.inotify.max_user_instances is often 128
- ;; per real UID, so --test-threads=128 can exhaust that
- ;; per-user inotify instance limit even after raising
- ;; RLIMIT_NOFILE.
- (let ((test-threads (min 64 (parallel-job-count))))
- (apply invoke
- `("cargo" "test" "--offline"
- ,@(if parallel-build?
- (list "-j"
- (number->string
- (parallel-job-count)))
- (list "-j" "1"))
- ,@cargo-test-flags
- ,@(if (member "--" cargo-test-flags)
- '()
- '("--"))
- "--test-threads"
- ,(number->string test-threads))))))))))
- (native-inputs `(("bubblewrap" ,bubblewrap) ;tests need bwrap on PATH
- ("clang" ,clang)
- ("cmake-minimal" ,cmake-minimal)
- ("curl" ,curl) ;local loopback test
- ("libunwind" ,libunwind)
- ("lsof" ,lsof) ;app-server tests
- ("nss-certs-for-test" ,nss-certs-for-test) ;OTLP gRPC TLS
- ("perl" ,perl)
- ("procps" ,procps) ;tests use ps
- ("python-minimal" ,python-minimal)
- ("pkg-config" ,pkg-config)
- ("bubblewrap-source" ,(package-source bubblewrap))))
- (inputs (cons* bash-minimal coreutils git-minimal sed
- libcap oniguruma openssl sqlite zlib `(,zstd "lib")
- (cargo-inputs 'codex)))
- (properties '((timeout . 108000) ; 30 hours
- (max-silent-time . 54000))) ; 15 hours
- (home-page "https://github.com/openai/codex")
- (synopsis "AI-assisted coding CLI and TUI")
- (description
- "Codex is an AI-powered coding assistant that runs in the terminal.
-It provides an interactive TUI for conversations with AI models, with
-support for shell command execution, file editing, and code generation.
-Configure providers via @file{~/.codex/config.toml}.
-
-codex-code-mode's V8 Javascript executor is disabled. That means if
-you want to use the GPT 5.6 models you need to add a custom
-@code{model_catalog_json} into @code{~/.codex/config.toml} that
-makes them NOT force code (i.e. V8) mode.")
- (license license:asl2.0)))
-
(define-public codex-acp
(package
(name "codex-acp")
diff --git a/gnu/packages/patches/codex-0.144.1-disable-code-mode.patch
b/gnu/packages/patches/codex-0.144.1-disable-code-mode.patch
deleted file mode 100644
index 58f9d3958cc..00000000000
--- a/gnu/packages/patches/codex-0.144.1-disable-code-mode.patch
+++ /dev/null
@@ -1,302 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-07-11
-License: ASL2.0
-Subject: Disable V8 support in codex-code-mode.
-
-The V8 engine is only needed for actually executing JavaScript in the
-code-mode sandbox. Upstream's code-mode crate depends on v8 and
-deno_core_icudata unconditionally, and the V8 build downloads a large
-prebuilt archive at build time.
-
-Gate the V8-backed implementation behind a disabled "v8-runtime"
-feature, remove the unvendored V8 dependencies, and provide stub
-session providers.
-
-diff --git a/codex-rs/code-mode/Cargo.toml b/codex-rs/code-mode/Cargo.toml
-index 011fee6..4242afb 100644
---- a/codex-rs/code-mode/Cargo.toml
-+++ b/codex-rs/code-mode/Cargo.toml
-@@ -10,7 +10,9 @@ name = "codex_code_mode"
- path = "src/lib.rs"
-
- [features]
--sandbox = ["v8/v8_enable_sandbox"]
-+default = []
-+v8-runtime = []
-+sandbox = []
-
- [lints]
- workspace = true
-@@ -18,13 +20,11 @@ workspace = true
- [dependencies]
- codex-code-mode-protocol = { workspace = true }
- codex-protocol = { workspace = true }
--deno_core_icudata = { workspace = true }
- futures = { workspace = true }
- serde_json = { workspace = true }
- tokio = { workspace = true, features = ["io-util", "macros", "process", "rt",
"sync", "time"] }
- tokio-util = { workspace = true, features = ["rt"] }
- tracing = { workspace = true }
--v8 = { workspace = true }
-
- [dev-dependencies]
- pretty_assertions = { workspace = true }
-diff --git a/codex-rs/code-mode/src/lib.rs b/codex-rs/code-mode/src/lib.rs
-index 6d332bf..b161369 100644
---- a/codex-rs/code-mode/src/lib.rs
-+++ b/codex-rs/code-mode/src/lib.rs
-@@ -1,17 +1,254 @@
-+#[cfg(feature = "v8-runtime")]
- mod cell_actor;
-+#[cfg(feature = "v8-runtime")]
- mod remote_session;
-+#[cfg(feature = "v8-runtime")]
- mod runtime;
-+#[cfg(feature = "v8-runtime")]
- mod service;
-+#[cfg(feature = "v8-runtime")]
- mod session_runtime;
-+#[cfg(feature = "v8-runtime")]
- mod v8_init;
-
-+#[cfg(feature = "v8-runtime")]
- pub(crate) type TaskFailureHandler = std::sync::Arc<dyn Fn(String) + Send +
Sync>;
-
- pub use codex_code_mode_protocol::*;
-+#[cfg(feature = "v8-runtime")]
- pub use remote_session::ProcessOwnedCodeModeSession;
-+#[cfg(feature = "v8-runtime")]
- pub use remote_session::ProcessOwnedCodeModeSessionProvider;
-+#[cfg(feature = "v8-runtime")]
- pub use service::InProcessCodeModeSession;
-+#[cfg(feature = "v8-runtime")]
- pub use service::InProcessCodeModeSessionProvider;
-+#[cfg(feature = "v8-runtime")]
- pub use service::NoopCodeModeSessionDelegate;
-+#[cfg(feature = "v8-runtime")]
- pub use v8_init::V8JitMode;
-+#[cfg(feature = "v8-runtime")]
- pub use v8_init::initialize_v8;
-+
-+// Stubs used when the v8-runtime feature is disabled. Consumers that only
-+// touch the protocol types can build without pulling in v8. Calling
-+// execute/wait/terminate on a stub session returns an error.
-+#[cfg(not(feature = "v8-runtime"))]
-+mod stub {
-+ use std::path::PathBuf;
-+ use std::sync::Arc;
-+
-+ use codex_code_mode_protocol::{
-+ CellId, CodeModeSession, CodeModeSessionDelegate,
CodeModeSessionProvider,
-+ CodeModeSessionProviderFuture, CodeModeSessionResultFuture,
ExecuteRequest, StartedCell,
-+ WaitOutcome, WaitRequest,
-+ };
-+
-+ const DISABLED: &str = "code mode is disabled (built without v8-runtime)";
-+
-+ pub struct NoopCodeModeSessionDelegate;
-+
-+ impl CodeModeSessionDelegate for NoopCodeModeSessionDelegate {
-+ fn invoke_tool<'a>(
-+ &'a self,
-+ _invocation: codex_code_mode_protocol::CodeModeNestedToolCall,
-+ _cancellation_token: tokio_util::sync::CancellationToken,
-+ ) -> codex_code_mode_protocol::ToolInvocationFuture<'a> {
-+ Box::pin(async { Err(DISABLED.into()) })
-+ }
-+
-+ fn notify<'a>(
-+ &'a self,
-+ _call_id: String,
-+ _cell_id: CellId,
-+ _text: String,
-+ _cancellation_token: tokio_util::sync::CancellationToken,
-+ ) -> codex_code_mode_protocol::NotificationFuture<'a> {
-+ Box::pin(async { Ok(()) })
-+ }
-+
-+ fn cell_closed(&self, _cell_id: &CellId) {}
-+ }
-+
-+ #[derive(Default)]
-+ pub struct InProcessCodeModeSessionProvider;
-+
-+ impl CodeModeSessionProvider for InProcessCodeModeSessionProvider {
-+ fn create_session<'a>(
-+ &'a self,
-+ _delegate: Arc<dyn CodeModeSessionDelegate>,
-+ ) -> CodeModeSessionProviderFuture<'a> {
-+ Box::pin(async {
-+ let session: Arc<dyn CodeModeSession> =
Arc::new(InProcessCodeModeSession);
-+ Ok(session)
-+ })
-+ }
-+ }
-+
-+ pub struct InProcessCodeModeSession;
-+
-+ impl InProcessCodeModeSession {
-+ pub fn new() -> Self {
-+ Self
-+ }
-+
-+ pub fn with_delegate(_delegate: Arc<dyn CodeModeSessionDelegate>) ->
Self {
-+ Self
-+ }
-+
-+ pub fn with_delegate_and_task_failure_handler(
-+ _delegate: Arc<dyn CodeModeSessionDelegate>,
-+ _task_failure_handler: Arc<dyn Fn(String) + Send + Sync>,
-+ ) -> Self {
-+ Self
-+ }
-+
-+ pub async fn execute(&self, _request: ExecuteRequest) ->
Result<StartedCell, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn wait(&self, _request: WaitRequest) ->
Result<WaitOutcome, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn terminate(&self, _cell_id: CellId) ->
Result<WaitOutcome, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn shutdown(&self) -> Result<(), String> {
-+ Ok(())
-+ }
-+ }
-+
-+ impl Default for InProcessCodeModeSession {
-+ fn default() -> Self {
-+ Self::new()
-+ }
-+ }
-+
-+ impl CodeModeSession for InProcessCodeModeSession {
-+ fn execute<'a>(
-+ &'a self,
-+ request: ExecuteRequest,
-+ ) -> CodeModeSessionResultFuture<'a, StartedCell> {
-+ Box::pin(InProcessCodeModeSession::execute(self, request))
-+ }
-+
-+ fn wait<'a>(
-+ &'a self,
-+ request: WaitRequest,
-+ ) -> CodeModeSessionResultFuture<'a, WaitOutcome> {
-+ Box::pin(InProcessCodeModeSession::wait(self, request))
-+ }
-+
-+ fn terminate<'a>(
-+ &'a self,
-+ cell_id: CellId,
-+ ) -> CodeModeSessionResultFuture<'a, WaitOutcome> {
-+ Box::pin(InProcessCodeModeSession::terminate(self, cell_id))
-+ }
-+
-+ fn shutdown<'a>(&'a self) -> CodeModeSessionResultFuture<'a, ()> {
-+ Box::pin(InProcessCodeModeSession::shutdown(self))
-+ }
-+ }
-+
-+ #[derive(Default)]
-+ pub struct ProcessOwnedCodeModeSessionProvider;
-+
-+ impl ProcessOwnedCodeModeSessionProvider {
-+ pub fn with_host_program(_host_program: PathBuf) -> Self {
-+ Self
-+ }
-+ }
-+
-+ impl CodeModeSessionProvider for ProcessOwnedCodeModeSessionProvider {
-+ fn create_session<'a>(
-+ &'a self,
-+ _delegate: Arc<dyn CodeModeSessionDelegate>,
-+ ) -> CodeModeSessionProviderFuture<'a> {
-+ Box::pin(async {
-+ let session: Arc<dyn CodeModeSession> =
Arc::new(ProcessOwnedCodeModeSession);
-+ Ok(session)
-+ })
-+ }
-+ }
-+
-+ pub struct ProcessOwnedCodeModeSession;
-+
-+ impl ProcessOwnedCodeModeSession {
-+ pub fn new() -> Self {
-+ Self
-+ }
-+
-+ pub async fn execute(&self, _request: ExecuteRequest) ->
Result<StartedCell, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn wait(&self, _request: WaitRequest) ->
Result<WaitOutcome, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn terminate(&self, _cell_id: CellId) ->
Result<WaitOutcome, String> {
-+ Err(DISABLED.into())
-+ }
-+
-+ pub async fn shutdown(&self) -> Result<(), String> {
-+ Ok(())
-+ }
-+ }
-+
-+ impl Default for ProcessOwnedCodeModeSession {
-+ fn default() -> Self {
-+ Self::new()
-+ }
-+ }
-+
-+ impl CodeModeSession for ProcessOwnedCodeModeSession {
-+ fn execute<'a>(
-+ &'a self,
-+ request: ExecuteRequest,
-+ ) -> CodeModeSessionResultFuture<'a, StartedCell> {
-+ Box::pin(ProcessOwnedCodeModeSession::execute(self, request))
-+ }
-+
-+ fn wait<'a>(
-+ &'a self,
-+ request: WaitRequest,
-+ ) -> CodeModeSessionResultFuture<'a, WaitOutcome> {
-+ Box::pin(ProcessOwnedCodeModeSession::wait(self, request))
-+ }
-+
-+ fn terminate<'a>(
-+ &'a self,
-+ cell_id: CellId,
-+ ) -> CodeModeSessionResultFuture<'a, WaitOutcome> {
-+ Box::pin(ProcessOwnedCodeModeSession::terminate(self, cell_id))
-+ }
-+
-+ fn shutdown<'a>(&'a self) -> CodeModeSessionResultFuture<'a, ()> {
-+ Box::pin(ProcessOwnedCodeModeSession::shutdown(self))
-+ }
-+ }
-+
-+ pub enum V8JitMode {
-+ Enabled,
-+ Disabled,
-+ }
-+
-+ impl V8JitMode {
-+ pub fn as_str(&self) -> &'static str {
-+ match self {
-+ Self::Enabled => "enabled",
-+ Self::Disabled => "disabled",
-+ }
-+ }
-+ }
-+
-+ pub fn initialize_v8(_jit_mode: V8JitMode) -> Result<(), String> {
-+ Err(DISABLED.into())
-+ }
-+}
-+
-+#[cfg(not(feature = "v8-runtime"))]
-+pub use stub::*;
diff --git a/gnu/packages/patches/codex-0.144.1-remove-libwebrtc.patch
b/gnu/packages/patches/codex-0.144.1-remove-libwebrtc.patch
deleted file mode 100644
index 0c1daa55e69..00000000000
--- a/gnu/packages/patches/codex-0.144.1-remove-libwebrtc.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-04-14
-License: ASL2.0
-Subject: Remove macOS-only libwebrtc git dependency.
-
---- a/codex-rs/realtime-webrtc/Cargo.toml
-+++ b/codex-rs/realtime-webrtc/Cargo.toml
-@@ -14,8 +14,5 @@
- thiserror = { workspace = true }
- tokio = { workspace = true, features = ["rt-multi-thread"] }
-
--[target.'cfg(target_os = "macos")'.dependencies]
--libwebrtc = { version = "0.3.26", git =
"https://github.com/juberti-oai/rust-sdks.git", rev =
"e2d1d1d230c6fc9df171ccb181423f957bb3c1f0" }
--
- [lints]
- workspace = true
diff --git a/gnu/packages/patches/codex-0.144.1-remove-patch-sections.patch
b/gnu/packages/patches/codex-0.144.1-remove-patch-sections.patch
deleted file mode 100644
index 0db389a5d0d..00000000000
--- a/gnu/packages/patches/codex-0.144.1-remove-patch-sections.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-07-11
-License: ASL2.0
-Subject: Remove Cargo [patch] sections.
-
-The [patch] sections point to git repositories which are unavailable in
-an offline build. Guix supplies the forked crate sources through
-cargo-inputs instead.
-
---- a/codex-rs/Cargo.toml
-+++ b/codex-rs/Cargo.toml
-@@ -552,17 +552,3 @@
- debug = "limited"
- inherits = "test"
- opt-level = 0
--
--[patch.crates-io]
--# Uncomment to debug local changes.
--# ratatui = { path = "../../ratatui" }
--crossterm = { git = "https://github.com/nornagon/crossterm", rev =
"87db8bfa6dc99427fd3b071681b07fc31c6ce995" }
--ratatui = { git = "https://github.com/nornagon/ratatui", rev =
"9b2ad1298408c45918ee9f8241a6f95498cdbed2" }
--tokio-tungstenite = { git =
"https://github.com/openai-oss-forks/tokio-tungstenite", rev =
"0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186" }
--tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs",
rev = "4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }
--
--# Uncomment to debug local changes.
--# rmcp = { path = "../../rust-sdk/crates/rmcp" }
--
--[patch."ssh://[email protected]/openai-oss-forks/tungstenite-rs.git"]
--tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs",
rev = "4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }
diff --git
a/gnu/packages/patches/codex-0.144.1-test-disable-network-model-refresh.patch
b/gnu/packages/patches/codex-0.144.1-test-disable-network-model-refresh.patch
deleted file mode 100644
index b43b2d21e55..00000000000
---
a/gnu/packages/patches/codex-0.144.1-test-disable-network-model-refresh.patch
+++ /dev/null
@@ -1,179 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-07-11
-License: ASL2.0
-Subject: Disable app-server network model refresh in tests.
-
-Codex 0.144.1 starts a background app-server model refresh worker at
-startup. That worker calls list_models with RefreshStrategy::Online, so
-prewriting models_cache.json does not keep it off the network.
-
-Tests that spawn a codex-app-server child must not depend on remote
-network behavior or start unrelated background network tasks. The
-app-server integration suite already passes the hidden
---disable-plugin-startup-tasks-for-tests flag to suppress startup side
-work in spawned child servers. Extend that test-only flag to skip the
-model refresh worker as well. Production startup keeps the worker
-enabled.
-
-diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs
-index 32a58dba2..7935f3a91 100644
---- a/codex-rs/app-server/src/lib.rs
-+++ b/codex-rs/app-server/src/lib.rs
-@@ -427,18 +427,26 @@ pub enum PluginStartupTasks {
- Skip,
- }
-
-+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-+pub enum ModelsRefreshStartup {
-+ Start,
-+ Skip,
-+}
-+
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
- pub struct AppServerRuntimeOptions {
- pub plugin_startup_tasks: PluginStartupTasks,
-+ pub models_refresh_startup: ModelsRefreshStartup,
- pub remote_control_startup_mode: RemoteControlStartupMode,
- pub install_shutdown_signal_handler: bool,
- }
-
- impl Default for AppServerRuntimeOptions {
- fn default() -> Self {
- Self {
- plugin_startup_tasks: PluginStartupTasks::Start,
-+ models_refresh_startup: ModelsRefreshStartup::Start,
- remote_control_startup_mode:
RemoteControlStartupMode::ResolvePersisted,
- install_shutdown_signal_handler: true,
- }
- }
-@@ -905,6 +912,7 @@ pub async fn run_main_with_transport_options(
- rpc_transport: analytics_rpc_transport(&transport),
- remote_control_handle: Some(remote_control_handle.clone()),
- plugin_startup_tasks: runtime_options.plugin_startup_tasks,
-+ models_refresh_startup: runtime_options.models_refresh_startup,
- }));
- let mut thread_created_rx = processor.thread_created_receiver();
- let mut running_turn_count_rx =
processor.subscribe_running_assistant_turn_count();
-diff --git a/codex-rs/app-server/src/in_process.rs
b/codex-rs/app-server/src/in_process.rs
-index f81c65c2a..1eb834771 100644
---- a/codex-rs/app-server/src/in_process.rs
-+++ b/codex-rs/app-server/src/in_process.rs
-@@ -450,6 +450,7 @@ impl InProcessAppServer {
- rpc_transport: AppServerRpcTransport::InProcess,
- remote_control_handle: None,
- plugin_startup_tasks: crate::PluginStartupTasks::Start,
-+ models_refresh_startup: crate::ModelsRefreshStartup::Start,
- }));
- let mut thread_created_rx = processor.thread_created_receiver();
- let session = Arc::new(ConnectionSessionState::new());
-diff --git a/codex-rs/app-server/src/main.rs b/codex-rs/app-server/src/main.rs
-index 874d20521..3104a2d03 100644
---- a/codex-rs/app-server/src/main.rs
-+++ b/codex-rs/app-server/src/main.rs
-@@ -2,6 +2,7 @@ use clap::Parser;
- use codex_app_server::AppServerRuntimeOptions;
- use codex_app_server::AppServerTransport;
- use codex_app_server::AppServerWebsocketAuthArgs;
-+use codex_app_server::ModelsRefreshStartup;
- use codex_app_server::PluginStartupTasks;
- use codex_app_server::run_main_with_transport_options;
- use codex_arg0::Arg0DispatchPaths;
-@@ -84,6 +85,7 @@ fn main() -> anyhow::Result<()> {
- #[cfg(debug_assertions)]
- if disable_plugin_startup_tasks_for_tests {
- runtime_options.plugin_startup_tasks = PluginStartupTasks::Skip;
-+ runtime_options.models_refresh_startup =
ModelsRefreshStartup::Skip;
- }
- runtime_options.remote_control_startup_mode =
- match (remote_control, remote_control_disabled) {
-diff --git a/codex-rs/app-server/src/message_processor.rs
b/codex-rs/app-server/src/message_processor.rs
-index 7d86f872a..b2da65a2a 100644
---- a/codex-rs/app-server/src/message_processor.rs
-+++ b/codex-rs/app-server/src/message_processor.rs
-@@ -101,7 +101,7 @@ fn decode_request_payload(payload: JsonRpcMessagePayload)
-> Result<Value, JsonR
-
- pub(crate) struct MessageProcessor {
- outgoing: Arc<OutgoingMessageSender>,
-- models_refresh_worker: ModelsRefreshWorker,
-+ models_refresh_worker: Option<ModelsRefreshWorker>,
- skills_watcher: Arc<SkillsWatcher>,
- account_processor: AccountRequestProcessor,
- apps_processor: AppsRequestProcessor,
-@@ -219,6 +219,7 @@ pub(crate) struct MessageProcessorArgs {
- pub(crate) rpc_transport: AppServerRpcTransport,
- pub(crate) remote_control_handle: Option<RemoteControlHandle>,
- pub(crate) plugin_startup_tasks: crate::PluginStartupTasks,
-+ pub(crate) models_refresh_startup: crate::ModelsRefreshStartup,
- }
-
- impl MessageProcessor {
-@@ -242,6 +243,7 @@ impl MessageProcessor {
- rpc_transport,
- remote_control_handle,
- plugin_startup_tasks,
-+ models_refresh_startup,
- } = args;
- let thread_state_manager = ThreadStateManager::new();
- // The thread store is intentionally process-scoped. Config reloads
can
-@@ -299,8 +301,13 @@ impl MessageProcessor {
- )
- });
- let models_manager = thread_manager.get_models_manager();
-- let models_refresh_worker =
-- crate::models_refresh_worker::spawn(&models_manager,
config.http_client_factory());
-+ let models_refresh_worker = match models_refresh_startup {
-+ crate::ModelsRefreshStartup::Start =>
Some(crate::models_refresh_worker::spawn(
-+ &models_manager,
-+ config.http_client_factory(),
-+ )),
-+ crate::ModelsRefreshStartup::Skip => None,
-+ };
- thread_manager
- .plugins_manager()
- .set_analytics_events_client(analytics_events_client.clone());
-@@ -499,7 +506,9 @@ impl MessageProcessor {
- pub(crate) fn clear_runtime_references(&self) {
- self.account_processor.clear_external_auth();
- self.apps_processor.shutdown();
-- self.models_refresh_worker.shutdown();
-+ if let Some(models_refresh_worker) = &self.models_refresh_worker {
-+ models_refresh_worker.shutdown();
-+ }
- self.skills_watcher.shutdown();
- }
-
-@@ -676,7 +685,9 @@ impl MessageProcessor {
- }
-
- pub(crate) async fn drain_background_tasks(&self) {
-- self.models_refresh_worker.shutdown();
-+ if let Some(models_refresh_worker) = &self.models_refresh_worker {
-+ models_refresh_worker.shutdown();
-+ }
- self.thread_processor.drain_background_tasks().await;
- }
-
-diff --git a/codex-rs/app-server/src/message_processor_tracing_tests.rs
b/codex-rs/app-server/src/message_processor_tracing_tests.rs
-index d839bd6f0..797813e35 100644
---- a/codex-rs/app-server/src/message_processor_tracing_tests.rs
-+++ b/codex-rs/app-server/src/message_processor_tracing_tests.rs
-@@ -267,6 +267,7 @@ fn make_processor() -> (Arc<MessageProcessor>,
OutgoingMessageReceiver) {
- rpc_transport: AppServerRpcTransport::Stdio,
- remote_control_handle: None,
- plugin_startup_tasks: crate::PluginStartupTasks::Start,
-+ models_refresh_startup: crate::ModelsRefreshStartup::Start,
- }));
- (processor, outgoing_rx)
- }
-diff --git a/codex-rs/app-server/tests/suite/v2/remote_control.rs
b/codex-rs/app-server/tests/suite/v2/remote_control.rs
-index f85688ddc..66ab20e88 100644
---- a/codex-rs/app-server/tests/suite/v2/remote_control.rs
-+++ b/codex-rs/app-server/tests/suite/v2/remote_control.rs
-@@ -240,6 +240,7 @@ async fn
explicit_remote_control_startup_fails_when_disabled_by_requirements() -
- AppServerWebsocketAuthSettings::default(),
- AppServerRuntimeOptions {
- plugin_startup_tasks: PluginStartupTasks::Skip,
-+ models_refresh_startup:
codex_app_server::ModelsRefreshStartup::Skip,
- remote_control_startup_mode:
RemoteControlStartupMode::EnabledEphemeral,
- install_shutdown_signal_handler: false,
- },
diff --git
a/gnu/packages/patches/codex-0.144.1-test-selected-capability-readiness.patch
b/gnu/packages/patches/codex-0.144.1-test-selected-capability-readiness.patch
deleted file mode 100644
index 5fef67924e0..00000000000
---
a/gnu/packages/patches/codex-0.144.1-test-selected-capability-readiness.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-07-12
-License: ASL2.0
-Subject: Wait for selected capabilities before resuming the turn.
-
-The selected-capability-stack test adds an executor environment while a
-turn is paused at a request_user_input call. It then expects the next
-model sample in the same turn to expose the newly available executor's
-skill, plugin tools, and MCP server.
-
-Replace the fixed 200 millisecond delay with the test suite's existing
-MCP readiness poll.
-
---- a/codex-rs/app-server/tests/suite/v2/selected_capability_stack.rs
-+++ b/codex-rs/app-server/tests/suite/v2/selected_capability_stack.rs
-@@ -358,7 +358,7 @@ async fn
selected_capabilities_become_available_between_samples_in_one_turn() ->
- .await?;
- let turn_start_id = app_server
- .send_turn_start_request(TurnStartParams {
-- thread_id,
-+ thread_id: thread_id.clone(),
- input: vec![UserInput::Text {
- text: "Use the executor when it becomes ready.".to_string(),
- text_elements: Vec::new(),
-@@ -395,7 +395,7 @@ async fn
selected_capabilities_become_available_between_samples_in_one_turn() ->
- let mut exec_server =
- spawn_exec_server(fixture.codex_home.path(),
&fixture.exec_server_url).await?;
- add_environment(&mut app_server, &fixture.exec_server_url).await?;
-- tokio::time::sleep(Duration::from_millis(200)).await;
-+ wait_for_selected_mcp_server(&mut app_server, &thread_id).await?;
- app_server
- .send_response(
- request_id,
diff --git a/gnu/packages/patches/codex-0.144.1-test-shebangs.patch
b/gnu/packages/patches/codex-0.144.1-test-shebangs.patch
deleted file mode 100644
index 1606fe95502..00000000000
--- a/gnu/packages/patches/codex-0.144.1-test-shebangs.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-07-11
-License: ASL2.0
-Subject: Use @SHELL@ placeholder for shebangs in embedded test scripts.
-
-Tests that create and execute temporary shell scripts at runtime use a
-hardcoded "#!/bin/sh" shebang. Replace it with @SHELL@ so the Guix
-build phase can substitute the actual store path.
-
-Also change assertions to print the actual error on failure.
-
---- a/codex-rs/rmcp-client/src/program_resolver.rs
-+++ b/codex-rs/rmcp-client/src/program_resolver.rs
-@@ -149,10 +149,7 @@
- cmd.envs(&env.mcp_env);
- let output = cmd.output().await;
-
-- assert!(
-- output.is_ok(),
-- "Resolved program should execute successfully"
-- );
-+ output.expect("Resolved program should execute successfully");
- Ok(())
- }
-
-@@ -200,7 +197,7 @@
- #[cfg(unix)]
- {
- let file = dir.join(Self::TEST_PROGRAM);
-- fs::write(&file, "#!/bin/sh\nexit 0")?;
-+ fs::write(&file, "#!@SHELL@\nexit 0")?;
- Self::set_executable(&file)?;
- }
-
---- a/codex-rs/tui/src/external_editor.rs
-+++ b/codex-rs/tui/src/external_editor.rs
-@@ -159,7 +159,7 @@
-
- let dir = tempdir().unwrap();
- let script_path = dir.path().join("edit.sh");
-- fs::write(&script_path, "#!/bin/sh\nprintf \"edited\" >
\"$1\"\n").unwrap();
-+ fs::write(&script_path, "#!@SHELL@\nprintf \"edited\" >
\"$1\"\n").unwrap();
- let mut perms = fs::metadata(&script_path).unwrap().permissions();
- perms.set_mode(0o755);
- fs::set_permissions(&script_path, perms).unwrap();
diff --git a/gnu/packages/patches/codex-0.144.1-test-timeout.patch
b/gnu/packages/patches/codex-0.144.1-test-timeout.patch
deleted file mode 100644
index 34c0be738a6..00000000000
--- a/gnu/packages/patches/codex-0.144.1-test-timeout.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-Author: Danny Milosavljevic <[email protected]>
-Date: 2026-03-05
-License: ASL2.0
-Subject: Increase per-event test timeout from 10 to 30 seconds.
-
-In resource-constrained build environments, image processing (resize,
-base64-encode, JSON serialization) can exceed 10 seconds under CPU
-contention, causing intermittent test failures.
-
---- a/codex-rs/core/tests/common/lib.rs
-+++ b/codex-rs/core/tests/common/lib.rs
-@@ -348,7 +348,7 @@
- use tokio::time::timeout;
- loop {
- // Allow a bit more time to accommodate async startup work (e.g.
config IO, tool discovery)
-- let ev = timeout(wait_time.max(Duration::from_secs(10)),
codex.next_event())
-+ let ev = timeout(wait_time.max(Duration::from_secs(30)),
codex.next_event())
- .await
- .expect("timeout waiting for event")
- .expect("stream ended unexpectedly");