mirror of
https://github.com/openai/codex.git
synced 2026-05-18 02:02:30 +00:00
## Summary - add a codex-uds crate with async UnixListener and UnixStream wrappers - expose helpers for private socket directory setup and stale socket path checks - migrate codex-stdio-to-uds onto codex-uds and Tokio-based stdio/socket relaying - update the CLI stdio-to-uds command path for the async runner ## Tests - cargo test -p codex-uds -p codex-stdio-to-uds - cargo test -p codex-cli - just fmt - just fix -p codex-uds - just fix -p codex-stdio-to-uds - just fix -p codex-cli - just bazel-lock-check - git diff --check
122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
use std::io::ErrorKind;
|
|
|
|
use pretty_assertions::assert_eq;
|
|
use tokio::io::AsyncReadExt;
|
|
use tokio::io::AsyncWriteExt;
|
|
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn prepare_private_socket_directory_creates_directory() {
|
|
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
|
let socket_dir = temp_dir.path().join("app-server-control");
|
|
|
|
prepare_private_socket_directory(&socket_dir)
|
|
.await
|
|
.expect("socket dir should be created");
|
|
|
|
assert!(socket_dir.is_dir());
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[tokio::test]
|
|
async fn prepare_private_socket_directory_sets_existing_permissions_to_owner_only() {
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
|
for mode in [0o755, 0o600] {
|
|
let socket_dir = temp_dir.path().join(format!("app-server-control-{mode:o}"));
|
|
std::fs::create_dir(&socket_dir).expect("socket dir should be created");
|
|
std::fs::set_permissions(&socket_dir, std::fs::Permissions::from_mode(mode))
|
|
.expect("socket dir permissions should be changed");
|
|
|
|
prepare_private_socket_directory(&socket_dir)
|
|
.await
|
|
.expect("socket dir permissions should be set exactly");
|
|
|
|
let mode = std::fs::metadata(&socket_dir)
|
|
.expect("socket dir metadata")
|
|
.permissions()
|
|
.mode();
|
|
assert_eq!(mode & 0o777, 0o700);
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[tokio::test]
|
|
async fn regular_file_path_is_not_stale_socket_path() {
|
|
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
|
let regular_file = temp_dir.path().join("not-a-socket");
|
|
std::fs::write(®ular_file, b"not a socket").expect("regular file should be created");
|
|
|
|
assert!(
|
|
!is_stale_socket_path(®ular_file)
|
|
.await
|
|
.expect("stale socket check should succeed")
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn bound_listener_path_is_stale_socket_path() {
|
|
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
|
let socket_path = temp_dir.path().join("socket");
|
|
let _listener = match UnixListener::bind(&socket_path).await {
|
|
Ok(listener) => listener,
|
|
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
|
|
eprintln!("skipping test: failed to bind unix socket: {err}");
|
|
return;
|
|
}
|
|
Err(err) => panic!("failed to bind test socket: {err}"),
|
|
};
|
|
|
|
assert!(
|
|
is_stale_socket_path(&socket_path)
|
|
.await
|
|
.expect("stale socket check should succeed")
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn stream_round_trips_data_between_listener_and_client() {
|
|
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
|
let socket_path = temp_dir.path().join("socket");
|
|
let mut listener = match UnixListener::bind(&socket_path).await {
|
|
Ok(listener) => listener,
|
|
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
|
|
eprintln!("skipping test: failed to bind unix socket: {err}");
|
|
return;
|
|
}
|
|
Err(err) => panic!("failed to bind test socket: {err}"),
|
|
};
|
|
|
|
let server_task = tokio::spawn(async move {
|
|
let mut server_stream = listener.accept().await.expect("connection should accept");
|
|
let mut request = [0; 7];
|
|
server_stream
|
|
.read_exact(&mut request)
|
|
.await
|
|
.expect("server should read request");
|
|
assert_eq!(&request, b"request");
|
|
server_stream
|
|
.write_all(b"response")
|
|
.await
|
|
.expect("server should write response");
|
|
});
|
|
|
|
let mut client_stream = UnixStream::connect(&socket_path)
|
|
.await
|
|
.expect("client should connect");
|
|
client_stream
|
|
.write_all(b"request")
|
|
.await
|
|
.expect("client should write request");
|
|
let mut response = [0; 8];
|
|
client_stream
|
|
.read_exact(&mut response)
|
|
.await
|
|
.expect("client should read response");
|
|
assert_eq!(&response, b"response");
|
|
|
|
server_task.await.expect("server task should join");
|
|
}
|