mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
## Why Private IP destinations always bypassed inherited upstream proxies, preventing their use for private networks reachable through an upstream VPN proxy. ## What changed - Add `codex exec-server --proxy-private-ips-via-upstream`, also configurable with `CODEX_EXEC_SERVER_PROXY_PRIVATE_IPS_VIA_UPSTREAM=true`. The setting defaults to disabled. - Allow permitted RFC 1918, carrier-grade NAT, and IPv6 unique-local destinations to use an applicable upstream proxy. Loopback and link-local destinations retain direct routing, and destination access policy still applies. - Keep connections direct when no valid upstream proxy applies or `allow_upstream_proxy=false`. Errors after selecting an upstream proxy do not trigger a direct retry. - Rename `ExecServerRuntimePaths` to `ExecServerRuntimeOptions` and carry the routing setting from executor startup into the managed network proxy. ## Testing Add routing coverage for private address ranges, special-use addresses, and public targets with the option enabled and disabled. Verify that HTTP and CONNECT requests still enforce destination allowlists and denylists, and update the CLI help snapshot. GitOrigin-RevId: b7c9cc7da0e0f545694a6521b74c9b36b7b92769
120 lines
3.7 KiB
Rust
120 lines
3.7 KiB
Rust
mod build_identity;
|
|
mod file_system_handler;
|
|
mod handler;
|
|
mod process_handler;
|
|
mod processor;
|
|
mod registry;
|
|
mod release_version;
|
|
mod request_dispatcher;
|
|
mod session_registry;
|
|
mod transport;
|
|
|
|
#[cfg(all(test, unix))]
|
|
#[path = "server/process_otel_tests.rs"]
|
|
mod process_otel_tests;
|
|
|
|
pub(crate) use handler::ExecServerHandler;
|
|
pub(crate) use processor::ConnectionProcessor;
|
|
pub use request_dispatcher::ConcurrentRequestLimit;
|
|
pub use request_dispatcher::RequestDispatchMode;
|
|
pub use transport::DEFAULT_LISTEN_URL;
|
|
pub use transport::ExecServerListenUrlParseError;
|
|
|
|
use crate::ExecServerRuntimeOptions;
|
|
use crate::ExecServerTelemetry;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_websocket_auth::WebsocketAuthSettings;
|
|
|
|
pub async fn run_main(
|
|
listen_url: &str,
|
|
runtime_paths: ExecServerRuntimeOptions,
|
|
http_client_factory: HttpClientFactory,
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
run_main_with_telemetry(
|
|
listen_url,
|
|
runtime_paths,
|
|
ExecServerTelemetry::default(),
|
|
http_client_factory,
|
|
RequestDispatchMode::Inline,
|
|
WebsocketAuthSettings::default(),
|
|
)
|
|
.await
|
|
}
|
|
|
|
#[tracing::instrument(
|
|
name = "codex.exec_server",
|
|
skip_all,
|
|
fields(otel.kind = "internal")
|
|
)]
|
|
pub async fn run_main_with_telemetry(
|
|
listen_url: &str,
|
|
runtime_paths: ExecServerRuntimeOptions,
|
|
telemetry: ExecServerTelemetry,
|
|
http_client_factory: HttpClientFactory,
|
|
request_dispatch_mode: RequestDispatchMode,
|
|
websocket_auth: WebsocketAuthSettings,
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
std::sync::LazyLock::force(&build_identity::PROVIDER_ID);
|
|
transport::run_transport(
|
|
listen_url,
|
|
runtime_paths,
|
|
telemetry,
|
|
http_client_factory,
|
|
request_dispatch_mode,
|
|
websocket_auth,
|
|
)
|
|
.await
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_http_client::OutboundProxyPolicy;
|
|
use opentelemetry::trace::TracerProvider as _;
|
|
use opentelemetry_sdk::trace::InMemorySpanExporter;
|
|
use opentelemetry_sdk::trace::SdkTracerProvider;
|
|
use tracing::instrument::WithSubscriber;
|
|
use tracing_subscriber::prelude::*;
|
|
|
|
use super::run_main_with_telemetry;
|
|
use crate::ExecServerRuntimeOptions;
|
|
use crate::ExecServerTelemetry;
|
|
|
|
#[tokio::test]
|
|
async fn telemetry_entrypoint_emits_root_span() {
|
|
let exporter = InMemorySpanExporter::default();
|
|
let provider = SdkTracerProvider::builder()
|
|
.with_simple_exporter(exporter.clone())
|
|
.build();
|
|
let subscriber = tracing_subscriber::registry()
|
|
.with(tracing_opentelemetry::layer().with_tracer(provider.tracer("exec-server-test")));
|
|
|
|
async {
|
|
tracing::callsite::rebuild_interest_cache();
|
|
run_main_with_telemetry(
|
|
"invalid",
|
|
ExecServerRuntimeOptions::new(
|
|
std::env::current_exe().expect("current executable"),
|
|
/*codex_linux_sandbox_exe*/ None,
|
|
)
|
|
.expect("runtime paths"),
|
|
ExecServerTelemetry::default(),
|
|
HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault),
|
|
super::RequestDispatchMode::Inline,
|
|
codex_websocket_auth::WebsocketAuthSettings::default(),
|
|
)
|
|
.await
|
|
.expect_err("invalid listen URL should fail");
|
|
}
|
|
.with_subscriber(subscriber)
|
|
.await;
|
|
|
|
provider.force_flush().expect("flush traces");
|
|
let spans = exporter.get_finished_spans().expect("span export");
|
|
assert!(
|
|
spans.iter().any(|span| span.name == "codex.exec_server"),
|
|
"root exec-server span missing: {spans:?}"
|
|
);
|
|
}
|
|
}
|