Skip to content

ci: support signed macOS release promotion#22737

Merged
bolinfest merged 1 commit into
mainfrom
pr22737
May 15, 2026
Merged

ci: support signed macOS release promotion#22737
bolinfest merged 1 commit into
mainfrom
pr22737

Conversation

@bolinfest
Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest commented May 15, 2026

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:

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:

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:

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.

@bolinfest bolinfest requested a review from shijie-oai May 15, 2026 01:18
Copy link
Copy Markdown

@russ-oai russ-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get folks unblocked

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

- if: ${{ runner.os == 'macOS' }}
name: Upload unsigned macOS artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: ${{ matrix.artifact_name }}-unsigned
path: codex-rs/unsigned-dist/${{ matrix.target }}/*

P1 Badge Do not publish unsigned macOS artifacts on signed releases

Because this upload is unconditional for every macOS build, normal tag-push signed releases now produce *-apple-darwin*-unsigned workflow artifacts; the release job downloads all artifacts and only prunes unsigned macOS assets when SIGN_MACOS == 'false', so signed releases will include the unsigned handoff binaries as public release assets. Limit this upload to the build_unsigned path (or prune it for signed releases) so regular signed releases do not ship unsigned macOS binaries alongside the signed ones.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +89 to +90
if [[ ! "${UNSIGNED_RUN_ID}" =~ ^[0-9]+$ ]]; then
echo "❌ release_mode=promote_signed requires unsigned_run_id to be a workflow run id"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate the unsigned run before promotion

In the promote_signed path, the only check on unsigned_run_id is that it is numeric; a typo that points at a successful rust-release run for a different tag still passes here, and the release job later imports artifacts from that run with gh run download "$UNSIGNED_RUN_ID". The GitHub CLI manual documents gh run download [<run-id>] as downloading artifacts for the supplied run, so this can silently ship Linux/Windows/Python assets built for another version under the current tag; please verify the run's workflow/ref/tag matches ${GITHUB_REF_NAME} before using it.

Useful? React with 👍 / 👎.

@bolinfest bolinfest enabled auto-merge (squash) May 15, 2026 01:24
@bolinfest bolinfest disabled auto-merge May 15, 2026 01:24
## 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.
- 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.
@bolinfest
Copy link
Copy Markdown
Collaborator Author

@codex review and verify earlier comments were addressed

@chatgpt-codex-connector
Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@bolinfest bolinfest merged commit db51df0 into main May 15, 2026
47 of 62 checks passed
@bolinfest bolinfest deleted the pr22737 branch May 15, 2026 01:36
@github-actions github-actions Bot locked and limited conversation to collaborators May 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants