509 Commits

  • [codex] auto-label AWS Bedrock issues (#30607)
    ## Summary
    
    AWS Bedrock issues currently fall under broader labels, which makes
    provider-specific reports harder to find. The issue tracker now has an
    `aws-bedrock` label, but the automated labeler does not know to apply
    it.
    
    Teach the issue labeler to select `aws-bedrock` for Amazon Bedrock
    provider or Bedrock Mantle issues while excluding generic AWS
    references.
  • [codex] group blocking and postmerge CI workflows (#30146)
    ## Why
    
    It's hard to change the set of required jobs when they're managed in the
    GitHub UI, and when each workflow is responsible for choosing it's own
    scheduling it's easy to end up with skew between what we enforce on PRs
    vs. on main.
    
    ## What
    
    - add a `blocking-ci` caller workflow, triggered by pull requests and
    pushes to `main`, for Bazel, blob size, cargo-deny, Codespell,
    `repo-checks`, rust CI, and SDK CI
    - add an `always()` terminal job named `CI required` that fails unless
    every called workflow succeeds
    - add a `postmerge-ci` caller workflow for `rust-ci-full` and
    `v8-canary`, with a terminal `Postmerge CI results` job
    - centralize V8 relevance detection in `v8_canary_changes.py`; unrelated
    PR and postmerge runs execute metadata only and skip the expensive build
    matrices
    - leave `v8-canary` outside the blocking gate and leave the external
    `cla` check independent
    
    ## Rollout
    
    A repository admin must replace the existing required GitHub Actions
    contexts with `CI required` in the main-branch ruleset. Retain `cla` as
    a separate required check. Until that change is coordinated, this PR
    cannot satisfy the old standalone check names. In-flight PRs will need
    to be rebased after this lands.
  • release: consume standalone zsh artifacts (#30116)
    ## Why
    
    Once #30114 publishes zsh independently, regular Rust releases should
    reuse that protected, versioned artifact set instead of rebuilding
    identical zsh binaries for every Codex version. Keeping the zsh release
    tag explicit in the workflow also makes future artifact upgrades
    deliberate and easy to review.
    
    This PR assumes the first standalone artifact release will be published
    as `codex-zsh-v0.1.0` before this change lands.
    
    ## What changed
    
    - Added `CODEX_ZSH_RELEASE_TAG` near the top of
    `.github/workflows/rust-release.yml`, initially pinned to
    `codex-zsh-v0.1.0`.
    - Download the standalone release’s generated `codex-zsh` DotSlash
    manifest before assembling Linux and macOS Codex packages.
    - Added a `--zsh-manifest` package-builder override so release packaging
    fetches the matching target archive and verifies the size and SHA-256
    digest recorded in that manifest.
    - Removed the reusable zsh build job from regular Rust releases.
    - Stopped copying zsh archives into each Rust release and stopped
    regenerating a zsh DotSlash manifest there.
    
    Windows packaging remains unchanged because the patched zsh resource is
    only shipped for supported Unix targets.
    
    ## Testing
    
    - Added package-helper coverage that supplies a standalone manifest
    override and verifies the extracted zsh bytes.
    - Ran the `scripts/codex_package` unit test suite.
    - Validated `.github/scripts/build-codex-package-archive.sh` with `bash
    -n`.
  • release: publish standalone zsh artifacts (#30114)
    ## Why
    
    The patched zsh artifacts rarely change, but
    `.github/workflows/rust-release-zsh.yml` currently runs as part of every
    Rust release. Rebuilding the same four binaries for each Codex version
    wastes release capacity and ties an independently versioned runtime
    dependency to the main release cadence.
    
    This establishes the producer side of a build-once flow. The existing
    Rust release workflow remains unchanged until the first standalone
    artifact release has been published and the checked-in DotSlash
    manifests can be updated with its URLs and checksums.
    
    ## What changed
    
    - Run the zsh release workflow for protected `codex-zsh-vX.Y.Z` tags
    instead of as a reusable workflow.
    - Validate the semantic release tag before starting the platform builds.
    - Publish the four zsh archives to a GitHub prerelease so the release
    never becomes the repository latest release.
    - Publish the generated `codex-zsh` DotSlash manifest alongside the
    archives.
    - Document how to publish the next artifact version after changing the
    pinned zsh commit or patch.
    
    ## Tag protection
    
    An active repository tag ruleset named `codex-zsh-v*.*.*` targets
    `refs/tags/codex-zsh-v*.*.*`. It restricts tag creation, updates,
    deletion, and non-fast-forward changes; requires linear history; and
    limits bypass to the configured repository role.
    
    This was verified with:
    
    ```shell
    gh api repos/openai/codex/rulesets/18140982
    ```
    
    The response reported `"enforcement":"active"`, the expected tag
    condition, and the `creation`, `update`, `deletion`, `non_fast_forward`,
    and `required_linear_history` rules.
    
    ## Rollout
    
    After this lands, publish the first `codex-zsh-vX.Y.Z` release. A
    follow-up can then update the checked-in DotSlash manifests and remove
    the zsh rebuild from `.github/workflows/rust-release.yml`.
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/30114).
    * #30116
    * __->__ #30114
  • ci: fail jobs that dirty the worktree (#29720)
    ## Why
    
    CI jobs should not silently leave tracked changes or untracked files in
    the repository worktree.
    
    ## What
    
    - Add a shared final worktree-cleanliness action to 19 checkout-bearing
    PR and main CI jobs.
    - Ignore the intentional SDK scratch directory and nested V8 checkout.
    - Pin Bazelisk in shared CI setup so `.bazelversion` remains
    authoritative, avoiding `MODULE.bazel.lock` deltas on Windows runners.
    - Leave `rust-ci-full` and release-only workflows unchanged.
    - Update `AGENTS.md` to discourage review bots from asking for
    `MODULE.bazel.lock` changes.
  • protocol: separate app and exec RPC ownership (#29714)
    ## Why
    
    The app-server and exec-server expose separate JSON-RPC APIs, but
    exec-server currently sources its serialized protocol and envelope types
    through app-server-oriented code. Giving each API an explicit owner
    makes the crate boundary legible without introducing shared generic
    envelopes.
    
    ## What changed
    
    - Added `codex-exec-server-protocol` to own exec DTOs, process IDs, and
    JSON-RPC envelopes.
    - Updated exec-server clients, transports, handlers, and tests to use
    the new crate.
    - Exposed app-server's existing JSON-RPC types through a public `rpc`
    module while retaining root re-exports.
    - Preserved existing wire shapes, including exec `PathUri` behavior.
    
    ## Stack
    
    This is PR 1 of 6. Next: [PR
    #29721](https://github.com/openai/codex/pull/29721), which moves auth
    mode below the app wire boundary.
    
    ## Validation
    
    - Exec-server protocol and server coverage passed in the focused
    protocol test runs.
    - App-server protocol schema fixtures passed.
  • ci: restore custom Windows runner with hermetic LLVM 0.7.9 (#29143)
    The custom Windows argument-comment-lint job was temporarily moved to
    `windows-2022` in #28940 after hermetic LLVM source extraction failed on
    the newer runner. This takes the upstream extraction fix so the job can
    return to the intended custom runner.
    
    This upgrades `llvm` to `0.7.9` and `rules_cc` to `0.2.18`, refreshes
    the module lock, rebases the remaining Windows and custom libc++
    patches, drops the obsolete symlink-extraction workaround, and restores
    the `windows-x64` runner configuration.
    
    Validation:
    
    - Verified all LLVM patches apply cleanly against the `0.7.9` source.
    - Built `@llvm-project//compiler-rt:clang_rt.builtins.static`.
  • Pin Windows argument lint to Windows 2022 (#28940)
    ## What
    
    Run the Windows argument-comment-lint job on the `windows-2022` hosted
    runner instead of the custom Windows runner pool.
    
    ## Why
    
    The custom pool recently moved from the Visual Studio 2022 Windows image
    to `windows-2025-vs2026`. Since that migration, the job fails while
    Bazel materializes LLVM external repository sources, before the argument
    lint itself runs. The same failure appears across unrelated PRs.
    
    This narrow change tests GitHub’s recommended mitigation for workloads
    that still require the Visual Studio 2022 image:
    https://github.com/actions/runner-images/issues/14017
    
    ## How
    
    Use the standard `windows-2022` runner for only the Windows
    argument-comment-lint matrix entry. No product code or lint behavior
    changes.
  • ci: run code-mode unit tests on all bazel targets (#28562)
    ## Why
    
    V8 should be stable under Bazel, so the `codex-code-mode` unit tests
    should run across the Bazel platform matrix. If these tests prove
    unstable, we should fix the tests rather than exclude them from CI.
    
    ## What changed
    
    - Remove the explicit `//codex-rs/code-mode:code-mode-unit-tests`
    exclusion from the macOS and Linux Bazel test jobs.
    - Remove the same exclusion from the native Windows post-merge job.
    - Keep the existing Windows gnullvm shard coverage.
    
    ## Bazel test coverage
    
    The target contains 26 unit tests. A fresh uncached local Bazel
    execution ran all 26 with 0 failures, 0 ignored tests, and 0 filtered
    tests.
    
    PR Bazel CI selected the target on every enabled platform and reported a
    cached pass:
    
    | Platform | Passing CI job |
    | --- | --- |
    | macOS aarch64 | [Bazel test
    passed](https://github.com/openai/codex/actions/runs/27636617545/job/81725447804)
    |
    | macOS x86_64 | [Bazel test passed in
    2.2s](https://github.com/openai/codex/actions/runs/27636617545/job/81725448008)
    |
    | Linux GNU | [Bazel test passed in
    0.4s](https://github.com/openai/codex/actions/runs/27636617545/job/81725447898)
    |
    | Linux musl | [Bazel test passed in
    0.4s](https://github.com/openai/codex/actions/runs/27636617545/job/81725448117)
    |
    | Windows gnullvm | [Bazel test passed in shard 4/4 in
    1.6s](https://github.com/openai/codex/actions/runs/27636617545/job/81725448166)
    |
  • Run core integration tests against a Wine-backed Windows executor (#28401)
    ## Why
    
    We want to exercise a linux app-server against a windows exec-server
    without having to repeat every test case. This approach has slight
    precedent in the remote docker test setup.
    
    ## What
    
    Run the shared `codex-core` integration suite against Windows
    exec-server behavior from Linux. This makes cross-OS path and shell
    regressions visible while keeping unsupported cases owned by individual
    tests.
    
    - Add `local`, `docker`, and `wine-exec` test environment selection with
    legacy Docker compatibility.
    - Extend `codex_rust_crate` to generate a sharded Wine-exec variant
    using a cross-built Windows server and pinned Bazel Wine/PowerShell
    runtimes.
    - Teach remote-aware helpers about Windows paths and track temporary
    incompatibilities with source-local `skip_if_wine_exec!` calls and
    follow-up reasons.
  • build: run buildifier from just fmt (#28125)
    ## Intent
    
    Keep Bazel and Starlark files consistently formatted without requiring
    contributors to install or version buildifier themselves.
    
    ## Implementation
    
    - Add a SHA-256-pinned, cross-platform DotSlash manifest for buildifier
    v8.5.1.
    - Run buildifier from the shared `just fmt` and `just fmt-check` driver,
    with Windows-safe explicit DotSlash invocation.
    - Provision DotSlash in formatting CI and contributor devcontainers, and
    document the source-build prerequisite.
    - Apply the initial mechanical buildifier formatting baseline.
  • [codex] package Windows ARM64 on x64 (#28001)
    The first release after parallelizing Windows packaging moved the
    critical path to the ARM64 packaging job:
    
    https://github.com/openai/codex/actions/runs/27451157324
    
    The x64 job started immediately and finished in 5m29s. The ARM64
    job waited 76s for its runner and then took 5m56s, holding the
    release for 1m43s after x64 had finished.
    
    Packaging only downloads, signs, archives, and compresses already
    built binaries. It does not execute target code. Run both packaging
    jobs on x64 runners, keeping ARM64 hardware for compilation.
  • [codex] parallelize Windows package archives (#27854)
    In the Windows x64 packaging job from
    
    https://github.com/openai/codex/actions/runs/27391514823
    
    building the primary and app-server package archives serially took 116
    seconds.
    
    Both archives read the same signed-binary directory but write separate
    package trees and output files. Run them concurrently with xargs -P2.
    
    The package helper rewrites DotSlash executables under the process temp
    directory. A naive concurrent run failed when one process tried to
    replace an executable used by the other. Give each bundle separate TMP
    and TEMP roots to keep those caches independent.
    
    On Windows x64 in
    
    https://github.com/openai/codex/actions/runs/27397197944
    
    three serial trials took 127, 128, and 126 seconds. Concurrent trials
    took 76, 74, and 74 seconds, saving 52 to 54 seconds. This removes about
    50 seconds from the release critical path without changing the packaging
    commands or output set.
  • [codex] package Windows symbols in parallel (#27856)
    In the x64 packaging job from
    
    https://github.com/openai/codex/actions/runs/27391514823
    
    archiving and uploading PDBs took 65 seconds after signing. Release
    packaging could not start until that work completed.
    
    Windows code signing changes executables but not their PDBs. Package
    the PDBs in a sibling Ubuntu job as soon as all binary artifacts are
    available. Signing and release packaging can then proceed without
    waiting for the symbols archive, reducing the critical path by about
    one minute.
  • [codex] parallelize Windows compression (#27855)
    Each Windows packaging job creates three compressed forms of five
    binaries in sequence. This takes roughly two minutes and is on the
    release critical path.
    
    Use two xargs workers to compress independent binaries concurrently.
    The workers only read the raw executables and write per-binary archive
    names. The Codex zip can safely read the helper executables while their
    own archives are generated.
    
    On a 16-vCPU AMD EPYC 9V74 Windows x64 release runner, alternating
    trials against artifacts from release run 27391514823 measured:
    
      serial:   121 s, 123 s, 121 s
      parallel:  73 s,  73 s,  74 s
    
    This saves 47 to 50 seconds in the x64 packaging lane, reducing the
    observed release critical path by about 48 seconds when x64 remains the
    limiting lane.
    
    https://github.com/openai/codex/actions/runs/27401905938
  • Use dependency groups for Python SDK tooling (#27538)
    ## Summary
    
    `just fmt` previously used `uv run --with ruff` to make Ruff available.
    Because `--with` creates an ephemeral overlay outside the project
    lockfile, uv periodically re-resolved Ruff (by default every 10 minutes)
    instead of using the version recorded in `uv.lock`.
    
    Move the Python SDK tooling dependencies from the published `dev` extra
    into `format`, `test`, and composed `dev` dependency groups. The
    formatter now selects only the locked `format` group, contributor and CI
    setup explicitly sync the `dev` group, and CI and release commands reuse
    that environment with `--frozen --no-sync`. The scripts formatter also
    uses its project's locked Ruff dependency instead of an ephemeral
    overlay.
    
    Validated the Python 3.12 SDK suite (119 passed, 38 skipped) and the
    repository formatter.
  • Translate non-English issues (#27778)
    Issues written in languages other than English, such as #26979, require
    manual translation before the development team can triage them.
    
    This adds an `Issue Translator` workflow that uses Codex when an issue
    is opened. For non-English reports, it replaces the title with an
    English translation, preserves the original body, and posts the
    translated body as an idempotent issue comment.
    
    The translation scripts were run manually against non-English issue
    content and produced the expected English title and comment output.
  • ci(v8): gate Windows source builds on relevant changes (#27715)
    Avoid rebuilding sandboxed Windows MSVC V8 artifacts for unrelated
    changes to `codex-rs/Cargo.toml`.
    
    The V8 canary now compares the resolved V8 version between the base and
    head commits and only runs the Windows source-build matrix when:
    
    - the resolved V8 crate version changes;
    - Windows artifact-production scripts or workflows change; or
    - the workflow is manually dispatched.
    
    The existing Bazel V8 matrix is unchanged.
    
    ## Why
    
    The Windows MSVC source builds take roughly two to three hours and
    currently run whenever any entry in the broad `v8-canary` path filter
    changes.
  • [codex] revert concurrent npm publishing (#27639)
    In https://github.com/openai/codex/actions/runs/27354608310, the
    concurrency introduced by
    
    https://github.com/openai/codex/commit/5e50e7e639c9284ceac24a5498b73a5602fb6615
    caused the npm publish job to fail.
    
    The six platform tarballs contain different versions of the same
    `@openai/codex` package. Every publish updates the same packument, so
    only two concurrent updates succeeded while four failed with HTTP 409.
    
    Serializing that group would leave only the responses API proxy running
    in parallel. Saving one publish does not justify the nested `xargs`
    machinery needed to express those groups.
    
    Restore the serial publish loop and document why the platform variants
    must not publish concurrently. Platform packages remain ahead of the
    root CLI wrapper, and the SDK remains after its exact root dependency.
  • [codex] download only release artifacts (#27529)
    In https://github.com/openai/codex/actions/runs/27308011621, the
    release job downloaded 10.0 GiB of workflow artifacts in 87 seconds,
    then discarded 42 artifacts accounting for 3.3 GiB.
    
    Select target and supplemental release artifact patterns at download
    time. This also excludes duplicate Cargo timing files without a cleanup
    pass and should reduce total release time by about 30 seconds.
  • [codex] publish DotSlash alongside npm (#27528)
    In https://github.com/openai/codex/actions/runs/27308011621,
    preparing and publishing the three DotSlash configurations took 72
    seconds after creating the GitHub release. npm publication could not
    start until those independent steps finished.
    
    Move DotSlash publication to a sibling job that starts after the GitHub
    release. npm and DotSlash can then proceed concurrently, reducing total
    release time by about one minute.
  • [codex] publish npm packages concurrently (#27527)
    In https://github.com/openai/codex/actions/runs/27308011621,
    publishing the npm tarballs serially took 147 seconds. Six platform
    packages and the responses API proxy are independent.
    
    Publish those packages concurrently, then publish the root CLI wrapper
    and SDK in dependency order. Individual platform publishes took 19 to
    23 seconds, so this should reduce total release time by nearly two
    minutes.
  • [codex] reuse release artifacts for npm staging (#27312)
    The release job already downloads every workflow artifact into `dist`,
    but npm staging creates a new cache and downloads the six target
    artifacts again.
    
    Reuse `dist` as the staging script's artifact cache while preserving the
    existing download fallback for missing artifacts and standalone callers.
    The script retains ownership of temporary caches but does not delete a
    caller-provided directory.
    
    In https://github.com/openai/codex/actions/runs/27242495616, the
    duplicate
    download transferred 3.3 GiB and took 4 minutes 13 seconds. This should
    reduce total release time by about 4 minutes.
  • [codex] link Windows releases with LLD (#27315)
    Windows x64 release builds spend about 36.5 of 48 minutes in final
    LLVM code generation and MSVC linking. Use the existing target-aware
    MSVC
    setup action to select LLD for release builds; the Windows ARM64 archive
    path already exercises the action and its LLD wrapper.
    
    In https://github.com/openai/codex/actions/runs/27242495616, macOS
    becomes
    the critical path after roughly four minutes of Windows improvement, so
    this is expected to reduce total workflow time by about four minutes.
  • Add typed file URIs (#26840)
    ## Why
    
    Codex needs stable `file:` URI identifiers that can cross process and
    operating-system boundaries without eagerly interpreting them as native
    paths. Existing fields also need to keep accepting absolute path strings
    during migration.
    
    ## What changed
    
    - Add `codex-utils-path-uri` with a validated, immutable `PathUri`
    wrapper that currently accepts only `file:` URLs.
    - Expose URI-level `basename`, `parent`, and `join` operations that
    preserve authorities and percent encoding without guessing the source
    operating system.
    - Keep native conversion explicit through `AbsolutePathBuf` and the
    current host rules.
    - Serialize as canonical URI text while accepting both URI text and
    legacy absolute native paths during deserialization.
    - Add adversarial coverage for Windows-looking and POSIX paths, UNC
    authorities, encoded metadata characters, non-UTF-8 POSIX paths, URI
    hierarchy operations, and legacy serde round trips.
  • ci: template custom runner names by repo (#27024)
    ## Why
    
    These workflows currently hard-code the `codex` runner group and custom
    runner labels. That makes the same workflow definitions less portable
    across repository copies or renamed repos, even though the runner fleet
    follows the repository name scheme. Template the runner identities from
    the repository name so `openai/codex` still resolves to the existing
    `codex-*` runners while other repos can use their own `<repo>-*` runner
    names.
    
    ## What Changed
    
    - Replaced custom runner `group` values such as `codex-runners` with
    `${{ github.event.repository.name }}-runners`.
    - Replaced custom runner labels such as `codex-linux-x64` and
    `codex-windows-arm64` with `${{ github.event.repository.name }}-...`.
    - Covered direct `runs-on` objects, matrix `runs_on` entries, reusable
    workflow runner inputs, and release runner labels.
    
    ## Verification
    
    - Parsed all `.github/workflows/*.yml` files as YAML with Ruby.
    - Searched `.github/workflows` to confirm no hardcoded runner-field
    `codex-runners` or `codex-*` labels remain.
  • [codex] Restore release symbol artifacts with line tables (#26202)
    ## Summary
    
    - Restore separate release symbol archives for macOS, Linux, and Windows
    binaries.
    - Build release binaries with `line-tables-only` debuginfo instead of
    full debuginfo.
    - Strip Unix distribution binaries after extracting symbols, preserve
    Windows PDBs, and keep symbol archives available to the release job.
    - Strip the packaged Linux `bwrap` binary before hashing it so the
    embedded digest matches the distributed bytes.
    
    ## Root cause
    
    The first symbol-artifact implementation enabled
    `CARGO_PROFILE_RELEASE_DEBUG=full`. In the June 2 release runs, macOS
    ARM primary builds reached the 90-minute timeout while still inside
    `Cargo build`. After the symbol changes were reverted, the same primary
    build completed in about 22 minutes. The archive step itself completed
    in tens of seconds when reached.
    
    Rust's `line-tables-only` debuginfo level preserves function names and
    source locations for symbolication without emitting the heavier variable
    and type information from full debuginfo.
    
    ## Validation
    
    - Ran `just fmt` from `codex-rs`.
    - Ran `just test-github-scripts` from the repository root: 23 tests
    passed.
    - Ran `bash -n` and `shellcheck` on
    `.github/scripts/archive-release-symbols-and-strip-binaries.sh`.
    - Parsed both modified workflows as YAML and ran `git diff --check`.
    - Built a macOS release smoke binary with `line-tables-only`, archived
    its dSYM through the restored script, stripped the production binary,
    and verified that `atos` resolves `symbol_smoke_function` to
    `main.rs:2`.
    - Ran Linux archive-script control-flow coverage with stubbed `objcopy`
    and `strip` commands.
    - Ran Windows PDB archive staging coverage and verified
    underscore-emitted Rust PDB names are staged under shipped hyphenated
    binary names.
    
    ## Follow-up
    
    The release workflow only runs for tags or manual dispatches, so CI
    cannot dry-run the full release matrix on this PR. The next release run
    will verify runner time and memory behavior under `line-tables-only`.
  • ci: use bazel environment for BuildBuddy secret (#26895)
    ## Why
    
    `BUILDBUDDY_API_KEY` now lives in the `bazel` GitHub Actions environment
    as an environment secret. Jobs that need BuildBuddy credentials must opt
    into that environment so `${{ secrets.BUILDBUDDY_API_KEY }}` resolves
    from the protected environment secret instead of relying on an unscoped
    repository/organization secret.
    
    This follows the same environment-secret migration pattern as #26466.
    
    ## What Changed
    
    - Attach each workflow job that reads `BUILDBUDDY_API_KEY` to the
    `bazel` environment.
    - Set `deployment: false` on those job-level environment blocks.
    
    `deployment: false` lets the job enter the `bazel` environment to access
    its environment secrets without creating GitHub deployment records for
    these CI jobs. That keeps the environment as a secret/access-control
    boundary without making ordinary Bazel CI runs look like deploys.
    
    ## Validation
    
    - Parsed the modified workflow YAML files with Ruby's YAML parser.
    - Checked the modified workflow files for trailing whitespace.
  • Clean up Rust release workflow (#26335)
    ## Why
    PR #26252 moved macOS release signing into the tag-triggered
    `rust-release` workflow through the protected `codesigning` environment
    and Azure Key Vault. That leaves the old manual unsigned-build /
    signed-promotion handoff as dead compatibility scaffolding: it makes the
    release DAG harder to reason about and keeps paths around that the
    current release process no longer intends to operate.
    
    ## What changed
    - Remove the manual `workflow_dispatch` inputs and validation for
    `build_unsigned`, `promote_signed`, and the deprecated `sign_macos`
    flag.
    - Drop the `stage-signed-macos` job and the promotion-specific artifact
    download, re-upload, pruning, and cleanup logic.
    - Make tag-pushed releases always follow the signed release path: build,
    sign, package, finalize, publish, and then run downstream release jobs
    from `release` success.
    - Remove stale `SIGN_MACOS` / `sign_macos` conditions and outputs,
    including downstream gates for npm, DotSlash, WinGet, dev website
    deploy, and `latest-alpha-cli` branch updates.
    
    ## Verification
    - `ruby -e 'require "yaml"; YAML.load_file(ARGV.fetch(0)); puts "yaml
    ok"' .github/workflows/rust-release.yml`
    - `git diff --check`
    - `rg -n
    "workflow_dispatch|inputs\\.|release_mode|build_unsigned|SIGN_MACOS|outputs\\.sign_macos|sign_macos\\b"
    .github/workflows/rust-release.yml` returned no matches
  • [codex] Keep Bazel startup options stable across commands (#26256)
    ## Why
    
    `just bazel-clippy` ran target discovery with
    `--noexperimental_remote_repo_contents_cache`, then ran the build with
    the workspace default `--experimental_remote_repo_contents_cache`. Bazel
    therefore killed and restarted its server on each transition, slowing
    repeated commands and discarding the in-memory analysis cache. An audit
    found the same class of startup-option variation in several CI command
    sequences.
    
    ## What changed
    
    - Keep local lint target-discovery queries on the workspace-default
    Bazel server, while making CI target discovery explicitly use the CI
    startup options.
    - Normalize GitHub Actions launches through the BuildBuddy wrapper to
    share `BAZEL_OUTPUT_USER_ROOT` and
    `--noexperimental_remote_repo_contents_cache`.
    - Route the CI lockfile check and Windows test-shard query through the
    same startup configuration.
    - Document the startup-option invariant and add wrapper regression
    coverage.
    
    ## Validation
    
    - Confirmed consecutive local clippy target-discovery runs retained the
    same Bazel server PID.
  • ci: test windows cross build (#25000)
    We cross build when using bazel for windows. This causes a couple
    hiccups in that v8 does a mksnapshot step that is expecting to snapshot
    on the host arch which wasn't matching when we were doing the
    crossbuild. This was causing segfault failiures when starting up
    codemode from a cross built artifact.
    
    This changes things such that we cross build the library and then run
    and link a snapshot on the host machine/arch which is windows. This
    gives us a functional snapshot and library that can start code-mode on
    windows.
    
    This fixes the build and then fixes two test regressions we had.
  • Use Winget release environment secret (#26466)
    ## Why
    `WINGET_PUBLISH_PAT` now lives as a GitHub environment secret under
    `mainline-release-winget`. The WinGet release job needs to enter that
    environment so `secrets.WINGET_PUBLISH_PAT` resolves during
    stable/mainline Rust releases.
    
    ## What Changed
    - Attach the `winget` job in `.github/workflows/rust-release.yml` to the
    `mainline-release-winget` environment.
    - Set `deployment: false` so the job can read environment secrets
    without creating GitHub deployment records.
    
    ## Operational Note
    The `mainline-release-winget` environment must allow `rust-v*.*.*` tag
    refs before this can run on release tags. The live environment currently
    has a custom policy named `rust-v*.*.*` with type `branch`; add the
    corresponding `tag` policy before relying on this path for a release.
    
    ## Validation
    - `git diff --check origin/main...HEAD --
    .github/workflows/rust-release.yml`
    - `ruby -e 'require "yaml"; ARGV.each { |f| YAML.load_file(f); puts
    "yaml ok: #{f}" }' .github/workflows/rust-release.yml`
  • build: use ThinLTO for release binaries (#23710)
    ## Why
    
    Fat LTO makes release builds substantially slower without providing
    enough measured runtime benefit to justify the release CI long pole. The
    build-profile investigation found that keeping Cargo's default release
    `opt-level=3` and switching from fat LTO to ThinLTO (`3/thin/1`) reduced
    a clean `codex-cli` release build from 2073.893 seconds to 1243.172
    seconds, a 40.06% improvement.
    
    The resulting binary increased from 196.7 MiB to 211.8 MiB (+7.63%).
    Measured runtime changes were small: the worst image workload median was
    +0.86% and app-server startup was +0.31% relative to fat LTO. ThinLTO
    retains cross-crate optimization while avoiding most of the fat-LTO
    build cost.
    
    This deliberately avoids global size optimization: final-executable
    testing showed a substantial regression on the image request path, which
    is expected to become more important as image usage grows.
    
    ## What changed
    
    - Set the workspace release profile to `lto = "thin"`, retaining Cargo's
    default release `opt-level=3`.
    - Remove release and CI workflow-specific LTO overrides so
    release-profile builds consistently use the workspace setting.
    - Remove the now-unused Windows release workflow input and related
    diagnostic output.
    
    ## Validation
    
    - Confirmed the release profile parses with `cargo metadata --no-deps
    --format-version 1`.
    - CI validates release builds across the supported target matrix.
  • Use Azure artifact signing environment secrets (#25945)
    ## Why
    Windows release signing should read Azure signing credentials from the
    `azure-artifact-signing` environment instead of the old repo-level
    `AZURE_TRUSTED_SIGNING_*` names. The smoke runs confirmed the
    environment secrets resolve with the new `AZURE_ARTIFACT_SIGNING_*`
    names once the Windows signing job is attached to that environment.
    
    ## What Changed
    - Put the real Windows signing job in the `azure-artifact-signing`
    environment.
    - Switch the Windows signing action inputs from
    `AZURE_TRUSTED_SIGNING_*` to `AZURE_ARTIFACT_SIGNING_*`.
    - Drop the obsolete `workflow_call.secrets` declarations for the old
    repo-level secret names; the caller continues to use `secrets: inherit`.
    - Remove the temporary branch-trigger and Windows-only smoke-test
    workflow changes before finalizing this PR.
    
    ## Validation
    - `git diff --check -- .github/workflows/rust-release.yml
    .github/workflows/rust-release-windows.yml`
    - `ruby -e 'require "yaml"; ARGV.each { |f| YAML.load_file(f); puts
    "yaml ok: #{f}" }' .github/workflows/rust-release.yml
    .github/workflows/rust-release-windows.yml`
  • ci: sign macOS release artifacts with Azure Key Vault (#26252)
    ## Why
    
    The public Codex release workflow needs to sign and notarize macOS
    binaries and DMGs without placing the Developer ID private key in
    GitHub. This moves the private-key operation behind the protected
    `codesigning` environment and uses GitHub OIDC with Azure Key Vault
    PKCS#11, while preserving the existing external `build_unsigned` /
    `promote_signed` fallback.
    
    ## What changed
    
    - Add a reusable AKV PKCS11 setup action that authenticates to Azure
    with OIDC, downloads pinned signing tools, verifies their SHA-256
    digests, and loads the public signing certificate from Key Vault.
    - Replace the legacy macOS signing action with scripts that support
    AKV-backed `rcodesign`, notarize signed binaries and DMGs, and staple
    DMG notarization tickets.
    - Restructure `rust-release.yml` so macOS builds produce unsigned
    artifacts first, protected jobs perform signing and notarization, macOS
    runners package and verify the results, and release publishing waits for
    verified artifacts.
    - Preserve the manual external-signing handoff flow and make manual-mode
    conditions explicit.
    - Move the Codex entitlements file alongside the signing scripts and
    update CODEOWNERS for the new signing surfaces.
    
    ## Verification
    
    - [Live protected signing workflow
    run](https://github.com/openai/codex/actions/runs/26903610631) completed
    successfully for both macOS architectures, including binary
    signing/notarization, DMG signing/notarization, and final artifact
    verification.
    - Downloaded both signed DMGs and independently verified their checksums
    and strict signatures.
    - Confirmed `xcrun stapler validate` succeeds and Gatekeeper accepts
    both DMGs as `Notarized Developer ID`.
    - Mounted both DMGs and confirmed the contained `codex` and
    `codex-responses-api-proxy` binaries have valid Developer ID signatures
    for the expected architectures.
    
    ---------
    
    Co-authored-by: shijie-openai <shijie.rao@openai.com>
  • [codex] Split Python runtime release workflow (#26226)
    ## Why
    
    Python SDK releases pin an exact `openai-codex-cli-bin` version, so all
    eight platform runtime wheels must be available on PyPI before the SDK
    package is built and published. PyPI does not support reusable workflows
    as Trusted Publishers, which means OIDC-backed publishing must run from
    each top-level release workflow.
    
    ## What changed
    
    - add reusable `python-runtime-build.yml` to prepare and upload all
    eight runtime wheels without publishing
    - add top-level `python-runtime-release.yml` for manual runtime
    publication before updating an SDK pin
    - have `python-sdk-release.yml` publish and verify the prepared runtime
    wheels from its own top-level trusted job before building the SDK
    - verify PyPI exposes exactly the expected eight runtime wheels before
    either release workflow continues
    
    ## PyPI configuration
    
    - keep the trusted publisher for
    `.github/workflows/python-sdk-release.yml` with environment `pypi`
    - add a trusted publisher for
    `.github/workflows/python-runtime-release.yml` with environment `pypi`
    - no trusted publisher is needed for
    `.github/workflows/python-runtime-build.yml`
    
    ## Validation
    
    - parsed all three workflow YAML files
    - validated all embedded shell blocks with `bash -n`
    - no local tests run; relying on online CI
  • [codex] Fix Windows BuildBuddy Bazel wrapper execution (#25915)
    ## Why
    
    #25156 moved Bazel CI launches into a shared Python wrapper. On Windows,
    launching Bazel with `os.execvp` can split the spaced
    `--test_env=PATH=...` argument and fail to propagate the eventual Bazel
    exit status, allowing jobs to pass without running tests. This reapplies
    the wrapper after #25909 with a Windows-safe launch path.
    
    ## What changed
    
    Use a waited `subprocess.run` launch on Windows while preserving
    `os.execvp` on Unix. Add a process-level regression test for spaced
    arguments and child exit status, and run it on Windows Bazel shard 1.
    
    ## Experiment
    
    To confirm Bazel was actually invoking tests, patch `87b61d0be6`
    temporarily added an intentionally failing `codex-core` unit test. Bazel
    failed on that sentinel on all three major platforms:
    
    - [Linux Bazel
    test](https://github.com/openai/codex/actions/runs/26841132773/job/79151062486)
    - [macOS Bazel
    test](https://github.com/openai/codex/actions/runs/26841132773/job/79151062362)
    - [Windows Bazel test shard
    1/4](https://github.com/openai/codex/actions/runs/26841132773/job/79151062155)
    
    The sentinel was removed after collecting this evidence. Windows Bazel
    [clippy](https://github.com/openai/codex/actions/runs/26841132773/job/79151062914)
    and [release
    verification](https://github.com/openai/codex/actions/runs/26841132773/job/79151062739)
    also passed.
    
    ## Validation
    
    After removing the sentinel, `just test -p codex-core` no longer
    reported it. The local run retained two unrelated environment-specific
    failures.
  • [codex] Publish Python runtime wheels with Python SDK releases (#25906)
    ## Summary
    - stop publishing Python runtime wheels as a side effect of Rust
    releases
    - publish runtime wheels from the Python SDK release workflow, either
    explicitly before updating the SDK pin or immediately before a
    `python-v*` SDK release
    - resolve the runtime release from the requested version or the SDK
    package's exact `openai-codex-cli-bin` pin
    - build two musllinux-tagged wheels from the Rust-release Linux package
    archives alongside the six existing runtime wheels
    - validate SDK beta tags before any PyPI write
    
    ## Release configuration
    - update the `openai-codex-cli-bin` PyPI trusted publisher to trust
    `.github/workflows/python-sdk-release.yml` and the
    `publish-python-runtime` job
    
    ## Pin update flow
    - run the `python-sdk-release` workflow manually with the new runtime
    version before opening or updating the SDK pin PR
    - after the pin lands, a `python-v*` SDK tag republishes with
    `skip-existing: true` before publishing the SDK package
    
    ## Validation
    - ran `just fmt`
    - validated the edited workflow YAML
    - validated the embedded `publish-python-runtime` Bash with `bash -n`
    - validated manual `0.136.0 -> rust-v0.136.0` mapping
    - validated tag-driven `python-v0.1.0b3 -> 0.132.0 -> rust-v0.132.0`
    mapping
    - validated rejection of an invalid SDK tag before publication
    - confirmed `rust-v0.136.0` contains the two required Linux package
    archives
    - CI will provide the full test signal
  • Use environment secrets for Azure signing (#24859)
    ## Summary
    - Move Azure Trusted Signing values out of reusable workflow-call
    secrets and into the `azure-artifact-signing` environment scope
    - Attach the Windows signing job to the `azure-artifact-signing`
    environment so it can resolve the signing secrets directly
    - Stop inheriting caller secrets for the Windows release reusable
    workflow
    
    ## Validation
    - `git diff --check -- .github/workflows/rust-release.yml
    .github/workflows/rust-release-windows.yml`
    - `ruby -e 'require "yaml"; ARGV.each { |path| YAML.load_file(path);
    puts "ok #{path}" }' .github/workflows/rust-release.yml
    .github/workflows/rust-release-windows.yml`
  • [codex] Pin Python SDK to glibc-compatible runtime (#25907)
    ## Summary
    - pin the Python SDK runtime package to `openai-codex-cli-bin==0.136.0`
    so Ubuntu/glibc installs resolve a compatible wheel
    - refresh generated SDK artifacts and lock data for the runtime update
    - keep newly generated client-message-id wire models internal to the
    generated protocol layer
    
    ## Dependency
    - merge #25906 first so the Python SDK release publishes both manylinux
    and musllinux runtime wheels before publishing the package with this pin
    
    ## Validation
    - ran `just fmt`
    - regenerated the Python public API helpers
    - validated the edited workflow YAML
    - CI passed 29/29 checks
  • Fix Windows release PDB staging (#25916)
    ## Summary
    - Teach the Windows release prebuild staging step to locate Rust/MSVC
    PDBs emitted with crate-style underscore names.
    - Stage PDBs under the shipped hyphenated binary names so the downstream
    symbol archive step keeps the same artifact contract.
    - Keep a fallback for already-hyphenated PDB names and fail with a clear
    diagnostic if neither form exists.
    
    ## Root cause
    The recent symbol publishing change in #25649 started copying
    `${binary}.pdb` from `target/<triple>/release` during Windows prebuild
    staging. Cargo still emits the `.exe` with the hyphenated binary name,
    but MSVC PDBs for hyphenated Rust crates are emitted with underscores,
    for example `codex_app_server.pdb` for `codex-app-server.exe`. The
    release workflow was still building into the expected directory; the new
    PDB copy step was looking for the wrong filename.
    
    ## Impact
    This unblocks the `rust-release` Windows prebuilt-binary jobs for
    hyphenated binaries while preserving the hyphenated PDB names consumed
    by the final Windows release packaging and symbol archive steps.
    
    ## Validation
    - `just fmt` from `codex-rs`
    - `git diff --check -- .github/workflows/rust-release-windows.yml`
    - Parsed `.github/workflows/rust-release-windows.yml` as YAML locally
    - Local bash staging sanity test for both underscore-emitted and
    hyphenated PDB filenames
  • [codex] Revert shared BuildBuddy Bazel wrapper (#25909)
    ## Why
    
    PR #25905 intentionally adds a failing `codex-core` unit test, but its
    [Bazel test on Windows
    check](https://github.com/openai/codex/actions/runs/26837526950/job/79135369259)
    passed. That shows the Bazel configuration introduced by #25156 is not
    behaving as expected, so revert it while the configuration can be
    investigated separately.
    
    ## What changed
    
    Revert #25156 in full, restoring the previous Bazel remote
    configuration, CI scripts, workflows, `rusty_v8` handling, and
    documentation. This removes the shared BuildBuddy wrapper and its tests.
    
    ## Validation
    
    Not run locally; this exact revert was prioritized for a fast rollback.
  • Route Bazel CI through shared BuildBuddy remote config wrapper (#25156)
    ## Why
    
    Bazel remote configuration was selected in several CI scripts and
    workflow steps. That made the BuildBuddy tenant policy easy to duplicate
    and harder to audit, especially for fork pull requests that must not use
    the OpenAI tenant.
    
    This builds on
    [sluongng/buildbuddy-ci-host-routing](https://github.com/openai/codex/compare/main...sluongng:codex:sluongng/buildbuddy-ci-host-routing)
    and consolidates the policy in one place.
    
    ## What to do if this breaks you
    
    See `codex-rs/docs/bazel.md` for details. TLDR:
    
    1. make a BuildBuddy API key and put it in `~/.bazelrc`
    2. if you're an OpenAI employee, add `common
    --config=buildbuddy-openai-rbe` to `user.bazelrc` in the repo root
    
    Run `just bazel-test` to ensure it works.
    
    Note that `just bazel-remote-test` no longer exists, you need to select
    a remote configuration as documented to use RBE.
    
    ## What changed
    
    - Add `.github/scripts/run_bazel_with_buildbuddy.py` as the shared Bazel
    wrapper and Python library. It selects the OpenAI host only for trusted
    upstream GitHub Actions runs, routes keyed fork runs to the generic
    host, and falls back to local Bazel execution when no key is available.
    - Move endpoint selection into explicit `.bazelrc` configurations and
    update Bazel CI, query helpers, and `rusty_v8` staging to use the shared
    policy. Loading-phase target-discovery queries remain local.
    - Add wrapper and `rusty_v8` unit coverage, plus `just test-scripts` for
    the `.github/scripts` Python tests.
    - Document local Bazel usage, `user.bazelrc` setup, BuildBuddy
    configurations, and CI behavior in `codex-rs/docs/bazel.md`.
    
    ## Validation
    
    - `just test-scripts`
    - `bash -n .github/scripts/run-bazel-ci.sh
    .github/scripts/run-bazel-query-ci.sh
    .github/scripts/run-argument-comment-lint-bazel.sh
    scripts/list-bazel-clippy-targets.sh`
    - `python3 -m py_compile .github/scripts/run_bazel_with_buildbuddy.py
    .github/scripts/test_run_bazel_with_buildbuddy.py
    .github/scripts/test_rusty_v8_bazel.py
    .github/scripts/rusty_v8_bazel.py`
    - `ruff check .github/scripts/run_bazel_with_buildbuddy.py
    .github/scripts/test_run_bazel_with_buildbuddy.py
    .github/scripts/test_rusty_v8_bazel.py
    .github/scripts/rusty_v8_bazel.py`
  • [codex] Use git CLI for Cargo fetches across Rust workflows (#25775)
    ## Why
    Cargo's libgit2 transport has intermittently failed while fetching git
    dependencies with nested submodules.
    [#25644](https://github.com/openai/codex/pull/25644) applied
    `CARGO_NET_GIT_FETCH_WITH_CLI=true` to the main Rust release build after
    macOS SecureTransport/libgit2 failures while cloning `libwebrtc`'s
    nested `libyuv` submodule. Similar flakes can affect other Cargo-bearing
    Rust jobs.
    
    ## What changed
    Configure `CARGO_NET_GIT_FETCH_WITH_CLI=true` at workflow scope for the
    remaining Cargo-bearing Rust workflows:
    
    - fast Rust CI and `cargo-deny`
    - reusable Windows and argument-comment-lint release workflows
    - `rusty-v8-release` and `v8-canary` Cargo builds and smoke tests
    
    The full Rust CI, reusable nextest workflow, and primary Rust release
    build already had the override. Bazel-only workflows are unchanged
    because they use a different dependency fetch path.
    
    ## Validation
    - Parsed all `.github/workflows/*.yml` files as YAML.
    - Scanned Cargo-bearing workflows to confirm they configure
    `CARGO_NET_GIT_FETCH_WITH_CLI`.
  • [codex] Add comprehensive root formatting check (#25683)
    ## Why
    
    The root formatting entrypoints could drift: `just fmt` did not format
    the Justfile itself, and the CI-facing check recipe only checked Python
    scripts instead of matching everything formatted by `just fmt`.
    
    ## What changed
    
    - Add a shared cross-platform Python formatter driver used by both `just
    fmt` and `just fmt-check`.
    - Run Justfile, Rust, Python SDK, and internal-script formatter groups
    concurrently while buffering each formatter group's output until it
    finishes.
    - Log formatter starts immediately, then print each formatter group's
    labeled output when it completes.
    - Keep the SDK lint-fix and Ruff formatting passes ordered, with source
    comments explaining their distinct roles and the check-mode equivalents.
    - Run Ruff through shared `uv run --no-sync --with ruff` overlays so
    formatting works on clean glibc Linux checkouts without installing the
    platform-specific SDK runtime wheel.
    - Show `fmt-check` help text in `just -l` and simplify CI to call the
    shared driver through `just fmt-check`.
    - Pin the general CI workflow to `just@1.51.0` so its formatter agrees
    with the checked-in Justfile.
    - Add regression coverage for the thin Just recipes and the driver's
    formatter graph.
    
    ## Validation
    
    - `just fmt`
    - `just fmt-check`
    - `python3 -m pytest
    sdk/python/tests/test_artifact_workflow_and_binaries.py -k 'root_fmt or
    root_format' -q`
    - `pnpm run format`
    - `git diff --check`
    - `just -l | rg -n '^    fmt|fmt-check'`
    - `uvx --from uv==0.7.22 uv run --frozen --project sdk/python --no-sync
    --with ruff ruff check --diff sdk/python`
  • [codex] Publish release symbol artifacts (#25649)
    ## Why
    
    Production Codex binaries are stripped for distribution, which leaves
    crashes and samples from released builds without the symbols needed for
    useful stack traces. Publish symbols as separate release assets so
    production artifacts stay small while released builds remain
    symbolicateable.
    
    ## What changed
    
    - Add `.github/scripts/archive-release-symbols-and-strip-binaries.sh` to
    package platform-native symbols into `codex-symbols-<artifact>.tar.gz`
    assets while stripping the corresponding Unix binaries before signing.
    - Build release binaries with full debug information before producing
    distribution artifacts.
    - Publish macOS `.dSYM` bundles, Linux `.debug` files with
    `.gnu_debuglink`, and Windows `.pdb` files.
    - Strip Linux `bwrap` before computing its packaged-resource digest, but
    intentionally omit `bwrap` from symbol archives.
    - Preserve symbols artifacts in the unsigned macOS promotion flow.
    
    ## Verification
    
    - Ran `shellcheck` and `bash -n` on
    `.github/scripts/archive-release-symbols-and-strip-binaries.sh`.
    - Parsed the modified workflow YAML files and ran `git diff --check`.
    - Built a macOS release smoke binary and verified that the archived
    `.dSYM` contains DWARF application source information and has the same
    UUID as the stripped production binary.
    - Built Linux smoke binaries and verified that the symbol archive
    contains `codex.debug`, excludes `bwrap.debug`, leaves the expected
    `.gnu_debuglink` in `codex`, and does not mutate the separately stripped
    `bwrap` digest.
    - Staged a Windows smoke archive and verified that it contains the
    expected `.pdb` file.
  • Check root Python script formatting in CI (#25165)
    ## Why
    
    Python files under `scripts/` were not covered by the repository
    formatting recipe or the CI formatting job, so formatting drift could
    merge unnoticed.
    
    ## What
    
    - Add a dedicated `scripts/pyproject.toml` and `scripts/uv.lock` so
    root-script formatting uses a locked Ruff version.
    - Extend `just fmt` to format root Python scripts and add
    `fmt-scripts-check` for CI.
    - Run `just fmt-scripts-check` from `.github/workflows/ci.yml`,
    installing `uv` through SHA-pinned `astral-sh/setup-uv` while retaining
    the `uv` `0.11.3` pin.
    - Apply Ruff formatting to the root Python scripts, including
    `scripts/just-shell.py`, and extend
    `sdk/python/tests/test_artifact_workflow_and_binaries.py` to cover the
    root formatting recipe.
    - Update `AGENTS.md` so agents run `just fmt` after code changes
    anywhere in the repository.
    
    ## Validation
    
    - Extended the existing Python SDK workflow test to assert that `just
    fmt` includes root Python scripts.