Apply shared network policy throughout embedded Codex startup (#47411)

## Why

Application network restrictions need to cover clients created by the TUI and `codex exec` before embedded app-server startup, and remain effective when configuration is rebuilt.

## What changed

- Introduce `EmbeddedNetworkPolicy` to share live policy between caller-owned transports and the embedded app-server.
- Apply loaded requirements before creating telemetry, background HTTP clients, and executor connections. Limit authentication and cloud configuration bootstrap requests to exact endpoints under local policy.
- Preserve the shared policy across TUI session changes, permission-profile rebuilds, and worktree cloud loaders so existing clients observe policy reloads and failures.
- Document application network policy behavior and transport coverage.

## Testing

Add regression coverage for policy activation, reload failure and recovery, retained policy across TUI rebuilds, rejected OAuth and cloud-policy redirects, and workspace network restrictions with `CODEX_API_KEY`. Also cover retaining the caller-selected project during embedded startup.

GitOrigin-RevId: 629009f087b8cb21fc34a1ee7ea6fe95d9e0f2b5
This commit is contained in:
acrognale-oai
2026-09-23 00:49:19 +00:00
committed by copyberry
parent db3cb33eca
commit 9d4d34d436
33 changed files with 799 additions and 31 deletions
+9 -3
View File
@@ -3,13 +3,18 @@
use super::*;
pub(super) struct ForkNetwork {
pub cloud_config_bundle: CloudConfigBundleLoader,
pub policy: codex_app_server_client::EmbeddedNetworkPolicy,
}
pub(super) async fn fork_source(
args: &mut crate::cli::ForkArgs,
config: &Config,
arg0_paths: &Arg0DispatchPaths,
cli_overrides: &[(String, codex_config::TomlValue)],
loader_overrides: &LoaderOverrides,
cloud_config_bundle: CloudConfigBundleLoader,
network: ForkNetwork,
strict_config: bool,
) -> anyhow::Result<std::path::PathBuf> {
let state_db = codex_core::init_state_db(config).await;
@@ -19,7 +24,7 @@ pub(super) async fn fork_source(
arg0_paths.codex_self_exe.clone(),
arg0_paths.codex_linux_sandbox_exe.clone(),
)?),
config.http_client_factory(),
network.policy.bind(config.http_client_factory()),
)
.await?;
let client = InProcessAppServerClient::start(InProcessClientStartArgs {
@@ -31,7 +36,8 @@ pub(super) async fn fork_source(
..loader_overrides.clone()
},
strict_config,
cloud_config_bundle,
cloud_config_bundle: network.cloud_config_bundle,
embedded_network_policy: network.policy,
feedback: CodexFeedback::new(),
log_db: None,
state_db: state_db.clone(),