diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 25394d6a..03a42223 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -83,6 +83,15 @@ jobs: - name: cargo clippy run: cargo clippy --target ${{ matrix.target }} --all-features -- -D warnings || echo "FAILED=${FAILED:+$FAILED, }cargo clippy" >> $GITHUB_ENV + # Running `cargo build` from the workspace root builds the workspace using + # the union of all features from third-party crates. This can mask errors + # where individual crates have underspecified features. To avoid this, we + # run `cargo build` for each crate individually, though because this is + # slower, we only do this for the x86_64-unknown-linux-gnu target. + - name: cargo build individual crates + if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }} + run: find . -name Cargo.toml -mindepth 2 -maxdepth 2 -print0 | xargs -0 -n1 -I{} bash -c 'cd "$(dirname "{}")" && cargo build' || echo "FAILED=${FAILED:+$FAILED, }cargo build individual crates" >> $GITHUB_ENV + - name: cargo test run: cargo test --target ${{ matrix.target }} || echo "FAILED=${FAILED:+$FAILED, }cargo test" >> $GITHUB_ENV diff --git a/codex-rs/core/src/approval_mode_cli_arg.rs b/codex-rs/core/src/approval_mode_cli_arg.rs index f4e64feb..6aadbd92 100644 --- a/codex-rs/core/src/approval_mode_cli_arg.rs +++ b/codex-rs/core/src/approval_mode_cli_arg.rs @@ -1,12 +1,11 @@ //! Standard type to use with the `--approval-mode` CLI option. //! Available when the `cli` feature is enabled for the crate. -use std::path::PathBuf; - use clap::ArgAction; use clap::Parser; use clap::ValueEnum; +use crate::config::parse_sandbox_permission_with_base_path; use crate::protocol::AskForApproval; use crate::protocol::SandboxPermission; @@ -72,49 +71,3 @@ fn parse_sandbox_permission(raw: &str) -> std::io::Result { let base_path = std::env::current_dir()?; parse_sandbox_permission_with_base_path(raw, base_path) } - -pub(crate) fn parse_sandbox_permission_with_base_path( - raw: &str, - base_path: PathBuf, -) -> std::io::Result { - use SandboxPermission::*; - - if let Some(path) = raw.strip_prefix("disk-write-folder=") { - return if path.is_empty() { - Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "--sandbox-permission disk-write-folder= requires a non-empty PATH", - )) - } else { - use path_absolutize::*; - - let file = PathBuf::from(path); - let absolute_path = if file.is_relative() { - file.absolutize_from(base_path) - } else { - file.absolutize() - } - .map(|path| path.into_owned())?; - Ok(DiskWriteFolder { - folder: absolute_path, - }) - }; - } - - match raw { - "disk-full-read-access" => Ok(DiskFullReadAccess), - "disk-write-platform-user-temp-folder" => Ok(DiskWritePlatformUserTempFolder), - "disk-write-platform-global-temp-folder" => Ok(DiskWritePlatformGlobalTempFolder), - "disk-write-cwd" => Ok(DiskWriteCwd), - "disk-full-write-access" => Ok(DiskFullWriteAccess), - "network-full-access" => Ok(NetworkFullAccess), - _ => Err( - std::io::Error::new( - std::io::ErrorKind::InvalidInput, - format!( - "`{raw}` is not a recognised permission.\nRun with `--help` to see the accepted values." - ), - ) - ), - } -} diff --git a/codex-rs/core/src/config.rs b/codex-rs/core/src/config.rs index 1557ce27..554173c5 100644 --- a/codex-rs/core/src/config.rs +++ b/codex-rs/core/src/config.rs @@ -1,4 +1,3 @@ -use crate::approval_mode_cli_arg::parse_sandbox_permission_with_base_path; use crate::flags::OPENAI_DEFAULT_MODEL; use crate::protocol::AskForApproval; use crate::protocol::SandboxPermission; @@ -257,6 +256,52 @@ pub fn log_dir() -> std::io::Result { Ok(p) } +pub(crate) fn parse_sandbox_permission_with_base_path( + raw: &str, + base_path: PathBuf, +) -> std::io::Result { + use SandboxPermission::*; + + if let Some(path) = raw.strip_prefix("disk-write-folder=") { + return if path.is_empty() { + Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "--sandbox-permission disk-write-folder= requires a non-empty PATH", + )) + } else { + use path_absolutize::*; + + let file = PathBuf::from(path); + let absolute_path = if file.is_relative() { + file.absolutize_from(base_path) + } else { + file.absolutize() + } + .map(|path| path.into_owned())?; + Ok(DiskWriteFolder { + folder: absolute_path, + }) + }; + } + + match raw { + "disk-full-read-access" => Ok(DiskFullReadAccess), + "disk-write-platform-user-temp-folder" => Ok(DiskWritePlatformUserTempFolder), + "disk-write-platform-global-temp-folder" => Ok(DiskWritePlatformGlobalTempFolder), + "disk-write-cwd" => Ok(DiskWriteCwd), + "disk-full-write-access" => Ok(DiskFullWriteAccess), + "network-full-access" => Ok(NetworkFullAccess), + _ => Err( + std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!( + "`{raw}` is not a recognised permission.\nRun with `--help` to see the accepted values." + ), + ) + ), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/codex-rs/mcp-client/Cargo.toml b/codex-rs/mcp-client/Cargo.toml index b3792922..562675c8 100644 --- a/codex-rs/mcp-client/Cargo.toml +++ b/codex-rs/mcp-client/Cargo.toml @@ -11,11 +11,11 @@ serde_json = "1" tracing = { version = "0.1.41", features = ["log"] } tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] } tokio = { version = "1", features = [ - "io-std", + "io-util", "macros", "process", "rt-multi-thread", - "signal", + "sync", ] } [dev-dependencies]