Files
codex/.github/workflows
Michael Bolin db51df0f44 ci: support signed macOS release promotion (#22737)
## 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.

## How this is meant to be used

First, start the release as an unsigned macOS build against the release
tag:

```shell
gh workflow run rust-release.yml \
  --repo openai/codex \
  --ref rust-vX.Y.Z \
  -f release_mode=build_unsigned
```

That run builds the normal Linux/Windows artifacts and publishes
unsigned macOS handoff artifacts. The unsigned macOS binaries are then
copied to the secure enclave, signed and notarized there, packaged as a
signed handoff archive, and uploaded back to the GitHub Release for the
same tag.

The signed handoff asset should contain either target directories such
as `aarch64-apple-darwin/` and `x86_64-apple-darwin/`, or artifact
directories such as `aarch64-apple-darwin-app-server/`. The promote
workflow accepts either layout. The directories should contain the
signed binaries and, for primary macOS bundles, the signed and stapled
DMGs.

For example, after signing, upload the handoff asset to the release:

```shell
gh release upload rust-vX.Y.Z \
  signed-macos-rust-vX.Y.Z.tar.zst \
  --repo openai/codex \
  --clobber
```

Then start the promotion run. `unsigned_run_id` is the workflow run id
from the first `build_unsigned` run, and `signed_macos_asset` is the
exact Release asset name uploaded by the secure enclave:

```shell
gh workflow run rust-release.yml \
  --repo openai/codex \
  --ref rust-vX.Y.Z \
  -f release_mode=promote_signed \
  -f unsigned_run_id=1234567890 \
  -f signed_macos_asset=signed-macos-rust-vX.Y.Z.tar.zst \
  -f signed_macos_sha256=<sha256>
```

The `signed_macos_sha256` input is optional, but when provided the
promotion run verifies the handoff archive before unpacking it. The
promotion run also validates that `unsigned_run_id` points to a
successful manual `rust-release` run for the same tag and commit before
importing artifacts.

## 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.
- Validate that `unsigned_run_id` points to a successful manual
`rust-release` run for the same tag and commit before importing
artifacts.
- Limit unsigned macOS artifact upload to the unsigned build path so
normal signed releases do not publish unsigned handoff binaries.
- 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.
2026-05-14 18:36:20 -07:00
..

Workflow Strategy

The workflows in this directory are split so that pull requests get fast, review-friendly signal while main still gets the full cross-platform verification pass.

Pull Requests

  • bazel.yml is the main pre-merge verification path for Rust code. It runs Bazel test and Bazel clippy on the supported Bazel targets, including the generated Rust test binaries needed to lint inline #[cfg(test)] code.
  • rust-ci.yml keeps the Cargo-native PR checks intentionally small:
    • cargo fmt --check
    • cargo shear
    • argument-comment-lint on Linux, macOS, and Windows
    • tools/argument-comment-lint package tests when the lint or its workflow wiring changes

Post-Merge On main

  • bazel.yml also runs on pushes to main. This re-verifies the merged Bazel path and helps keep the BuildBuddy caches warm.
  • rust-ci-full.yml is the full Cargo-native verification workflow. It keeps the heavier checks off the PR path while still validating them after merge:
    • the full Cargo clippy matrix
    • the full Cargo nextest matrix
    • release-profile Cargo builds
    • cross-platform argument-comment-lint
    • Linux remote-env tests

Rule Of Thumb

  • If a build/test/clippy check can be expressed in Bazel, prefer putting the PR-time version in bazel.yml.
  • Keep rust-ci.yml fast enough that it usually does not dominate PR latency.
  • Reserve rust-ci-full.yml for heavyweight Cargo-native coverage that Bazel does not replace yet.