## Why
`rust-release.yml` can create unsigned macOS artifacts for external signing, but there was no signed resume path after those artifacts returned from a secure enclave. Release operators need a way to reuse the first run artifacts, ingest signed macOS binaries and DMGs, and continue the normal signed release path without rebuilding every platform or treating handoff assets as final release assets.
## What Changed
- Add explicit manual `release_mode` values for `build_unsigned` and `promote_signed` while keeping `sign_macos` as a deprecated compatibility input.
- Add promote inputs for `unsigned_run_id`, `signed_macos_asset`, and optional `signed_macos_sha256`.
- Add a `stage-signed-macos` job that downloads the signed handoff asset from the GitHub Release, verifies signed binaries and stapled DMGs, repacks normal macOS release artifacts, and builds macOS Python runtime wheels.
- Teach the release job to download Part 1 artifacts from the unsigned run, discard unsigned macOS staging artifacts, re-upload promoted Linux and Windows artifacts for npm staging, and then run the signed release tail.
- Clean up unsigned and signed handoff release assets after successful promotion.
## Verification
- Parsed `.github/workflows/rust-release.yml` with Ruby YAML loading.
No developers.openai.com documentation update is needed.
This change fixes the case where the UI can sit on _"Starting MCP
servers"_ even though the review work is already running or has already
completed.
- MCP startup status header is visible when a `/review` turn starts with
enabled MCP server startups
- Restore the underlying _Working..._ status after MCP startup completes
or fails
- Add regression coverage for overlapping startup/turn flows and status
restoration
_De-scoped from a broader thread-scoped MCP status change that would
have made it easier to route MCP startup statuses to the appropriate
thread (parent vs. review). These changes address the UI regression
without requiring more significant changes across app-server & core._
Fixes#18792.
## Why
The TUI still had a few low-risk dependencies flowing through the
transitional `legacy_core` namespace after the app-server migration.
These helpers either already have clearer non-core owners or are
presentation logic that does not belong in `codex-core`, so moving them
out reduces the compatibility surface without changing product behavior.
## What changed
This is a low-risk change, almost completely mechanical in nature.
- Route TUI Codex-home lookup through `codex-utils-home-dir`, use
`Config::log_dir` directly, and call
`codex-sandboxing::system_bwrap_warning` without going through
`legacy_core`.
- Move shared `codex resume` hint formatting from `codex-core` into
`codex-utils-cli`.
- Update CLI and TUI call sites to use the shared CLI utility, and keep
the resume-command behavior covered by tests in its new home.
## Verification
- `cargo test -p codex-utils-cli`
- `cargo test -p codex-utils-cli resume_command`
## Summary
Removes the feature since this is effectively on by default in all cases
where we should use it, or can be configured via models.json.
## Testing
- [x] unit tests pass
## Summary
- remove two redundant `PathBuf` clones in Windows sandbox setup tests
- fix current `rust-ci-full` Windows clippy failures on `main`
## Validation
- `just fmt`
- attempted on `dev`: `cargo clippy --target x86_64-pc-windows-msvc
--tests --profile dev --timings -- -D warnings`
- blocked by missing MSVC cross toolchain on the Linux devbox (`lib.exe`
/ MSVC C toolchain unavailable)
- live failure evidence: main `rust-ci-full` runs 25880209898 and
25879137967 failed on `windows-sandbox-rs/src/bin/setup_main/win.rs`
with `clippy::redundant_clone` at the two edited callsites
## Summary
- remove the app-server `plugin-read` serialization queue from
`plugin/list` and `plugin/read`
- allow plugin read/list requests to start immediately instead of
waiting behind other plugin read/list requests
## Test plan
- `just fmt`
- `cargo test -p codex-app-server-protocol`
made a `rust-release-prepare` environment with the necessary API key as
an environment secret. use this in the workflow rather than the action
secret.
once this merges and i confirm it works as intended, ill rm the action
secret.
## Summary
This change lets `forced_chatgpt_workspace_id` accept multiple workspace
IDs instead of a single value.
It keeps the existing config key name, adds backward-compatible parsing
for a single string in `config.toml`, and normalizes the setting into an
allowed workspace list across login enforcement, app-server config
surfaces, and local ChatGPT auth helpers.
## Why
Workspace-restricted deployments may need to allow more than one ChatGPT
workspace without dropping the guardrail entirely.
## Server-side impact
Codex's local server and app-server protocol needed changes because they
previously assumed a single workspace ID. The local login flow now
matches the auth backend interface by sending the allowed workspace list
as a single comma-separated `allowed_workspace_id` query parameter.
## Validation
This was tested with:
- A single workspace config
- With multi-workspace configs
- With multiple workspaces in the config
- The user only being a part of a subset of them
All were successful.
Automated coverage:
- `cargo test -p codex-login`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-tui local_chatgpt_auth`
- `cargo test --locked -p codex-app-server
login_account_chatgpt_includes_forced_workspace_allowlist_query_param`
## Why
Some core integration-test paths were creating Codex state under ambient
`~/.codex`. In environments where `HOME=/tmp`, that showed up as
`/tmp/.codex`, which is host-level shared state and makes these tests
environment/order sensitive.
The affected paths were:
- `core/tests/suite/live_cli.rs`: `run_live()` spawned the real CLI with
a temp cwd, but without an isolated home, so the child resolved Codex
home from ambient `HOME`.
- core / exec-server integration test binaries using
`configure_test_binary_dispatch(...)`: their startup ctor installs arg0
helper aliases like `apply_patch` and `codex-linux-sandbox`. Full
`arg0_dispatch()` also installs aliases from ambient Codex-home
resolution, so test-binary startup could create `CODEX_HOME/tmp/arg0`;
with `HOME=/tmp`, that became `/tmp/.codex/tmp/arg0/...`.
## What changed
- `live_cli` now gives the spawned CLI a temp `HOME` and temp
`CODEX_HOME`.
- arg0 alias setup now has an explicit-home form,
`prepend_path_entry_for_codex_aliases_in(...)`, so test helpers can
place alias state under a temp directory without relying on ambient
`CODEX_HOME`.
- helper re-entry behavior is preserved with
`dispatch_arg0_if_needed()`, so aliases like `apply_patch` and
`codex-linux-sandbox` still dispatch correctly before test alias
installation.
- core test support keeps the temp Codex home alive for the lifetime of
the test binary, matching the alias lifetime.
## Verification
Verified on `dev2` with `HOME=/tmp` that the focused core test-binary
startup path no longer recreates `/tmp/.codex`.
Also checked the exact `live_cli` test path under `HOME=/tmp`; on `dev2`
it still hits the existing remote-only `cargo_bin("codex-rs")`
resolution failure before spawning the child, but `/tmp/.codex` remains
absent after the run.