mirror of
https://github.com/openai/codex.git
synced 2026-04-25 23:24:55 +00:00
This PR introduces integration tests that run [codex-shell-tool-mcp](https://www.npmjs.com/package/@openai/codex-shell-tool-mcp) as a user would. Note that this requires running our fork of Bash, so we introduce a [DotSlash](https://dotslash-cli.com/) file for `bash` so that we can run the integration tests on multiple platforms without having to check the binaries into the repository. (As noted in the DotSlash file, it is slightly more heavyweight than necessary, which may be worth addressing as disk space in CI is limited: https://github.com/openai/codex/pull/7678.) To start, this PR adds two tests: - `list_tools()` makes the `list_tools` request to the MCP server and verifies we get the expected response - `accept_elicitation_for_prompt_rule()` defines a `prefix_rule()` with `decision="prompt"` and verifies the elicitation flow works as expected Though the `accept_elicitation_for_prompt_rule()` test **only works on Linux**, as this PR reveals that there are currently issues when running the Bash fork in a read-only sandbox on Linux. This will have to be fixed in a follow-up PR. Incidentally, getting this test run to correctly on macOS also requires a recent fix we made to `brew` that hasn't hit a mainline release yet, so getting CI green in this PR required https://github.com/openai/codex/pull/7680.
77 lines
2.6 KiB
Rust
77 lines
2.6 KiB
Rust
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
|
use std::borrow::Cow;
|
|
use std::fs;
|
|
use std::sync::Arc;
|
|
|
|
use anyhow::Result;
|
|
use exec_server_test_support::create_transport;
|
|
use pretty_assertions::assert_eq;
|
|
use rmcp::ServiceExt;
|
|
use rmcp::model::Tool;
|
|
use rmcp::model::object;
|
|
use serde_json::json;
|
|
use tempfile::TempDir;
|
|
|
|
/// Verify the list_tools call to the MCP server returns the expected response.
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn list_tools() -> Result<()> {
|
|
let codex_home = TempDir::new()?;
|
|
let policy_dir = codex_home.path().join("policy");
|
|
fs::create_dir_all(&policy_dir)?;
|
|
fs::write(
|
|
policy_dir.join("default.codexpolicy"),
|
|
r#"prefix_rule(pattern=["ls"], decision="prompt")"#,
|
|
)?;
|
|
let transport = create_transport(codex_home.path())?;
|
|
|
|
let service = ().serve(transport).await?;
|
|
let tools = service.list_tools(Default::default()).await?.tools;
|
|
assert_eq!(
|
|
vec![Tool {
|
|
name: Cow::Borrowed("shell"),
|
|
title: None,
|
|
description: Some(Cow::Borrowed(
|
|
"Runs a shell command and returns its output. You MUST provide the workdir as an absolute path."
|
|
)),
|
|
input_schema: Arc::new(object(json!({
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"properties": {
|
|
"command": {
|
|
"description": "The bash string to execute.",
|
|
"type": "string",
|
|
},
|
|
"login": {
|
|
"description": "Launch Bash with -lc instead of -c: defaults to true.",
|
|
"nullable": true,
|
|
"type": "boolean",
|
|
},
|
|
"timeout_ms": {
|
|
"description": "The timeout for the command in milliseconds.",
|
|
"format": "uint64",
|
|
"minimum": 0,
|
|
"nullable": true,
|
|
"type": "integer",
|
|
},
|
|
"workdir": {
|
|
"description": "The working directory to execute the command in. Must be an absolute path.",
|
|
"type": "string",
|
|
},
|
|
},
|
|
"required": [
|
|
"command",
|
|
"workdir",
|
|
],
|
|
"title": "ExecParams",
|
|
"type": "object",
|
|
}))),
|
|
output_schema: None,
|
|
annotations: None,
|
|
icons: None,
|
|
meta: None
|
|
}],
|
|
tools
|
|
);
|
|
|
|
Ok(())
|
|
}
|