From 80b70f20b4d3128b812baf64d89159f94ed54267 Mon Sep 17 00:00:00 2001 From: Channing Conger Date: Fri, 12 Jun 2026 04:32:18 +0000 Subject: [PATCH] code-mode: scope IPC test coverage to host --- .../rust-ci-full-nextest-platform.yml | 82 +++++++------------ codex-rs/Cargo.lock | 3 +- codex-rs/app-server/BUILD.bazel | 1 - .../tests/suite/v2/imagegen_extension.rs | 15 +--- codex-rs/code-mode-host/Cargo.toml | 1 + codex-rs/code-mode-host/tests/client.rs | 49 +++++++++++ codex-rs/core/BUILD.bazel | 1 - codex-rs/core/Cargo.toml | 1 - codex-rs/core/src/session/tests.rs | 18 ++-- .../core/src/session/tests/guardian_tests.rs | 4 +- codex-rs/core/tests/common/Cargo.toml | 1 - codex-rs/core/tests/common/test_codex.rs | 10 --- justfile | 4 +- scripts/run-nextest.py | 65 --------------- 14 files changed, 94 insertions(+), 161 deletions(-) create mode 100644 codex-rs/code-mode-host/tests/client.rs delete mode 100644 scripts/run-nextest.py diff --git a/.github/workflows/rust-ci-full-nextest-platform.yml b/.github/workflows/rust-ci-full-nextest-platform.yml index 17bc173965..3fdf7b51ee 100644 --- a/.github/workflows/rust-ci-full-nextest-platform.yml +++ b/.github/workflows/rust-ci-full-nextest-platform.yml @@ -104,13 +104,6 @@ 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 @@ -206,23 +199,13 @@ 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 }} \ @@ -230,7 +213,7 @@ jobs: -p codex-linux-sandbox \ --bin codex-linux-sandbox cp "target/${{ inputs.target }}/${{ inputs.profile }}/codex-linux-sandbox" "${helper_dir}/" - elif [[ "${RUNNER_OS}" == "Windows" ]]; then + else cargo build \ --target ${{ inputs.target }} \ --profile ${{ inputs.profile }} \ @@ -258,6 +241,7 @@ 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 }} @@ -369,6 +353,7 @@ 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 }} @@ -387,43 +372,18 @@ 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=( @@ -437,7 +397,27 @@ jobs: nextest_args+=(--test-threads "${{ inputs.test_threads }}") fi - env "${test_env[@]}" cargo nextest "${nextest_args[@]}" + 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: RUST_BACKTRACE: 1 RUST_MIN_STACK: "8388608" # 8 MiB diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 00505796e3..db1112c3c3 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2505,6 +2505,7 @@ name = "codex-code-mode-host" version = "0.0.0" dependencies = [ "codex-code-mode", + "codex-code-mode-client", "codex-code-mode-protocol", "codex-protocol", "codex-utils-cargo-bin", @@ -2621,7 +2622,6 @@ dependencies = [ "codex-apply-patch", "codex-async-utils", "codex-code-mode", - "codex-code-mode-client", "codex-code-mode-protocol", "codex-config", "codex-connectors", @@ -4626,7 +4626,6 @@ dependencies = [ "assert_cmd", "base64 0.22.1", "codex-arg0", - "codex-code-mode-client", "codex-config", "codex-core", "codex-exec-server", diff --git a/codex-rs/app-server/BUILD.bazel b/codex-rs/app-server/BUILD.bazel index 1dd4fde7a7..6765141bdc 100644 --- a/codex-rs/app-server/BUILD.bazel +++ b/codex-rs/app-server/BUILD.bazel @@ -16,7 +16,6 @@ codex_rust_crate( }, extra_binaries = [ "//codex-rs/bwrap:bwrap", - "//codex-rs/code-mode-host:codex-code-mode-host", ], test_tags = ["no-sandbox"], ) diff --git a/codex-rs/app-server/tests/suite/v2/imagegen_extension.rs b/codex-rs/app-server/tests/suite/v2/imagegen_extension.rs index 3d53e38243..a42222b777 100644 --- a/codex-rs/app-server/tests/suite/v2/imagegen_extension.rs +++ b/codex-rs/app-server/tests/suite/v2/imagegen_extension.rs @@ -290,19 +290,8 @@ generatedImage(result); ChatGptAuthFixture::new("access-chatgpt"), AuthCredentialsStoreMode::File, )?; - let code_mode_host = codex_utils_cargo_bin::cargo_bin("codex-code-mode-host")?; - let code_mode_host = code_mode_host - .to_str() - .context("code-mode host path is not valid UTF-8")?; - - let mut mcp = TestAppServer::new_with_env( - codex_home.path(), - &[ - ("OPENAI_API_KEY", None), - ("CODEX_CODE_MODE_HOST_PATH", Some(code_mode_host)), - ], - ) - .await?; + let mut mcp = + TestAppServer::new_with_env(codex_home.path(), &[("OPENAI_API_KEY", None)]).await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; start_image_generation_turn(&mut mcp).await?; timeout( diff --git a/codex-rs/code-mode-host/Cargo.toml b/codex-rs/code-mode-host/Cargo.toml index b9ded54ae5..9cabcf0b41 100644 --- a/codex-rs/code-mode-host/Cargo.toml +++ b/codex-rs/code-mode-host/Cargo.toml @@ -21,6 +21,7 @@ tokio-util = { workspace = true, features = ["rt"] } 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 } diff --git a/codex-rs/code-mode-host/tests/client.rs b/codex-rs/code-mode-host/tests/client.rs new file mode 100644 index 0000000000..ebe38ab8ca --- /dev/null +++ b/codex-rs/code-mode-host/tests/client.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; + +use codex_code_mode::NoopCodeModeSessionDelegate; +use codex_code_mode_client::CodeModeHostCommand; +use codex_code_mode_client::IpcCodeModeSessionProvider; +use codex_code_mode_protocol::CodeModeSessionProvider; +use codex_code_mode_protocol::ExecuteRequest; +use codex_code_mode_protocol::FunctionCallOutputContentItem; +use codex_code_mode_protocol::RuntimeResponse; +use pretty_assertions::assert_eq; + +#[tokio::test] +async fn client_executes_code_through_host() { + let provider = IpcCodeModeSessionProvider::new(CodeModeHostCommand { + program: codex_utils_cargo_bin::cargo_bin("codex-code-mode-host") + .expect("resolve codex-code-mode-host binary"), + args: Vec::new(), + }); + let session = provider + .create_session(Arc::new(NoopCodeModeSessionDelegate)) + .await + .expect("create code mode session"); + let started = session + .execute(ExecuteRequest { + tool_call_id: "call-1".to_string(), + enabled_tools: Vec::new(), + source: "text('hello')".to_string(), + yield_time_ms: None, + max_output_tokens: None, + }) + .await + .expect("execute code through host"); + let cell_id = started.cell_id.clone(); + + assert_eq!( + started + .initial_response() + .await + .expect("receive initial response"), + RuntimeResponse::Result { + cell_id, + content_items: vec![FunctionCallOutputContentItem::InputText { + text: "hello".to_string(), + }], + error_text: None, + } + ); + session.shutdown().await.expect("shut down session"); +} diff --git a/codex-rs/core/BUILD.bazel b/codex-rs/core/BUILD.bazel index 4fb5ab0725..478699c0a1 100644 --- a/codex-rs/core/BUILD.bazel +++ b/codex-rs/core/BUILD.bazel @@ -41,7 +41,6 @@ codex_rust_crate( unit_test_timeout = "long", extra_binaries = [ "//codex-rs/bwrap:bwrap", - "//codex-rs/code-mode-host:codex-code-mode-host", "//codex-rs/linux-sandbox:codex-linux-sandbox", "//codex-rs/rmcp-client:test_stdio_server", "//codex-rs/rmcp-client:test_streamable_http_server", diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index cf37e1021d..fe8f421463 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -134,7 +134,6 @@ codex-shell-escalation = { workspace = true } [dev-dependencies] assert_cmd = { workspace = true } assert_matches = { workspace = true } -codex-code-mode-client = { workspace = true } codex-image-generation-extension = { workspace = true } codex-home = { workspace = true } codex-otel = { workspace = true } diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 749128eb9c..901d336c8a 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -4835,7 +4835,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() { )), codex_rollout_trace::ThreadTraceContext::disabled(), /*attestation_provider*/ None, - Arc::new(codex_code_mode_client::IpcCodeModeSessionProvider::default()), + Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), Some(config.multi_agent_version_from_features()), ) .await; @@ -5003,11 +5003,9 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) { /*attestation_provider*/ None, ), code_mode_service: crate::tools::code_mode::CodeModeService::new(Arc::new( - codex_code_mode_client::IpcCodeModeSessionProvider::default(), + codex_code_mode::InProcessCodeModeSessionProvider, )), - code_mode_session_provider: Arc::new( - codex_code_mode_client::IpcCodeModeSessionProvider::default(), - ), + code_mode_session_provider: Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), environment_manager: Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), }; @@ -5179,7 +5177,7 @@ async fn make_session_with_config_and_rx( )), codex_rollout_trace::ThreadTraceContext::disabled(), /*attestation_provider*/ None, - Arc::new(codex_code_mode_client::IpcCodeModeSessionProvider::default()), + Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), Some(config.multi_agent_version_from_features()), ) .await?; @@ -5289,7 +5287,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx( )), codex_rollout_trace::ThreadTraceContext::disabled(), /*attestation_provider*/ None, - Arc::new(codex_code_mode_client::IpcCodeModeSessionProvider::default()), + Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), Some(config.multi_agent_version_from_features()), ) .await?; @@ -7009,11 +7007,9 @@ where /*attestation_provider*/ None, ), code_mode_service: crate::tools::code_mode::CodeModeService::new(Arc::new( - codex_code_mode_client::IpcCodeModeSessionProvider::default(), + codex_code_mode::InProcessCodeModeSessionProvider, )), - code_mode_session_provider: Arc::new( - codex_code_mode_client::IpcCodeModeSessionProvider::default(), - ), + code_mode_session_provider: Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), environment_manager: Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), }; diff --git a/codex-rs/core/src/session/tests/guardian_tests.rs b/codex-rs/core/src/session/tests/guardian_tests.rs index 397dc5c5fa..65cf8ccb96 100644 --- a/codex-rs/core/src/session/tests/guardian_tests.rs +++ b/codex-rs/core/src/session/tests/guardian_tests.rs @@ -736,9 +736,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() { analytics_events_client: None, thread_store, attestation_provider: None, - code_mode_session_provider: Arc::new( - codex_code_mode_client::IpcCodeModeSessionProvider::default(), - ), + code_mode_session_provider: Arc::new(codex_code_mode::InProcessCodeModeSessionProvider), inherited_multi_agent_version: None, }) .await diff --git a/codex-rs/core/tests/common/Cargo.toml b/codex-rs/core/tests/common/Cargo.toml index 956162f25e..76f06df1ed 100644 --- a/codex-rs/core/tests/common/Cargo.toml +++ b/codex-rs/core/tests/common/Cargo.toml @@ -17,7 +17,6 @@ assert_cmd = { workspace = true } base64 = { workspace = true } codex-arg0 = { workspace = true } codex-config = { workspace = true } -codex-code-mode-client = { workspace = true } codex-core = { workspace = true } codex-extension-api = { workspace = true } codex-exec-server = { workspace = true } diff --git a/codex-rs/core/tests/common/test_codex.rs b/codex-rs/core/tests/common/test_codex.rs index 6e2dce3715..1582b44d7d 100644 --- a/codex-rs/core/tests/common/test_codex.rs +++ b/codex-rs/core/tests/common/test_codex.rs @@ -13,8 +13,6 @@ use std::time::Duration; use anyhow::Context; use anyhow::Result; use anyhow::anyhow; -use codex_code_mode_client::CodeModeHostCommand; -use codex_code_mode_client::IpcCodeModeSessionProvider; use codex_config::CloudConfigBundleLoader; use codex_core::CodexThread; use codex_core::ThreadManager; @@ -569,14 +567,6 @@ impl TestCodexBuilder { installation_id, /*attestation_provider*/ None, ); - let program = codex_utils_cargo_bin::cargo_bin("codex-code-mode-host") - .context("codex-code-mode-host must be built for core integration tests")?; - let code_mode_session_provider = IpcCodeModeSessionProvider::new(CodeModeHostCommand { - program, - args: Vec::new(), - }); - let thread_manager = - thread_manager.with_code_mode_session_provider(Arc::new(code_mode_session_provider)); let thread_manager = Arc::new(thread_manager); let user_shell_override = self.user_shell_override.clone(); diff --git a/justfile b/justfile index 7676d4d5c4..153fc7bd97 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 {{ python }} ../scripts/run-nextest.py "$@" + RUST_MIN_STACK={{ rust_min_stack }} NEXTEST_PROFILE=local cargo nextest run --no-fail-fast "$@" [windows] test *args: - $env:RUST_MIN_STACK = "{{ rust_min_stack }}"; $env:NEXTEST_PROFILE = "local"; {{ python }} ../scripts/run-nextest.py @($args | Select-Object -Skip 1) + $env:RUST_MIN_STACK = "{{ rust_min_stack }}"; $env:NEXTEST_PROFILE = "local"; cargo nextest run --no-fail-fast @($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. diff --git a/scripts/run-nextest.py b/scripts/run-nextest.py deleted file mode 100644 index 6a6d0679ba..0000000000 --- a/scripts/run-nextest.py +++ /dev/null @@ -1,65 +0,0 @@ -"""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())