From 60dad3fc7edc6ca7a9c2a02d9bba46eb18f9164c Mon Sep 17 00:00:00 2001 From: Channing Conger Date: Tue, 16 Jun 2026 05:10:44 +0000 Subject: [PATCH] build: package and validate code-mode host --- .github/actions/setup-rusty-v8/action.yml | 21 +++-- .../scripts/build-codex-package-archive.sh | 17 ++++ .../rust-ci-full-nextest-platform.yml | 82 ++++++++++++------- .github/workflows/rust-ci-full.yml | 1 + .github/workflows/rust-release-windows.yml | 15 ++-- .github/workflows/rust-release.yml | 52 +++++++----- BUILD.bazel | 2 + codex-rs/Cargo.lock | 1 + codex-rs/cli/BUILD.bazel | 10 ++- codex-rs/code-mode-host/BUILD.bazel | 1 + codex-rs/code-mode-host/Cargo.toml | 8 ++ codex-rs/v8-poc/src/lib.rs | 5 +- defs.bzl | 62 +++++++++++++- justfile | 10 ++- runfile_env_binary_launcher.bat.tpl | 51 ++++++++++++ runfile_env_binary_launcher.sh.tpl | 57 +++++++++++++ scripts/codex_package/README.md | 4 +- scripts/codex_package/cargo.py | 13 ++- scripts/codex_package/cli.py | 14 ++++ scripts/codex_package/layout.py | 8 ++ scripts/codex_package/targets.py | 1 + scripts/codex_package/test_cargo.py | 21 +++++ scripts/codex_package/v8.py | 7 +- scripts/install/install.ps1 | 1 + scripts/install/install.sh | 6 +- scripts/run-nextest.py | 65 +++++++++++++++ 26 files changed, 457 insertions(+), 78 deletions(-) create mode 100644 runfile_env_binary_launcher.bat.tpl create mode 100644 runfile_env_binary_launcher.sh.tpl create mode 100644 scripts/run-nextest.py diff --git a/.github/actions/setup-rusty-v8/action.yml b/.github/actions/setup-rusty-v8/action.yml index d9c4484657..bfe4a1444e 100644 --- a/.github/actions/setup-rusty-v8/action.yml +++ b/.github/actions/setup-rusty-v8/action.yml @@ -4,6 +4,10 @@ inputs: target: description: Rust target triple with Codex-built V8 release artifacts. required: true + sandbox: + description: Use the V8 pointer-compression sandbox artifact profile. + required: false + default: "false" runs: using: composite @@ -11,6 +15,7 @@ runs: - name: Configure rusty_v8 artifact overrides and verify checksums shell: bash env: + SANDBOX: ${{ inputs.sandbox }} TARGET: ${{ inputs.target }} run: | set -euo pipefail @@ -19,14 +24,18 @@ runs: release_tag="rusty-v8-v${version}" base_url="https://github.com/openai/codex/releases/download/${release_tag}" binding_dir="${RUNNER_TEMP}/rusty_v8" - archive_path="${binding_dir}/librusty_v8_release_${TARGET}.a.gz" - binding_path="${binding_dir}/src_binding_release_${TARGET}.rs" - checksums_path="${binding_dir}/rusty_v8_release_${TARGET}.sha256" + artifact_profile="release" + if [[ "${SANDBOX}" == "true" ]]; then + artifact_profile="ptrcomp_sandbox_release" + fi + archive_path="${binding_dir}/librusty_v8_${artifact_profile}_${TARGET}.a.gz" + binding_path="${binding_dir}/src_binding_${artifact_profile}_${TARGET}.rs" + checksums_path="${binding_dir}/rusty_v8_${artifact_profile}_${TARGET}.sha256" mkdir -p "${binding_dir}" - curl -fsSL "${base_url}/librusty_v8_release_${TARGET}.a.gz" -o "${archive_path}" - curl -fsSL "${base_url}/src_binding_release_${TARGET}.rs" -o "${binding_path}" - curl -fsSL "${base_url}/rusty_v8_release_${TARGET}.sha256" -o "${checksums_path}" + curl -fsSL "${base_url}/$(basename "${archive_path}")" -o "${archive_path}" + curl -fsSL "${base_url}/$(basename "${binding_path}")" -o "${binding_path}" + curl -fsSL "${base_url}/$(basename "${checksums_path}")" -o "${checksums_path}" if [[ "$(wc -l < "${checksums_path}")" -ne 2 ]]; then echo "Expected exactly two checksums for ${TARGET} in ${checksums_path}" >&2 diff --git a/.github/scripts/build-codex-package-archive.sh b/.github/scripts/build-codex-package-archive.sh index 80da4cf20c..5559562566 100644 --- a/.github/scripts/build-codex-package-archive.sh +++ b/.github/scripts/build-codex-package-archive.sh @@ -8,6 +8,7 @@ Usage: build-codex-package-archive.sh \ --bundle \ --entrypoint-dir \ --archive-dir \ + [--code-mode-host-bin ] \ [--bwrap-bin ] \ [--codex-command-runner-bin ] \ [--codex-windows-sandbox-setup-bin ] \ @@ -19,6 +20,7 @@ target="" bundle="" entrypoint_dir="" archive_dir="" +code_mode_host_bin="" target_suffixed_entrypoint="false" resource_args=() bwrap_bin_provided="false" @@ -43,6 +45,10 @@ while [[ $# -gt 0 ]]; do archive_dir="${2:?--archive-dir requires a value}" shift 2 ;; + --code-mode-host-bin) + code_mode_host_bin="${2:?--code-mode-host-bin requires a value}" + shift 2 + ;; --bwrap-bin) resource_args+=(--bwrap-bin "${2:?--bwrap-bin requires a value}") bwrap_bin_provided="true" @@ -110,8 +116,18 @@ case "$target" in esac entrypoint_name="$entrypoint" +code_mode_host_name="codex-code-mode-host" if [[ "$target_suffixed_entrypoint" == "true" ]]; then entrypoint_name="${entrypoint_name}-${target}" + code_mode_host_name="${code_mode_host_name}-${target}" +fi + +if [[ -z "$code_mode_host_bin" ]]; then + code_mode_host_bin="${entrypoint_dir%/}/${code_mode_host_name}${exe_suffix}" +fi +if [[ ! -f "$code_mode_host_bin" ]]; then + echo "Code-mode host binary ${code_mode_host_bin} not found" >&2 + exit 1 fi case "$target" in @@ -159,6 +175,7 @@ python_args=( --target "$target" --variant "$variant" --entrypoint-bin "${entrypoint_dir%/}/${entrypoint_name}${exe_suffix}" + --code-mode-host-bin "$code_mode_host_bin" --cargo-profile release --package-dir "$package_dir" --archive-output "$gzip_archive_path" diff --git a/.github/workflows/rust-ci-full-nextest-platform.yml b/.github/workflows/rust-ci-full-nextest-platform.yml index 65d1fb2be5..5658e2e6d5 100644 --- a/.github/workflows/rust-ci-full-nextest-platform.yml +++ b/.github/workflows/rust-ci-full-nextest-platform.yml @@ -104,6 +104,13 @@ jobs: with: target: ${{ inputs.target }} + - name: Configure rusty_v8 artifact overrides and verify checksums + if: ${{ runner.os != 'Windows' }} + uses: ./.github/actions/setup-rusty-v8 + with: + sandbox: "true" + target: ${{ inputs.target }} + - name: Compute lockfile hash id: lockhash shell: bash @@ -199,13 +206,23 @@ jobs: --archive-file "${archive_dir}/${NEXTEST_ARCHIVE_FILE}" - name: Build runtime test helpers - if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} shell: bash run: | set -euo pipefail helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" mkdir -p "${helper_dir}" + host_name="codex-code-mode-host" + if [[ "${RUNNER_OS}" == "Windows" ]]; then + host_name="${host_name}.exe" + fi + cargo build \ + --target ${{ inputs.target }} \ + --profile ${{ inputs.profile }} \ + -p codex-code-mode-host \ + --bin codex-code-mode-host + cp "target/${{ inputs.target }}/${{ inputs.profile }}/${host_name}" "${helper_dir}/" + if [[ "${RUNNER_OS}" == "Linux" ]]; then cargo build \ --target ${{ inputs.target }} \ @@ -213,7 +230,7 @@ jobs: -p codex-linux-sandbox \ --bin codex-linux-sandbox cp "target/${{ inputs.target }}/${{ inputs.profile }}/codex-linux-sandbox" "${helper_dir}/" - else + elif [[ "${RUNNER_OS}" == "Windows" ]]; then cargo build \ --target ${{ inputs.target }} \ --profile ${{ inputs.profile }} \ @@ -241,7 +258,6 @@ jobs: retention-days: 1 - name: Upload runtime test helpers - if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ env.TEST_HELPERS_ARTIFACT }} @@ -355,7 +371,6 @@ jobs: path: ${{ runner.temp }}/nextest-archive - name: Download runtime test helpers - if: ${{ runner.os == 'Linux' || runner.os == 'Windows' }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ env.TEST_HELPERS_ARTIFACT }} @@ -374,18 +389,43 @@ jobs: workspace_root="$(cygpath -w "${workspace_root}")" fi + helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" + helper_target_dir="$(pwd)/target/${{ inputs.target }}/${{ inputs.profile }}" + mkdir -p "${helper_target_dir}" + host_name="codex-code-mode-host" + if [[ "${RUNNER_OS}" == "Windows" ]]; then + host_name="${host_name}.exe" + fi + cp "${helper_dir}/${host_name}" "${helper_target_dir}/" + + host_path="${helper_target_dir}/${host_name}" + if [[ "${RUNNER_OS}" == "Windows" ]]; then + host_path="$(cygpath -w "${host_path}")" + else + chmod +x "${host_path}" + fi + + test_env=( + "CARGO_BIN_EXE_codex-code-mode-host=${host_path}" + "CARGO_BIN_EXE_codex_code_mode_host=${host_path}" + ) if [[ "${RUNNER_OS}" == "Linux" ]]; then - helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" - helper_target_dir="$(pwd)/target/${{ inputs.target }}/${{ inputs.profile }}" - mkdir -p "${helper_target_dir}" cp "${helper_dir}/codex-linux-sandbox" "${helper_target_dir}/" chmod +x "${helper_target_dir}/codex-linux-sandbox" + sandbox_helper="${helper_target_dir}/codex-linux-sandbox" + test_env+=( + "CARGO_BIN_EXE_codex-linux-sandbox=${sandbox_helper}" + "CARGO_BIN_EXE_codex_linux_sandbox=${sandbox_helper}" + ) elif [[ "${RUNNER_OS}" == "Windows" ]]; then - helper_dir="${RUNNER_TEMP}/${TEST_HELPERS_ARTIFACT}" - helper_target_dir="$(pwd)/target/${{ inputs.target }}/${{ inputs.profile }}" - mkdir -p "${helper_target_dir}" cp "${helper_dir}/codex-windows-sandbox-setup.exe" "${helper_target_dir}/" cp "${helper_dir}/codex-command-runner.exe" "${helper_target_dir}/" + setup_helper="$(cygpath -w "${helper_target_dir}/codex-windows-sandbox-setup.exe")" + command_runner="$(cygpath -w "${helper_target_dir}/codex-command-runner.exe")" + test_env+=( + "CARGO_BIN_EXE_codex_windows_sandbox_setup=${setup_helper}" + "CARGO_BIN_EXE_codex_command_runner=${command_runner}" + ) fi nextest_args=( @@ -399,27 +439,7 @@ jobs: nextest_args+=(--test-threads "${{ inputs.test_threads }}") fi - test_command=(cargo nextest "${nextest_args[@]}") - if [[ "${RUNNER_OS}" == "Linux" ]]; then - sandbox_helper="${helper_target_dir}/codex-linux-sandbox" - test_command=( - env - "CARGO_BIN_EXE_codex-linux-sandbox=${sandbox_helper}" - "CARGO_BIN_EXE_codex_linux_sandbox=${sandbox_helper}" - cargo nextest "${nextest_args[@]}" - ) - elif [[ "${RUNNER_OS}" == "Windows" ]]; then - setup_helper="$(cygpath -w "${helper_target_dir}/codex-windows-sandbox-setup.exe")" - command_runner="$(cygpath -w "${helper_target_dir}/codex-command-runner.exe")" - test_command=( - env - "CARGO_BIN_EXE_codex_windows_sandbox_setup=${setup_helper}" - "CARGO_BIN_EXE_codex_command_runner=${command_runner}" - cargo nextest "${nextest_args[@]}" - ) - fi - - "${test_command[@]}" + env "${test_env[@]}" cargo nextest "${nextest_args[@]}" env: RUST_BACKTRACE: 1 RUST_MIN_STACK: "8388608" # 8 MiB diff --git a/.github/workflows/rust-ci-full.yml b/.github/workflows/rust-ci-full.yml index 7ad1d4b3ad..0b8b2ed031 100644 --- a/.github/workflows/rust-ci-full.yml +++ b/.github/workflows/rust-ci-full.yml @@ -382,6 +382,7 @@ jobs: name: Configure rusty_v8 artifact overrides and verify checksums uses: ./.github/actions/setup-rusty-v8 with: + sandbox: "true" target: ${{ matrix.target }} - name: Install cargo-chef diff --git a/.github/workflows/rust-release-windows.yml b/.github/workflows/rust-release-windows.yml index 7069b6ca8f..5770d08c1c 100644 --- a/.github/workflows/rust-release-windows.yml +++ b/.github/workflows/rust-release-windows.yml @@ -42,14 +42,14 @@ jobs: - runner: windows-x64 target: x86_64-pc-windows-msvc bundle: helpers - binaries: "codex-windows-sandbox-setup codex-command-runner" + binaries: "codex-windows-sandbox-setup codex-command-runner codex-code-mode-host" runs_on: group: ${{ github.event.repository.name }}-runners labels: ${{ github.event.repository.name }}-windows-x64 - runner: windows-arm64 target: aarch64-pc-windows-msvc bundle: helpers - binaries: "codex-windows-sandbox-setup codex-command-runner" + binaries: "codex-windows-sandbox-setup codex-command-runner codex-code-mode-host" runs_on: group: ${{ github.event.repository.name }}-runners labels: ${{ github.event.repository.name }}-windows-arm64 @@ -201,6 +201,9 @@ jobs: defaults: run: working-directory: codex-rs + env: + WINDOWS_BINARIES: "codex codex-responses-api-proxy codex-windows-sandbox-setup codex-command-runner codex-code-mode-host codex-app-server" + strategy: fail-fast: false matrix: @@ -382,16 +385,18 @@ jobs: bundle_dir="$(mktemp -d)" runner_src="$dest/codex-command-runner-${target}.exe" setup_src="$dest/codex-windows-sandbox-setup-${target}.exe" - if [[ -f "$runner_src" && -f "$setup_src" ]]; then + code_mode_host_src="$dest/codex-code-mode-host-${target}.exe" + if [[ -f "$runner_src" && -f "$setup_src" && -f "$code_mode_host_src" ]]; then cp "$dest/$base" "$bundle_dir/$base" cp "$runner_src" "$bundle_dir/codex-command-runner.exe" cp "$setup_src" "$bundle_dir/codex-windows-sandbox-setup.exe" + cp "$code_mode_host_src" "$bundle_dir/codex-code-mode-host.exe" # Use an absolute path so bundle zips land in the real dist # dir even when 7z runs from a temp directory. (cd "$bundle_dir" && 7z a "$repo_root/$dest/${base}.zip" .) else - echo "warning: missing sandbox binaries; falling back to single-binary zip" - echo "warning: expected $runner_src and $setup_src" + echo "warning: missing bundled binaries; falling back to single-binary zip" + echo "warning: expected $runner_src, $setup_src, and $code_mode_host_src" (cd "$dest" && 7z a "${base}.zip" "$base") fi rm -rf "$bundle_dir" diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml index a2646e3eae..9d4f325e55 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-release.yml @@ -80,50 +80,50 @@ jobs: target: aarch64-apple-darwin bundle: primary artifact_name: aarch64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" build_dmg: "true" - runner: macos-15-xlarge target: aarch64-apple-darwin bundle: app-server artifact_name: aarch64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" - runner: macos-15-xlarge target: x86_64-apple-darwin bundle: primary artifact_name: x86_64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" build_dmg: "true" - runner: macos-15-xlarge target: x86_64-apple-darwin bundle: app-server artifact_name: x86_64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" # Release artifacts intentionally ship MUSL-linked Linux binaries. - runner: ${{ github.event.repository.name }}-linux-x64-xl target: x86_64-unknown-linux-musl bundle: primary artifact_name: x86_64-unknown-linux-musl - binaries: "codex codex-responses-api-proxy bwrap" + binaries: "codex codex-responses-api-proxy codex-code-mode-host bwrap" build_dmg: "false" - runner: ${{ github.event.repository.name }}-linux-x64-xl target: x86_64-unknown-linux-musl bundle: app-server artifact_name: x86_64-unknown-linux-musl-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" - runner: ${{ github.event.repository.name }}-linux-arm64 target: aarch64-unknown-linux-musl bundle: primary artifact_name: aarch64-unknown-linux-musl - binaries: "codex codex-responses-api-proxy bwrap" + binaries: "codex codex-responses-api-proxy codex-code-mode-host bwrap" build_dmg: "false" - runner: ${{ github.event.repository.name }}-linux-arm64 target: aarch64-unknown-linux-musl bundle: app-server artifact_name: aarch64-unknown-linux-musl-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" steps: @@ -208,6 +208,7 @@ jobs: - name: Configure rusty_v8 artifact overrides and verify checksums uses: ./.github/actions/setup-rusty-v8 with: + sandbox: "true" target: ${{ matrix.target }} - if: ${{ contains(matrix.target, 'linux') }} @@ -344,9 +345,15 @@ jobs: rm -rf "$bundle_root" mkdir -p "$bundle_root/codex-resources" cp "$dest/codex-${{ matrix.target }}" "$bundle_root/codex" + cp "$dest/codex-code-mode-host-${{ matrix.target }}" \ + "$bundle_root/codex-code-mode-host" cp "$dest/bwrap-${{ matrix.target }}" "$bundle_root/codex-resources/bwrap" - chmod 0755 "$bundle_root/codex" "$bundle_root/codex-resources/bwrap" - tar -C "$bundle_root" -cf - codex codex-resources/bwrap | + chmod 0755 \ + "$bundle_root/codex" \ + "$bundle_root/codex-code-mode-host" \ + "$bundle_root/codex-resources/bwrap" + tar -C "$bundle_root" -cf - \ + codex codex-code-mode-host codex-resources/bwrap | zstd -T0 -19 -o "$dest/codex-${{ matrix.target }}-bundle.tar.zst" fi @@ -484,19 +491,19 @@ jobs: - target: aarch64-apple-darwin bundle: primary artifact_name: aarch64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" - target: aarch64-apple-darwin bundle: app-server artifact_name: aarch64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" - target: x86_64-apple-darwin bundle: primary artifact_name: x86_64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" - target: x86_64-apple-darwin bundle: app-server artifact_name: x86_64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -602,22 +609,22 @@ jobs: - target: aarch64-apple-darwin bundle: primary artifact_name: aarch64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" build_dmg: "true" - target: aarch64-apple-darwin bundle: app-server artifact_name: aarch64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" - target: x86_64-apple-darwin bundle: primary artifact_name: x86_64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" build_dmg: "true" - target: x86_64-apple-darwin bundle: app-server artifact_name: x86_64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" build_dmg: "false" steps: @@ -889,22 +896,22 @@ jobs: - target: aarch64-apple-darwin bundle: primary artifact_name: aarch64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" verify_dmg: "true" - target: aarch64-apple-darwin bundle: app-server artifact_name: aarch64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" verify_dmg: "false" - target: x86_64-apple-darwin bundle: primary artifact_name: x86_64-apple-darwin - binaries: "codex codex-responses-api-proxy" + binaries: "codex codex-responses-api-proxy codex-code-mode-host" verify_dmg: "true" - target: x86_64-apple-darwin bundle: app-server artifact_name: x86_64-apple-darwin-app-server - binaries: "codex-app-server" + binaries: "codex-app-server codex-code-mode-host" verify_dmg: "false" steps: @@ -992,6 +999,7 @@ jobs: mkdir -p "$package_dir" tar -xzf "${packaged_dir}/${package_stem}-${target}.tar.gz" -C "$package_dir" verify_signed_binary "${package_dir}/bin/${package_entrypoint}" + verify_signed_binary "${package_dir}/bin/codex-code-mode-host" if [[ "${{ matrix.verify_dmg }}" != "true" ]]; then exit 0 diff --git a/BUILD.bazel b/BUILD.bazel index a82126e6f1..3f5d4f3f33 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -71,6 +71,8 @@ alias( exports_files([ "AGENTS.md", + "runfile_env_binary_launcher.bat.tpl", + "runfile_env_binary_launcher.sh.tpl", "workspace_root_test_launcher.bat.tpl", "workspace_root_test_launcher.sh.tpl", ]) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 2dae185061..7c24c3dc9b 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2531,6 +2531,7 @@ dependencies = [ "serde_json", "tokio", "tokio-util", + "v8", ] [[package]] diff --git a/codex-rs/cli/BUILD.bazel b/codex-rs/cli/BUILD.bazel index 97c868845b..c7671f92a5 100644 --- a/codex-rs/cli/BUILD.bazel +++ b/codex-rs/cli/BUILD.bazel @@ -1,4 +1,4 @@ -load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate") +load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate", "runfile_env_binary") load("//bazel/platforms:release_binaries.bzl", "multiplatform_binaries") codex_rust_crate( @@ -13,3 +13,11 @@ codex_rust_crate( multiplatform_binaries( name = "codex", ) + +runfile_env_binary( + name = "codex-with-code-mode", + binary = ":codex", + runfile_env = { + "//codex-rs/code-mode-host:codex-code-mode-host": "CODEX_CODE_MODE_HOST_PATH", + }, +) diff --git a/codex-rs/code-mode-host/BUILD.bazel b/codex-rs/code-mode-host/BUILD.bazel index c1245e21a8..124f32fef5 100644 --- a/codex-rs/code-mode-host/BUILD.bazel +++ b/codex-rs/code-mode-host/BUILD.bazel @@ -3,4 +3,5 @@ load("//:defs.bzl", "codex_rust_crate") codex_rust_crate( name = "code-mode-host", crate_name = "codex_code_mode_host", + crate_srcs = [], ) diff --git a/codex-rs/code-mode-host/Cargo.toml b/codex-rs/code-mode-host/Cargo.toml index 6aed00ba5a..10c3e9aae5 100644 --- a/codex-rs/code-mode-host/Cargo.toml +++ b/codex-rs/code-mode-host/Cargo.toml @@ -17,9 +17,17 @@ codex-code-mode-protocol = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = ["io-std", "io-util", "macros", "process", "rt-multi-thread", "sync", "time"] } tokio-util = { workspace = true, features = ["rt"] } +# The host owns V8 process configuration, so select the sandboxed V8 build at +# the executable boundary without adding a workspace-crate feature gate. +v8 = { workspace = true, features = ["v8_enable_sandbox"] } [dev-dependencies] codex-code-mode-client = { workspace = true } codex-protocol = { workspace = true } codex-utils-cargo-bin = { workspace = true } pretty_assertions = { workspace = true } + +[package.metadata.cargo-shear] +# This direct dependency intentionally selects the V8 sandbox feature for the +# host without activating an internal workspace-crate feature. +ignored = ["v8"] diff --git a/codex-rs/v8-poc/src/lib.rs b/codex-rs/v8-poc/src/lib.rs index 5103cdeb39..41a633a441 100644 --- a/codex-rs/v8-poc/src/lib.rs +++ b/codex-rs/v8-poc/src/lib.rs @@ -64,9 +64,10 @@ mod tests { assert!(!super::embedded_v8_version().is_empty()); } + #[cfg(feature = "sandbox")] #[test] - fn sandbox_feature_matches_linked_v8() { - assert_eq!(super::linked_v8_has_sandbox(), cfg!(feature = "sandbox")); + fn sandbox_feature_enables_linked_v8_sandbox() { + assert!(super::linked_v8_has_sandbox()); } #[test] diff --git a/defs.bzl b/defs.bzl index d49b06c267..8a46efc742 100644 --- a/defs.bzl +++ b/defs.bzl @@ -138,6 +138,66 @@ def _windows_workspace_root_setup(ctx): return """set "INSTA_WORKSPACE_ROOT=%workspace_root%" cd /d "%workspace_root%" || exit /b 1""" +def _runfile_env_binary_impl(ctx): + is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]) + launcher = ctx.actions.declare_file(ctx.label.name + ".bat" if is_windows else ctx.label.name) + binary = ctx.executable.binary + launcher_template = ctx.file._windows_launcher_template if is_windows else ctx.file._bash_launcher_template + runfile_env_exports = _windows_runfile_env_exports(ctx) if is_windows else _bash_runfile_env_exports(ctx) + ctx.actions.expand_template( + template = launcher_template, + output = launcher, + is_executable = True, + substitutions = { + "__BINARY__": binary.short_path, + "__RUNFILE_ENV_EXPORTS__": runfile_env_exports, + "__WORKSPACE_NAME__": ctx.workspace_name, + }, + ) + + runfiles = ctx.runfiles(files = [binary]).merge(ctx.attr.binary[DefaultInfo].default_runfiles) + for runfile_dep in ctx.attr.runfile_env: + executable = runfile_dep[DefaultInfo].files_to_run.executable + if executable == None: + fail("{} does not provide an executable for runfile_env".format(runfile_dep.label)) + runfiles = runfiles.merge(ctx.runfiles(files = [executable])) + runfiles = runfiles.merge(runfile_dep[DefaultInfo].default_runfiles) + + return [DefaultInfo( + executable = launcher, + files = depset([launcher]), + runfiles = runfiles, + )] + +runfile_env_binary = rule( + implementation = _runfile_env_binary_impl, + executable = True, + toolchains = ["@bazel_tools//tools/test:default_test_toolchain_type"], + attrs = { + "binary": attr.label( + cfg = "target", + executable = True, + mandatory = True, + ), + "runfile_env": attr.label_keyed_string_dict( + cfg = "target", + ), + "_windows_constraint": attr.label( + default = "@platforms//os:windows", + providers = [platform_common.ConstraintValueInfo], + ), + "_bash_launcher_template": attr.label( + allow_single_file = True, + default = "//:runfile_env_binary_launcher.sh.tpl", + ), + "_windows_launcher_template": attr.label( + allow_single_file = True, + default = "//:runfile_env_binary_launcher.bat.tpl", + ), + }, + doc = "Runs a binary with environment variables resolved from executable runfiles.", +) + workspace_root_test = rule( implementation = _workspace_root_test_impl, test = True, @@ -285,7 +345,7 @@ def codex_rust_crate( binaries = DEP_DATA.get(native.package_name())["binaries"] - lib_srcs = crate_srcs or native.glob(["src/**/*.rs"], exclude = binaries.values(), allow_empty = True) + lib_srcs = native.glob(["src/**/*.rs"], exclude = binaries.values(), allow_empty = True) if crate_srcs == None else crate_srcs maybe_deps = [] diff --git a/justfile b/justfile index 560fb1c22e..c5c2b3feb4 100644 --- a/justfile +++ b/justfile @@ -75,11 +75,11 @@ install: # there should be no need to add `--all-features`. [unix] test *args: - RUST_MIN_STACK={{ rust_min_stack }} NEXTEST_PROFILE=local cargo nextest run --no-fail-fast "$@" + RUST_MIN_STACK={{ rust_min_stack }} NEXTEST_PROFILE=local {{ python }} ../scripts/run-nextest.py "$@" [windows] test *args: - $env:RUST_MIN_STACK = "{{ rust_min_stack }}"; $env:NEXTEST_PROFILE = "local"; cargo nextest run --no-fail-fast @($args | Select-Object -Skip 1) + $env:RUST_MIN_STACK = "{{ rust_min_stack }}"; $env:NEXTEST_PROFILE = "local"; {{ python }} ../scripts/run-nextest.py @($args | Select-Object -Skip 1) # Run from the repository root so scripts that resolve paths from `cwd` see # the same layout they use in GitHub Actions. @@ -96,16 +96,18 @@ bench-smoke: just bench -- --test # Build and run Codex from source using Bazel. +# The launcher target also builds the code-mode host and injects its runfile +# path, so Bazel can rebuild either binary incrementally. # On Unix, use `[no-cd]` and `--run_under="cd $PWD &&"` to ensure Bazel runs # the command in the current working directory. [no-cd] [unix] bazel-codex *args: - bazel run //codex-rs/cli:codex --run_under="cd $PWD &&" -- "$@" + bazel run //codex-rs/cli:codex-with-code-mode --run_under="cd $PWD &&" -- "$@" [windows] bazel-codex *args: - bazel run //codex-rs/cli:codex --run_under='cd /d "{{ invocation_directory_native() }}" &&' -- @($args | Select-Object -Skip 1) + bazel run //codex-rs/cli:codex-with-code-mode --run_under='cd /d "{{ invocation_directory_native() }}" &&' -- @($args | Select-Object -Skip 1) [no-cd] bazel-lock-update: diff --git a/runfile_env_binary_launcher.bat.tpl b/runfile_env_binary_launcher.bat.tpl new file mode 100644 index 0000000000..2d322e5677 --- /dev/null +++ b/runfile_env_binary_launcher.bat.tpl @@ -0,0 +1,51 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +call :resolve_runfile binary "__BINARY__" +if errorlevel 1 exit /b 1 + +__RUNFILE_ENV_EXPORTS__ + +"%binary%" %* +exit /b %ERRORLEVEL% + +:resolve_runfile +setlocal EnableExtensions EnableDelayedExpansion +set "logical_path=%~2" +set "native_logical_path=%logical_path:/=\%" +set "workspace_name=__WORKSPACE_NAME__" + +for %%R in ("%RUNFILES_DIR%" "%TEST_SRCDIR%" "%~f0.runfiles") do ( + set "runfiles_root=%%~R" + if defined runfiles_root ( + for %%P in ("!native_logical_path!" "%TEST_WORKSPACE%\!native_logical_path!" "!workspace_name!\!native_logical_path!" "_main\!native_logical_path!") do ( + if exist "!runfiles_root!\%%~P" ( + endlocal & set "%~1=!runfiles_root!\%%~P" & exit /b 0 + ) + ) + ) +) + +set "manifest=%RUNFILES_MANIFEST_FILE%" +if not defined manifest if exist "%~f0.runfiles_manifest" set "manifest=%~f0.runfiles_manifest" +if not defined manifest if exist "%~f0.exe.runfiles_manifest" set "manifest=%~f0.exe.runfiles_manifest" + +if defined manifest if exist "%manifest%" ( + for /f "usebackq tokens=1,* delims= " %%A in ("%manifest%") do ( + if "%%A"=="%logical_path%" ( + endlocal & set "%~1=%%B" & exit /b 0 + ) + if "%%A"=="%TEST_WORKSPACE%/%logical_path%" ( + endlocal & set "%~1=%%B" & exit /b 0 + ) + if "%%A"=="%workspace_name%/%logical_path%" ( + endlocal & set "%~1=%%B" & exit /b 0 + ) + if "%%A"=="_main/%logical_path%" ( + endlocal & set "%~1=%%B" & exit /b 0 + ) + ) +) + +>&2 echo failed to resolve runfile: %logical_path% +endlocal & exit /b 1 diff --git a/runfile_env_binary_launcher.sh.tpl b/runfile_env_binary_launcher.sh.tpl new file mode 100644 index 0000000000..105118f7f9 --- /dev/null +++ b/runfile_env_binary_launcher.sh.tpl @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +resolve_runfile() { + local logical_path="$1" + local launcher_runfiles="$0.runfiles" + local workspace_name="__WORKSPACE_NAME__" + local runfiles_root + + for runfiles_root in "${RUNFILES_DIR:-}" "${TEST_SRCDIR:-}" "${launcher_runfiles}"; do + if [[ -z "${runfiles_root}" ]]; then + continue + fi + for candidate in \ + "${runfiles_root}/${logical_path}" \ + "${runfiles_root}/${TEST_WORKSPACE:-}/${logical_path}" \ + "${runfiles_root}/${workspace_name}/${logical_path}" \ + "${runfiles_root}/_main/${logical_path}"; do + if [[ -e "${candidate}" ]]; then + printf '%s\n' "${candidate}" + return 0 + fi + done + done + + local manifest="${RUNFILES_MANIFEST_FILE:-}" + if [[ -z "${manifest}" ]]; then + if [[ -f "$0.runfiles_manifest" ]]; then + manifest="$0.runfiles_manifest" + elif [[ -f "$0.exe.runfiles_manifest" ]]; then + manifest="$0.exe.runfiles_manifest" + fi + fi + + if [[ -n "${manifest}" && -f "${manifest}" ]]; then + local resolved + resolved="$(awk -v path="${logical_path}" '$1 == path || substr($1, length($1) - length(path), length(path) + 1) == "/" path { $1 = ""; sub(/^ /, ""); print; exit }' "${manifest}")" + if [[ -n "${resolved}" ]]; then + printf '%s\n' "${resolved}" + return 0 + fi + fi + + echo "failed to resolve runfile: ${logical_path}" >&2 + return 1 +} + +binary="$(resolve_runfile "__BINARY__")" +RUNFILE_ENV_ARGS=() + +__RUNFILE_ENV_EXPORTS__ + +if (( ${#RUNFILE_ENV_ARGS[@]} > 0 )); then + exec env "${RUNFILE_ENV_ARGS[@]}" "${binary}" "$@" +else + exec "${binary}" "$@" +fi diff --git a/scripts/codex_package/README.md b/scripts/codex_package/README.md index 323a3ce5ba..3fe93441d4 100644 --- a/scripts/codex_package/README.md +++ b/scripts/codex_package/README.md @@ -10,7 +10,8 @@ The builder creates a canonical Codex package directory: . ├── codex-package.json ├── bin -│ └── [.exe] +│ ├── [.exe] +│ └── codex-code-mode-host[.exe] ├── codex-resources │ ├── bwrap # Linux only │ ├── zsh/bin/zsh # supported Unix targets only @@ -40,6 +41,7 @@ grouped `cargo build` command per package when they are needed and no prebuilt override was provided: - all targets: the selected entrypoint, unless `--entrypoint-bin` is provided +- all targets: `codex-code-mode-host`, unless `--code-mode-host-bin` is provided - Linux targets: `bwrap`, unless `--bwrap-bin` is provided - Windows targets: `codex-command-runner` and `codex-windows-sandbox-setup`, unless the corresponding prebuilt helper flags are provided diff --git a/scripts/codex_package/cargo.py b/scripts/codex_package/cargo.py index 208d85d174..f2dbe6c774 100644 --- a/scripts/codex_package/cargo.py +++ b/scripts/codex_package/cargo.py @@ -17,6 +17,7 @@ CODEX_RS_ROOT = REPO_ROOT / "codex-rs" @dataclass(frozen=True) class SourceBuildOutputs: entrypoint_bin: Path + code_mode_host_bin: Path bwrap_bin: Path | None codex_command_runner_bin: Path | None codex_windows_sandbox_setup_bin: Path | None @@ -29,6 +30,7 @@ def build_source_binaries( cargo: str, profile: str, entrypoint_bin: Path | None, + code_mode_host_bin: Path | None, bwrap_bin: Path | None, codex_command_runner_bin: Path | None, codex_windows_sandbox_setup_bin: Path | None, @@ -43,6 +45,7 @@ def build_source_binaries( spec, variant, build_entrypoint=entrypoint_bin is None, + build_code_mode_host=code_mode_host_bin is None, build_bwrap=spec.is_linux and bwrap_bin is None, build_codex_command_runner=spec.is_windows and codex_command_runner_bin is None, build_codex_windows_sandbox_setup=spec.is_windows @@ -61,7 +64,7 @@ def build_source_binaries( cmd.extend(["--bin", binary]) cargo_env = None - if entrypoint_bin is None: + if entrypoint_bin is None or code_mode_host_bin is None: codex_v8_env = resolve_codex_v8_cargo_env(spec) if codex_v8_env: cargo_env = {**os.environ, **codex_v8_env} @@ -80,6 +83,10 @@ def build_source_binaries( entrypoint_bin, output_dir / variant.entrypoint_name(spec), ), + code_mode_host_bin=resolve_output_path( + code_mode_host_bin, + output_dir / f"codex-code-mode-host{spec.exe_suffix}", + ), bwrap_bin=resolve_output_path( bwrap_bin, output_dir / "bwrap" if spec.is_linux else None, @@ -102,6 +109,7 @@ def source_binaries_for_target( variant: PackageVariant, *, build_entrypoint: bool, + build_code_mode_host: bool, build_bwrap: bool, build_codex_command_runner: bool, build_codex_windows_sandbox_setup: bool, @@ -109,6 +117,8 @@ def source_binaries_for_target( binaries = [] if build_entrypoint: binaries.append(variant.cargo_bin) + if build_code_mode_host: + binaries.append("codex-code-mode-host") if build_bwrap: binaries.append("bwrap") if build_codex_command_runner: @@ -174,6 +184,7 @@ def cargo_profile_dirname(profile: str) -> str: def validate_source_outputs(outputs: SourceBuildOutputs) -> None: for path in [ outputs.entrypoint_bin, + outputs.code_mode_host_bin, outputs.bwrap_bin, outputs.codex_command_runner_bin, outputs.codex_windows_sandbox_setup_bin, diff --git a/scripts/codex_package/cli.py b/scripts/codex_package/cli.py index b7d919e4ff..d3c6fafe33 100644 --- a/scripts/codex_package/cli.py +++ b/scripts/codex_package/cli.py @@ -82,6 +82,14 @@ def parse_args() -> argparse.Namespace: "variant. If omitted, the entrypoint is built with Cargo." ), ) + parser.add_argument( + "--code-mode-host-bin", + type=Path, + help=( + "Optional prebuilt codex-code-mode-host executable. If omitted, " + "codex-code-mode-host is built with Cargo." + ), + ) parser.add_argument( "--bwrap-bin", type=Path, @@ -140,6 +148,11 @@ def main() -> int: "prebuilt entrypoint executable", "--entrypoint-bin", ), + code_mode_host_bin=resolve_optional_input_path( + args.code_mode_host_bin, + "prebuilt code-mode host executable", + "--code-mode-host-bin", + ), bwrap_bin=resolve_optional_input_path( args.bwrap_bin, "prebuilt Linux bwrap executable", @@ -159,6 +172,7 @@ def main() -> int: version = read_workspace_version() inputs = PackageInputs( entrypoint_bin=source_outputs.entrypoint_bin, + code_mode_host_bin=source_outputs.code_mode_host_bin, rg_bin=resolve_rg_bin(spec, args.rg_bin), zsh_bin=resolve_zsh_bin(spec), bwrap_bin=source_outputs.bwrap_bin, diff --git a/scripts/codex_package/layout.py b/scripts/codex_package/layout.py index 63598672ea..131de5f5bc 100644 --- a/scripts/codex_package/layout.py +++ b/scripts/codex_package/layout.py @@ -51,6 +51,11 @@ def build_package_dir( bin_dir / entrypoint_name, is_windows=spec.is_windows, ) + copy_executable( + inputs.code_mode_host_bin, + bin_dir / f"codex-code-mode-host{spec.exe_suffix}", + is_windows=spec.is_windows, + ) copy_executable(inputs.rg_bin, path_dir / spec.rg_name, is_windows=spec.is_windows) if inputs.zsh_bin is not None: @@ -83,6 +88,7 @@ def build_package_dir( "target": spec.target, "variant": variant.name, "entrypoint": f"bin/{entrypoint_name}", + "codeModeHost": f"bin/codex-code-mode-host{spec.exe_suffix}", "resourcesDir": "codex-resources", "pathDir": "codex-path", } @@ -118,6 +124,7 @@ def validate_package_dir( "target": spec.target, "variant": variant.name, "entrypoint": f"bin/{variant.entrypoint_name(spec)}", + "codeModeHost": f"bin/codex-code-mode-host{spec.exe_suffix}", "resourcesDir": "codex-resources", "pathDir": "codex-path", } @@ -130,6 +137,7 @@ def validate_package_dir( required_files = [ Path("bin") / variant.entrypoint_name(spec), + Path("bin") / f"codex-code-mode-host{spec.exe_suffix}", Path("codex-path") / spec.rg_name, ] executable_files = list(required_files) diff --git a/scripts/codex_package/targets.py b/scripts/codex_package/targets.py index 8307a3e630..016202cf5f 100644 --- a/scripts/codex_package/targets.py +++ b/scripts/codex_package/targets.py @@ -39,6 +39,7 @@ class PackageVariant: @dataclass(frozen=True) class PackageInputs: entrypoint_bin: Path + code_mode_host_bin: Path rg_bin: Path zsh_bin: Path | None bwrap_bin: Path | None diff --git a/scripts/codex_package/test_cargo.py b/scripts/codex_package/test_cargo.py index 6185f8b8b3..6f2df7a3ff 100644 --- a/scripts/codex_package/test_cargo.py +++ b/scripts/codex_package/test_cargo.py @@ -20,6 +20,7 @@ class SourceBinariesForTargetTest(unittest.TestCase): TARGET_SPECS["aarch64-apple-darwin"], PACKAGE_VARIANTS["codex"], build_entrypoint=False, + build_code_mode_host=False, build_bwrap=False, build_codex_command_runner=False, build_codex_windows_sandbox_setup=False, @@ -35,6 +36,7 @@ class SourceBinariesForTargetTest(unittest.TestCase): TARGET_SPECS["x86_64-unknown-linux-musl"], PACKAGE_VARIANTS["codex"], build_entrypoint=False, + build_code_mode_host=False, build_bwrap=False, build_codex_command_runner=False, build_codex_windows_sandbox_setup=False, @@ -50,6 +52,7 @@ class SourceBinariesForTargetTest(unittest.TestCase): TARGET_SPECS["x86_64-pc-windows-msvc"], PACKAGE_VARIANTS["codex"], build_entrypoint=False, + build_code_mode_host=False, build_bwrap=False, build_codex_command_runner=False, build_codex_windows_sandbox_setup=False, @@ -63,6 +66,7 @@ class SourceBinariesForTargetTest(unittest.TestCase): TARGET_SPECS["x86_64-pc-windows-msvc"], PACKAGE_VARIANTS["codex"], build_entrypoint=False, + build_code_mode_host=False, build_bwrap=False, build_codex_command_runner=True, build_codex_windows_sandbox_setup=True, @@ -70,10 +74,25 @@ class SourceBinariesForTargetTest(unittest.TestCase): ["codex-command-runner", "codex-windows-sandbox-setup"], ) + def test_missing_code_mode_host_is_built(self) -> None: + self.assertEqual( + source_binaries_for_target( + TARGET_SPECS["x86_64-unknown-linux-musl"], + PACKAGE_VARIANTS["codex"], + build_entrypoint=False, + build_code_mode_host=True, + build_bwrap=False, + build_codex_command_runner=False, + build_codex_windows_sandbox_setup=False, + ), + ["codex-code-mode-host"], + ) + def test_build_uses_prebuilt_windows_helpers_without_running_cargo(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir) entrypoint = touch_file(root / "codex.exe") + code_mode_host = touch_file(root / "codex-code-mode-host.exe") command_runner = touch_file(root / "codex-command-runner.exe") sandbox_setup = touch_file(root / "codex-windows-sandbox-setup.exe") @@ -83,12 +102,14 @@ class SourceBinariesForTargetTest(unittest.TestCase): cargo=str(root / "cargo-that-should-not-run"), profile="release", entrypoint_bin=entrypoint, + code_mode_host_bin=code_mode_host, bwrap_bin=None, codex_command_runner_bin=command_runner, codex_windows_sandbox_setup_bin=sandbox_setup, ) self.assertEqual(outputs.entrypoint_bin, entrypoint) + self.assertEqual(outputs.code_mode_host_bin, code_mode_host) self.assertEqual(outputs.codex_command_runner_bin, command_runner) self.assertEqual(outputs.codex_windows_sandbox_setup_bin, sandbox_setup) diff --git a/scripts/codex_package/v8.py b/scripts/codex_package/v8.py index 4033e6822f..16c9a740a9 100644 --- a/scripts/codex_package/v8.py +++ b/scripts/codex_package/v8.py @@ -16,6 +16,7 @@ from .targets import TargetSpec DOWNLOAD_TIMEOUT_SECS = 120 +ARTIFACT_PROFILE = "ptrcomp_sandbox_release" @dataclass(frozen=True) @@ -70,9 +71,9 @@ def fetch_codex_v8_artifacts( ) target = spec.target cache_dir = (cache_root or default_cache_root()) / f"rusty-v8-{version}-{target}" - archive = cache_dir / f"librusty_v8_release_{target}.a.gz" - binding = cache_dir / f"src_binding_release_{target}.rs" - checksums = cache_dir / f"rusty_v8_release_{target}.sha256" + archive = cache_dir / f"librusty_v8_{ARTIFACT_PROFILE}_{target}.a.gz" + binding = cache_dir / f"src_binding_{ARTIFACT_PROFILE}_{target}.rs" + checksums = cache_dir / f"rusty_v8_{ARTIFACT_PROFILE}_{target}.sha256" download_file(f"{release_url}/{checksums.name}", checksums) expected_checksums = load_checksums(checksums, {archive.name, binding.name}) diff --git a/scripts/install/install.ps1 b/scripts/install/install.ps1 index 6973d482e2..31aef584f3 100644 --- a/scripts/install/install.ps1 +++ b/scripts/install/install.ps1 @@ -537,6 +537,7 @@ function Test-PackageContentsAreComplete { $expectedFiles = @( "codex-package.json", "bin\codex.exe", + "bin\codex-code-mode-host.exe", "codex-path\rg.exe", "codex-resources\codex-command-runner.exe", "codex-resources\codex-windows-sandbox-setup.exe" diff --git a/scripts/install/install.sh b/scripts/install/install.sh index 7513efc429..e02b6bd2b9 100755 --- a/scripts/install/install.sh +++ b/scripts/install/install.sh @@ -677,7 +677,10 @@ install_package_release() { rm -rf "$stage_release" mkdir -p "$stage_release" tar -xzf "$archive_path" -C "$stage_release" - chmod 0755 "$stage_release/bin/codex" "$stage_release/codex-path/rg" + chmod 0755 \ + "$stage_release/bin/codex" \ + "$stage_release/bin/codex-code-mode-host" \ + "$stage_release/codex-path/rg" if [ -f "$stage_release/codex-resources/bwrap" ]; then chmod 0755 "$stage_release/codex-resources/bwrap" fi @@ -730,6 +733,7 @@ release_dir_is_complete() { package) [ -f "$release_dir/codex-package.json" ] && [ -x "$release_dir/bin/codex" ] && + [ -x "$release_dir/bin/codex-code-mode-host" ] && [ -x "$release_dir/codex" ] && [ -x "$release_dir/codex-path/rg" ] || return 1 diff --git a/scripts/run-nextest.py b/scripts/run-nextest.py new file mode 100644 index 0000000000..6a6d0679ba --- /dev/null +++ b/scripts/run-nextest.py @@ -0,0 +1,65 @@ +"""Build runtime helpers and run the Codex nextest suite.""" + +import os +import subprocess +import sys +from pathlib import Path + + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +from codex_package.targets import REPO_ROOT +from codex_package.targets import TARGET_SPECS +from codex_package.v8 import resolve_codex_v8_cargo_env + + +CODEX_RS_ROOT = REPO_ROOT / "codex-rs" + + +def rustc_host_target() -> str: + rustc = os.environ.get("RUSTC", "rustc") + version = subprocess.run( + [rustc, "-vV"], + check=True, + capture_output=True, + text=True, + ).stdout + for line in version.splitlines(): + if line.startswith("host: "): + return line.removeprefix("host: ") + raise RuntimeError("rustc -vV did not report a host target") + + +def main() -> int: + target = rustc_host_target() + try: + spec = TARGET_SPECS[target] + except KeyError as exc: + raise RuntimeError( + f"unsupported host target for code-mode tests: {target}" + ) from exc + + env = {**os.environ, **resolve_codex_v8_cargo_env(spec)} + cargo = os.environ.get("CARGO", "cargo") + subprocess.run( + [ + cargo, + "build", + "-p", + "codex-code-mode-host", + "--bin", + "codex-code-mode-host", + ], + cwd=CODEX_RS_ROOT, + check=True, + env=env, + ) + return subprocess.run( + [cargo, "nextest", "run", "--no-fail-fast", *sys.argv[1:]], + cwd=CODEX_RS_ROOT, + env=env, + ).returncode + + +if __name__ == "__main__": + raise SystemExit(main())