Add a composite action to build and smoke-test Codex packages (#46551)

## What changed

Add `build-codex-packages` to build unsigned CLI and app-server packages for a supplied Rust target and package version. Support release optimizations or faster, unoptimized builds using the release profile.

Prepare platform-specific tools and bundled binaries, archive debug symbols, and produce both `.tar.gz` and `.tar.zst` packages.

## Testing

Run the existing package smoke tests against both compression formats and the symbols archive. Reject host `rg`, and host `bwrap` on Linux, on `PATH` so the tests exercise packaged tools.

GitOrigin-RevId: e843db1ec94681a33a37862fa0cbbb8d715f3b5f
This commit is contained in:
Adam Perry @ OpenAI
2026-09-18 21:36:49 +00:00
committed by copyberry
parent 98a8d4ea9c
commit bfb8daa3c9

View File

@@ -0,0 +1,300 @@
name: build-codex-packages
description: Build and smoke-test unsigned Codex CLI and app-server release packages.
inputs:
target:
description: Rust release target triple to build and test.
required: true
package-version:
description: Semantic version to record in both packages.
required: true
build-mode:
description: Use release optimizations (release) or disable them for faster smoke coverage (debug).
required: true
# Resolve package sources relative to the action so it works in both repository layouts.
runs:
using: composite
steps:
- name: Select release binaries
shell: bash
working-directory: codex-rs
env:
BASE_BINARIES: "codex codex-app-server codex-code-mode-host"
WINDOWS_ONLY_BINARIES: "codex-command-runner codex-windows-sandbox-setup"
BUILD_MODE: ${{ inputs.build-mode }}
# macOS symbol extraction needs packed dSYM bundles before binaries are stripped.
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO: ${{ contains(inputs.target, 'apple-darwin') && 'packed' || 'off' }}
run: |
set -euo pipefail
needed_binaries="$BASE_BINARIES"
if [[ "$RUNNER_OS" == "Windows" ]]; then
needed_binaries+=" $WINDOWS_ONLY_BINARIES"
fi
echo "NEEDED_BINARIES=$needed_binaries" >> "$GITHUB_ENV"
echo "CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=$CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO" >> "$GITHUB_ENV"
case "$BUILD_MODE" in
release) ;;
debug)
# Use the release profile so assertions, symbols and packaging match production.
# Only trade compiler optimizations for faster builds.
{
echo "CARGO_PROFILE_RELEASE_OPT_LEVEL=0"
echo "CARGO_PROFILE_RELEASE_LTO=off"
echo "CARGO_PROFILE_RELEASE_CODEGEN_UNITS=256"
} >> "$GITHUB_ENV"
;;
*) echo "Unsupported build mode: $BUILD_MODE" >&2; exit 1 ;;
esac
- uses: ./.github/actions/setup-ci
- name: Set up Python 3.12
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.3"
- name: Install Linux build dependencies
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: codex-rs
run: |
set -euo pipefail
sudo apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends binutils make pkg-config libcap-dev
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
with:
targets: ${{ inputs.target }}
- name: Use hermetic Cargo home (musl)
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: codex-rs
run: |
set -euo pipefail
cargo_home="${GITHUB_WORKSPACE}/.cargo-home"
mkdir -p "${cargo_home}/bin"
echo "CARGO_HOME=${cargo_home}" >> "$GITHUB_ENV"
echo "${cargo_home}/bin" >> "$GITHUB_PATH"
: > "${cargo_home}/config.toml"
- name: Install Zig
if: ${{ runner.os == 'Linux' }}
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: 0.14.0
use-cache: false
- name: Install musl build tools
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
run: bash "${GITHUB_WORKSPACE}/.github/scripts/install-musl-build-tools.sh"
- name: Disable aws-lc jitter entropy (musl)
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
run: |
set -euo pipefail
# Match public releases: aws-lc's jitter entropy path does not work
# reliably on musl builders, so disable it globally and per target.
echo "AWS_LC_SYS_NO_JITTER_ENTROPY=1" >> "$GITHUB_ENV"
target_no_jitter="AWS_LC_SYS_NO_JITTER_ENTROPY_${TARGET}"
target_no_jitter="${target_no_jitter//-/_}"
echo "${target_no_jitter}=1" >> "$GITHUB_ENV"
- name: Configure rusty_v8 artifact overrides and verify checksums
uses: ./.github/actions/setup-rusty-v8
with:
target: ${{ inputs.target }}
- name: Configure MSVC environment
if: ${{ runner.os == 'Windows' }}
uses: ./.github/actions/setup-msvc-env
with:
target: ${{ inputs.target }}
- name: Build bwrap and export digest
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
run: |
set -euo pipefail
cargo build --target "${TARGET}" --release --timings --bin bwrap
bwrap_path="${CARGO_TARGET_DIR}/${TARGET}/release/bwrap"
# Codex embeds this digest at build time and verifies the packaged
# bwrap at runtime, so hash its final stripped bytes first.
strip --strip-debug --strip-unneeded "$bwrap_path"
digest="$(sha256sum "$bwrap_path" | awk '{print $1}')"
echo "CODEX_BWRAP_SHA256=${digest}" >> "$GITHUB_ENV"
- name: Build Codex package binaries
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
run: |
set -euo pipefail
build_args=()
for binary in $NEEDED_BINARIES; do
build_args+=(--bin "$binary")
done
# SQLite intrinsics can emit instructions unsupported by older x64
# CPUs, causing Windows release binaries to crash during startup.
if [[ "${TARGET}" == "x86_64-pc-windows-msvc" ]]; then
export LIBSQLITE3_FLAGS=SQLITE_DISABLE_INTRINSIC
fi
STABLE_GIT_COMMIT="$(git rev-parse HEAD)"
export STABLE_GIT_COMMIT
cargo build --target "${TARGET}" --release --timings "${build_args[@]}"
- name: Normalize Windows PDB filenames
if: ${{ runner.os == 'Windows' }}
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
run: |
set -euo pipefail
release_dir="${CARGO_TARGET_DIR}/${TARGET}/release"
for binary in $NEEDED_BINARIES; do
expected_pdb="${release_dir}/${binary}.pdb"
if [[ -f "$expected_pdb" ]]; then
continue
fi
underscored_pdb="${release_dir}/${binary//-/_}.pdb"
if [[ ! -f "$underscored_pdb" ]]; then
echo "PDB for ${binary} not found at ${expected_pdb} or ${underscored_pdb}" >&2
exit 1
fi
cp "$underscored_pdb" "$expected_pdb"
done
- name: Download packaged zsh manifest
if: ${{ runner.os != 'Windows' }}
shell: bash
working-directory: codex-rs
run: |
set -euo pipefail
curl -fsSL \
"https://github.com/openai/codex/releases/download/codex-zsh-v0.1.0/codex-zsh" \
-o "${RUNNER_TEMP}/codex-zsh"
- name: Archive symbols and strip binaries
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
PACKAGE_ACTION_PATH: ${{ github.action_path }}
run: |
set -euo pipefail
bash "${PACKAGE_ACTION_PATH}/../../../.github/scripts/archive-release-symbols-and-strip-binaries.sh" \
--target "${TARGET}" \
--artifact-name "${TARGET}" \
--release-dir "${CARGO_TARGET_DIR}/${TARGET}/release" \
--archive-dir "../symbols-dist/${TARGET}" \
--binaries "$NEEDED_BINARIES"
- name: Build Codex package archives
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
CODEX_PACKAGE_VERSION: ${{ inputs.package-version }}
PACKAGE_ACTION_PATH: ${{ github.action_path }}
run: |
set -euo pipefail
target="${TARGET}"
release_dir="${CARGO_TARGET_DIR}/${target}/release"
archive_dir="${GITHUB_WORKSPACE}/dist/${target}"
exe_suffix=""
if [[ "$RUNNER_OS" == "Windows" ]]; then
exe_suffix=".exe"
fi
package_args=(
--target "$target"
--code-mode-host-bin "${release_dir}/codex-code-mode-host${exe_suffix}"
--cargo-profile release
--package-version "$CODEX_PACKAGE_VERSION"
--force
)
if [[ "$RUNNER_OS" == "Linux" ]]; then
package_args+=(--bwrap-bin "${release_dir}/bwrap")
fi
if [[ "$RUNNER_OS" == "Windows" ]]; then
package_args+=(
--codex-command-runner-bin "${release_dir}/codex-command-runner.exe"
--codex-windows-sandbox-setup-bin "${release_dir}/codex-windows-sandbox-setup.exe"
)
else
package_args+=(--zsh-manifest "${RUNNER_TEMP}/codex-zsh")
fi
python3 "${PACKAGE_ACTION_PATH}/../../../scripts/build_codex_package.py" \
"${package_args[@]}" \
--variant codex \
--entrypoint-bin "${release_dir}/codex${exe_suffix}" \
--package-dir "${RUNNER_TEMP}/codex-package-${target}" \
--archive-output "${archive_dir}/codex-package-${target}.tar.gz" \
--archive-output "${archive_dir}/codex-package-${target}.tar.zst"
python3 "${PACKAGE_ACTION_PATH}/../../../scripts/build_codex_package.py" \
"${package_args[@]}" \
--variant codex-app-server \
--entrypoint-bin "${release_dir}/codex-app-server${exe_suffix}" \
--package-dir "${RUNNER_TEMP}/codex-app-server-package-${target}" \
--archive-output "${archive_dir}/codex-app-server-package-${target}.tar.gz" \
--archive-output "${archive_dir}/codex-app-server-package-${target}.tar.zst"
- name: Smoke-test assembled packages
shell: bash
working-directory: codex-rs
env:
TARGET: ${{ inputs.target }}
PYTHONPATH: ${{ github.workspace }}/sdk/python/src${{ runner.os == 'Windows' && ';' || ':' }}${{ github.workspace }}/sdk/python/tests
PACKAGE_ACTION_PATH: ${{ github.action_path }}
run: |
set -euo pipefail
cd "${PACKAGE_ACTION_PATH}/../../../scripts/codex_package/smoke_tests"
target="${TARGET}"
archive_dir="${GITHUB_WORKSPACE}/dist/${target}"
mkdir -p "${GITHUB_WORKSPACE}/codex-rs/target"
pytest_args=(
-v
--basetemp "${GITHUB_WORKSPACE}/codex-rs/target/package-smoke-tmp"
--package-target "$target"
--symbols-archive "${GITHUB_WORKSPACE}/symbols-dist/${target}/codex-symbols-${target}.tar.gz"
)
# CI must exercise packaged tools; local smoke runs may use host tools.
if command -v rg || { [[ "$RUNNER_OS" == "Linux" ]] && command -v bwrap; }; then
echo "Host rg (or bwrap on Linux) is on PATH; CI must use packaged tools." >&2
exit 1
fi
uv run --frozen pytest "${pytest_args[@]}" \
--compression gzip \
--cli-archive "${archive_dir}/codex-package-${target}.tar.gz" \
--app-server-archive "${archive_dir}/codex-app-server-package-${target}.tar.gz" \
test_codex_package.py
uv run --frozen pytest "${pytest_args[@]}" \
--compression zstd \
--cli-archive "${archive_dir}/codex-package-${target}.tar.zst" \
--app-server-archive "${archive_dir}/codex-app-server-package-${target}.tar.zst" \
test_codex_package.py