diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 0be45540c1..13fcaacbbd 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -412,14 +412,6 @@ jobs: - name: Install DotSlash uses: facebook/install-dotslash@v2 - - name: Pre-fetch DotSlash artifacts - # The Bash wrapper is not available on Windows. - if: ${{ !startsWith(matrix.runner, 'windows') }} - shell: bash - run: | - set -euo pipefail - dotslash -- fetch exec-server/tests/suite/bash - - uses: dtolnay/rust-toolchain@1.90 with: targets: ${{ matrix.target }} diff --git a/codex-rs/exec-server/tests/common/lib.rs b/codex-rs/exec-server/tests/common/lib.rs index c6df5c32c7..a968db9657 100644 --- a/codex-rs/exec-server/tests/common/lib.rs +++ b/codex-rs/exec-server/tests/common/lib.rs @@ -23,7 +23,10 @@ use std::sync::Arc; use std::sync::Mutex; use tokio::process::Command; -pub fn create_transport

(codex_home: P) -> anyhow::Result +pub async fn create_transport

( + codex_home: P, + dotslash_cache: P, +) -> anyhow::Result where P: AsRef, { @@ -36,11 +39,22 @@ where .join("suite") .join("bash"); + // Need to ensure the artifact associated with the bash DotSlash file is + // available before it is run in a read-only sandbox. + Command::new("dotslash") + .arg("--") + .arg("fetch") + .arg(bash.clone()) + .env("DOTSLASH_CACHE", dotslash_cache.as_ref()) + .status() + .await?; + let transport = TokioChildProcess::new(Command::new(mcp_executable.get_program()).configure(|cmd| { cmd.arg("--bash").arg(bash); cmd.arg("--execve").arg(execve_wrapper.get_program()); cmd.env("CODEX_HOME", codex_home.as_ref()); + cmd.env("DOTSLASH_CACHE", dotslash_cache.as_ref()); // Important: pipe stdio so rmcp can speak JSON-RPC over stdin/stdout cmd.stdin(Stdio::piped()); diff --git a/codex-rs/exec-server/tests/suite/accept_elicitation.rs b/codex-rs/exec-server/tests/suite/accept_elicitation.rs index 2093f9a577..b56c717599 100644 --- a/codex-rs/exec-server/tests/suite/accept_elicitation.rs +++ b/codex-rs/exec-server/tests/suite/accept_elicitation.rs @@ -42,7 +42,9 @@ prefix_rule( codex_home.as_ref(), ) .await?; - let transport = create_transport(codex_home.as_ref())?; + let dotslash_cache_temp_dir = TempDir::new()?; + let dotslash_cache = dotslash_cache_temp_dir.path(); + let transport = create_transport(codex_home.as_ref(), dotslash_cache).await?; // Create an MCP client that approves expected elicitation messages. let project_root = TempDir::new()?; diff --git a/codex-rs/exec-server/tests/suite/list_tools.rs b/codex-rs/exec-server/tests/suite/list_tools.rs index 17505c7613..2f3d412df7 100644 --- a/codex-rs/exec-server/tests/suite/list_tools.rs +++ b/codex-rs/exec-server/tests/suite/list_tools.rs @@ -22,7 +22,9 @@ async fn list_tools() -> Result<()> { policy_dir.join("default.codexpolicy"), r#"prefix_rule(pattern=["ls"], decision="prompt")"#, )?; - let transport = create_transport(codex_home.path())?; + let dotslash_cache_temp_dir = TempDir::new()?; + let dotslash_cache = dotslash_cache_temp_dir.path(); + let transport = create_transport(codex_home.path(), dotslash_cache).await?; let service = ().serve(transport).await?; let tools = service.list_tools(Default::default()).await?.tools;