mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +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
115 lines
4.0 KiB
Rust
115 lines
4.0 KiB
Rust
use std::sync::Arc;
|
|
|
|
use codex_exec_server::EnvironmentManager;
|
|
use codex_exec_server::ExecServerRuntimeOptions;
|
|
use codex_extension_api::ExtensionRegistry;
|
|
use codex_extension_api::UserInstructionsProvider;
|
|
use codex_login::AuthManager;
|
|
use codex_protocol::error::CodexErr;
|
|
use codex_protocol::error::Result as CodexResult;
|
|
use codex_protocol::models::ResponseItem;
|
|
use codex_protocol::protocol::SessionSource;
|
|
use codex_protocol::user_input::UserInput;
|
|
use tokio_util::sync::CancellationToken;
|
|
|
|
use crate::config::Config;
|
|
use crate::resolve_installation_id;
|
|
use crate::session::session::Session;
|
|
use crate::session::turn::build_prompt;
|
|
use crate::state_db_bridge::StateDbHandle;
|
|
use crate::thread_manager::StartThreadOptions;
|
|
use crate::thread_manager::ThreadManager;
|
|
use crate::thread_manager::thread_store_from_config;
|
|
|
|
/// Build the model-visible `input` list for a single debug turn.
|
|
#[doc(hidden)]
|
|
pub async fn build_prompt_input(
|
|
mut config: Config,
|
|
input: Vec<UserInput>,
|
|
state_db: Option<StateDbHandle>,
|
|
extensions: Arc<ExtensionRegistry<Config>>,
|
|
user_instructions_provider: Arc<dyn UserInstructionsProvider>,
|
|
) -> CodexResult<Vec<ResponseItem>> {
|
|
config.ephemeral = true;
|
|
|
|
let auth_manager =
|
|
AuthManager::shared_from_config(&config, /*enable_codex_api_key_env*/ false)
|
|
.await
|
|
.map_err(|err| CodexErr::Fatal(err.to_string()))?;
|
|
|
|
let local_runtime_paths = ExecServerRuntimeOptions::from_optional_paths(
|
|
config.codex_self_exe.clone(),
|
|
config.codex_linux_sandbox_exe.clone(),
|
|
)?;
|
|
|
|
let thread_store = thread_store_from_config(&config, state_db.clone());
|
|
let installation_id = resolve_installation_id(&config.codex_home).await?;
|
|
let thread_manager = ThreadManager::new(
|
|
&config,
|
|
Arc::clone(&auth_manager),
|
|
crate::thread_manager::build_models_manager(&config, Arc::clone(&auth_manager)),
|
|
crate::CodexAppsToolsCache::default(),
|
|
SessionSource::Exec,
|
|
Arc::new(
|
|
EnvironmentManager::from_codex_home(
|
|
config.codex_home.clone(),
|
|
Some(local_runtime_paths),
|
|
config.http_client_factory(),
|
|
)
|
|
.await
|
|
.map_err(|err| CodexErr::Fatal(err.to_string()))?,
|
|
),
|
|
extensions,
|
|
user_instructions_provider,
|
|
/*analytics_events_client*/ None,
|
|
crate::thread_manager::passthrough_image_store(),
|
|
thread_store,
|
|
crate::local_agent_graph_store_from_state_db(state_db.as_ref()),
|
|
installation_id,
|
|
/*attestation_provider*/ None,
|
|
/*external_time_provider*/ None,
|
|
);
|
|
let thread = thread_manager
|
|
.start_thread(StartThreadOptions::new(config))
|
|
.await?;
|
|
|
|
let output = build_prompt_input_from_session(&thread.thread.session, input).await;
|
|
let shutdown = thread.thread.shutdown_and_wait().await;
|
|
let _removed = thread_manager.remove_thread(&thread.thread_id).await;
|
|
|
|
shutdown?;
|
|
output
|
|
}
|
|
|
|
pub(crate) async fn build_prompt_input_from_session(
|
|
sess: &Arc<Session>,
|
|
input: Vec<UserInput>,
|
|
) -> CodexResult<Vec<ResponseItem>> {
|
|
let turn_context = sess.new_default_turn().await;
|
|
// Prompt debugging builds a standalone request without entering run_turn.
|
|
let step_context = sess
|
|
.capture_step_context(Arc::clone(&turn_context), &CancellationToken::new())
|
|
.await?;
|
|
sess.record_context_updates_and_set_reference_context_item(step_context.as_ref())
|
|
.await?;
|
|
|
|
if !input.is_empty() {
|
|
let response_item = sess.response_item_from_user_input(input);
|
|
sess.record_conversation_items(
|
|
turn_context.as_ref(),
|
|
&step_context.settings.model_info,
|
|
std::slice::from_ref(&response_item),
|
|
)
|
|
.await;
|
|
}
|
|
|
|
let prompt_input = sess
|
|
.clone_history()
|
|
.await
|
|
.for_prompt(&step_context.settings.model_info.input_modalities);
|
|
let base_instructions = sess.get_base_instructions().await;
|
|
let prompt = build_prompt(prompt_input, step_context.as_ref(), base_instructions);
|
|
|
|
Ok(prompt.input)
|
|
}
|