mirror of
https://github.com/openai/codex.git
synced 2026-09-01 14:39:21 +00:00
## What changed - Move the reusable WebSocket relay, registration, frame capture, and encryption assertion helpers into `codex-exec-server-test-support`. - Re-export the helpers from the existing relay test module so its callers keep the same interface. - Add the Cargo dependencies and Bazel proto compile data required by the shared support module. GitOrigin-RevId: 0383149c79ef86cb5e64a09baec41332f9eec4c6
157 lines
5.9 KiB
Rust
157 lines
5.9 KiB
Rust
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
|
|
use anyhow::Context;
|
|
use anyhow::Result;
|
|
use codex_api::AuthProvider;
|
|
use codex_exec_server::ExecServerClient;
|
|
use codex_exec_server::NoiseChannelIdentity;
|
|
use codex_exec_server::NoiseRendezvousConnectArgs;
|
|
use codex_exec_server::NoiseRendezvousConnectBundle;
|
|
use codex_exec_server::RemoteEnvironmentConfig;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_http_client::OutboundProxyPolicy;
|
|
use http::HeaderMap;
|
|
use http::HeaderValue;
|
|
use tokio::net::TcpListener;
|
|
use tokio::time::timeout;
|
|
use tokio_util::task::AbortOnDropHandle;
|
|
use wiremock::Mock;
|
|
use wiremock::MockServer;
|
|
use wiremock::ResponseTemplate;
|
|
use wiremock::matchers::header;
|
|
use wiremock::matchers::method;
|
|
use wiremock::matchers::path;
|
|
|
|
pub(crate) use codex_exec_server_test_support::relay::TEST_TIMEOUT;
|
|
pub(crate) use codex_exec_server_test_support::relay::accept_websocket;
|
|
pub(crate) use codex_exec_server_test_support::relay::assert_relay_data_is_encrypted;
|
|
pub(crate) use codex_exec_server_test_support::relay::proxy_relay_frames;
|
|
pub(crate) use codex_exec_server_test_support::relay::registered_executor_public_key;
|
|
|
|
pub(crate) const ENVIRONMENT_ID: &str = "env-noise-relay-test";
|
|
pub(crate) const EXECUTOR_REGISTRATION_ID: &str = "registration-1";
|
|
pub(crate) const HARNESS_KEY_AUTHORIZATION: &str = "harness-key-authorization";
|
|
pub(crate) const REGISTRY_TOKEN: &str = "registry-token";
|
|
|
|
#[derive(Debug)]
|
|
struct StaticRegistryAuthProvider;
|
|
|
|
impl AuthProvider for StaticRegistryAuthProvider {
|
|
fn add_auth_headers(&self, headers: &mut HeaderMap) {
|
|
let _ = headers.insert(
|
|
http::header::AUTHORIZATION,
|
|
HeaderValue::from_static("Bearer registry-token"),
|
|
);
|
|
}
|
|
}
|
|
|
|
pub(crate) fn static_registry_auth_provider() -> codex_api::SharedAuthProvider {
|
|
Arc::new(StaticRegistryAuthProvider)
|
|
}
|
|
|
|
pub(crate) struct RelayTest {
|
|
registry: MockServer,
|
|
listener: TcpListener,
|
|
}
|
|
|
|
pub(crate) struct RelayConnection {
|
|
pub(crate) client: ExecServerClient,
|
|
captured_frames: Arc<Mutex<Vec<Vec<u8>>>>,
|
|
relay_task: AbortOnDropHandle<Result<()>>,
|
|
}
|
|
|
|
impl RelayTest {
|
|
pub(crate) async fn new() -> Result<Self> {
|
|
let listener = TcpListener::bind("127.0.0.1:0").await?;
|
|
let rendezvous_url = format!("ws://{}", listener.local_addr()?);
|
|
let registry = MockServer::start().await;
|
|
Mock::given(method("POST"))
|
|
.and(path(format!(
|
|
"/cloud/environment/{ENVIRONMENT_ID}/register"
|
|
)))
|
|
.and(header("authorization", format!("Bearer {REGISTRY_TOKEN}")))
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
|
|
"environment_id": ENVIRONMENT_ID,
|
|
"url": format!("{rendezvous_url}/relay?role=environment"),
|
|
"security_profile": "noise_hybrid_ik_v1",
|
|
"executor_registration_id": EXECUTOR_REGISTRATION_ID,
|
|
})))
|
|
.mount(®istry)
|
|
.await;
|
|
Mock::given(method("POST"))
|
|
.and(path(format!(
|
|
"/cloud/environment/{ENVIRONMENT_ID}/validate"
|
|
)))
|
|
.and(header("authorization", format!("Bearer {REGISTRY_TOKEN}")))
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
|
|
"valid": true,
|
|
})))
|
|
.mount(®istry)
|
|
.await;
|
|
Ok(Self { registry, listener })
|
|
}
|
|
|
|
pub(crate) fn config(&self) -> Result<RemoteEnvironmentConfig> {
|
|
Ok(RemoteEnvironmentConfig::new(
|
|
self.registry.uri(),
|
|
ENVIRONMENT_ID.to_string(),
|
|
static_registry_auth_provider(),
|
|
HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault),
|
|
)?)
|
|
}
|
|
|
|
pub(crate) async fn connect(&self) -> Result<RelayConnection> {
|
|
let rendezvous_url = format!("ws://{}", self.listener.local_addr()?);
|
|
let environment_websocket = accept_websocket(&self.listener, "environment").await?;
|
|
let executor_public_key = registered_executor_public_key(&self.registry).await?;
|
|
let harness_identity = NoiseChannelIdentity::generate()?;
|
|
let client_args = NoiseRendezvousConnectArgs {
|
|
bundle: NoiseRendezvousConnectBundle {
|
|
websocket_url: format!("{rendezvous_url}/relay?role=harness"),
|
|
environment_id: ENVIRONMENT_ID.to_string(),
|
|
executor_registration_id: EXECUTOR_REGISTRATION_ID.to_string(),
|
|
executor_public_key,
|
|
harness_key_authorization: HARNESS_KEY_AUTHORIZATION.to_string(),
|
|
},
|
|
harness_identity,
|
|
client_name: "noise-relay-test".to_string(),
|
|
connect_timeout: TEST_TIMEOUT,
|
|
initialize_timeout: TEST_TIMEOUT,
|
|
resume_session_id: None,
|
|
http_client_factory: HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault),
|
|
};
|
|
let client_task =
|
|
tokio::spawn(
|
|
async move { ExecServerClient::connect_noise_rendezvous(client_args).await },
|
|
);
|
|
let harness_websocket = accept_websocket(&self.listener, "harness").await?;
|
|
let captured_frames = Arc::new(Mutex::new(Vec::new()));
|
|
let relay_task = AbortOnDropHandle::new(tokio::spawn(proxy_relay_frames(
|
|
environment_websocket,
|
|
harness_websocket,
|
|
Arc::clone(&captured_frames),
|
|
)));
|
|
let client = timeout(TEST_TIMEOUT, client_task)
|
|
.await
|
|
.context("Noise harness client should connect")???;
|
|
Ok(RelayConnection {
|
|
client,
|
|
captured_frames,
|
|
relay_task,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl RelayConnection {
|
|
pub(crate) fn assert_encrypted(&self) -> Result<()> {
|
|
assert_relay_data_is_encrypted(&self.captured_frames)
|
|
}
|
|
|
|
pub(crate) async fn close(self) {
|
|
drop(self.client);
|
|
self.relay_task.abort();
|
|
let _ = self.relay_task.await;
|
|
}
|
|
}
|