Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions codex-rs/network-proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ It enforces an allow/deny policy and a "limited" mode intended for read-only net
Example config:

```toml
[network_proxy]
[network]
enabled = true
proxy_url = "http://127.0.0.1:3128"
admin_url = "http://127.0.0.1:8080"
Expand All @@ -35,7 +35,6 @@ dangerously_allow_non_loopback_proxy = false
dangerously_allow_non_loopback_admin = false
mode = "full" # default when unset; use "limited" for read-only mode

[network_proxy.policy]
# Hosts must match the allowlist (unless denied).
# If `allowed_domains` is empty, the proxy blocks requests until an allowlist is configured.
allowed_domains = ["*.openai.com"]
Expand Down
60 changes: 21 additions & 39 deletions codex-rs/network-proxy/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use url::Url;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NetworkProxyConfig {
#[serde(default)]
pub network_proxy: NetworkProxySettings,
pub network: NetworkProxySettings,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -37,7 +37,13 @@ pub struct NetworkProxySettings {
#[serde(default)]
pub mode: NetworkMode,
#[serde(default)]
pub policy: NetworkPolicy,
pub allowed_domains: Vec<String>,
#[serde(default)]
pub denied_domains: Vec<String>,
#[serde(default)]
pub allow_unix_sockets: Vec<String>,
#[serde(default)]
pub allow_local_binding: bool,
}

impl Default for NetworkProxySettings {
Expand All @@ -53,23 +59,14 @@ impl Default for NetworkProxySettings {
dangerously_allow_non_loopback_proxy: false,
dangerously_allow_non_loopback_admin: false,
mode: NetworkMode::default(),
policy: NetworkPolicy::default(),
allowed_domains: Vec::new(),
denied_domains: Vec::new(),
allow_unix_sockets: Vec::new(),
allow_local_binding: false,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NetworkPolicy {
#[serde(default)]
pub allowed_domains: Vec<String>,
#[serde(default)]
pub denied_domains: Vec<String>,
#[serde(default)]
pub allow_unix_sockets: Vec<String>,
#[serde(default)]
pub allow_local_binding: bool,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum NetworkMode {
Expand Down Expand Up @@ -142,7 +139,7 @@ pub(crate) fn clamp_bind_addrs(
cfg.dangerously_allow_non_loopback_admin,
"admin API",
);
if cfg.policy.allow_unix_sockets.is_empty() {
if cfg.allow_unix_sockets.is_empty() {
return (http_addr, socks_addr, admin_addr);
}

Expand Down Expand Up @@ -179,26 +176,14 @@ pub struct RuntimeConfig {
}

pub fn resolve_runtime(cfg: &NetworkProxyConfig) -> Result<RuntimeConfig> {
let http_addr = resolve_addr(&cfg.network_proxy.proxy_url, 3128).with_context(|| {
format!(
"invalid network_proxy.proxy_url: {}",
cfg.network_proxy.proxy_url
)
})?;
let socks_addr = resolve_addr(&cfg.network_proxy.socks_url, 8081).with_context(|| {
format!(
"invalid network_proxy.socks_url: {}",
cfg.network_proxy.socks_url
)
})?;
let admin_addr = resolve_addr(&cfg.network_proxy.admin_url, 8080).with_context(|| {
format!(
"invalid network_proxy.admin_url: {}",
cfg.network_proxy.admin_url
)
})?;
let http_addr = resolve_addr(&cfg.network.proxy_url, 3128)
.with_context(|| format!("invalid network.proxy_url: {}", cfg.network.proxy_url))?;
let socks_addr = resolve_addr(&cfg.network.socks_url, 8081)
.with_context(|| format!("invalid network.socks_url: {}", cfg.network.socks_url))?;
let admin_addr = resolve_addr(&cfg.network.admin_url, 8080)
.with_context(|| format!("invalid network.admin_url: {}", cfg.network.admin_url))?;
let (http_addr, socks_addr, admin_addr) =
clamp_bind_addrs(http_addr, socks_addr, admin_addr, &cfg.network_proxy);
clamp_bind_addrs(http_addr, socks_addr, admin_addr, &cfg.network);

Ok(RuntimeConfig {
http_addr,
Expand Down Expand Up @@ -453,10 +438,7 @@ mod tests {
let cfg = NetworkProxySettings {
dangerously_allow_non_loopback_proxy: true,
dangerously_allow_non_loopback_admin: true,
policy: NetworkPolicy {
allow_unix_sockets: vec!["/tmp/docker.sock".to_string()],
..Default::default()
},
allow_unix_sockets: vec!["/tmp/docker.sock".to_string()],
..Default::default()
};
let http_addr = "0.0.0.0:3128".parse::<SocketAddr>().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/network-proxy/src/http_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ mod tests {
use super::*;

use crate::config::NetworkMode;
use crate::config::NetworkPolicy;
use crate::config::NetworkProxySettings;
use crate::runtime::network_proxy_state_for_policy;
use pretty_assertions::assert_eq;
use rama_http::Method;
Expand All @@ -697,7 +697,7 @@ mod tests {

#[tokio::test]
async fn http_connect_accept_blocks_in_limited_mode() {
let policy = NetworkPolicy {
let policy = NetworkProxySettings {
allowed_domains: vec!["example.com".to_string()],
..Default::default()
};
Expand Down
12 changes: 6 additions & 6 deletions codex-rs/network-proxy/src/network_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ fn map_decider_decision(decision: NetworkDecision) -> NetworkDecision {
mod tests {
use super::*;

use crate::config::NetworkPolicy;
use crate::config::NetworkProxySettings;
use crate::reasons::REASON_DENIED;
use crate::reasons::REASON_NOT_ALLOWED_LOCAL;
use crate::state::network_proxy_state_for_policy;
Expand All @@ -228,7 +228,7 @@ mod tests {

#[tokio::test]
async fn evaluate_host_policy_invokes_decider_for_not_allowed() {
let state = network_proxy_state_for_policy(NetworkPolicy::default());
let state = network_proxy_state_for_policy(NetworkProxySettings::default());
let calls = Arc::new(AtomicUsize::new(0));
let decider: Arc<dyn NetworkPolicyDecider> = Arc::new({
let calls = calls.clone();
Expand Down Expand Up @@ -259,10 +259,10 @@ mod tests {

#[tokio::test]
async fn evaluate_host_policy_skips_decider_for_denied() {
let state = network_proxy_state_for_policy(NetworkPolicy {
let state = network_proxy_state_for_policy(NetworkProxySettings {
allowed_domains: vec!["example.com".to_string()],
denied_domains: vec!["blocked.com".to_string()],
..NetworkPolicy::default()
..NetworkProxySettings::default()
});
let calls = Arc::new(AtomicUsize::new(0));
let decider: Arc<dyn NetworkPolicyDecider> = Arc::new({
Expand Down Expand Up @@ -299,10 +299,10 @@ mod tests {

#[tokio::test]
async fn evaluate_host_policy_skips_decider_for_not_allowed_local() {
let state = network_proxy_state_for_policy(NetworkPolicy {
let state = network_proxy_state_for_policy(NetworkProxySettings {
allowed_domains: vec!["example.com".to_string()],
allow_local_binding: false,
..NetworkPolicy::default()
..NetworkProxySettings::default()
});
let calls = Arc::new(AtomicUsize::new(0));
let decider: Arc<dyn NetworkPolicyDecider> = Arc::new({
Expand Down
10 changes: 5 additions & 5 deletions codex-rs/network-proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl NetworkProxyBuilder {
self.http_addr.unwrap_or(runtime.http_addr),
runtime.socks_addr,
self.admin_addr.unwrap_or(runtime.admin_addr),
&current_cfg.network_proxy,
&current_cfg.network,
);

Ok(NetworkProxy {
Expand Down Expand Up @@ -95,8 +95,8 @@ impl NetworkProxy {

pub async fn run(&self) -> Result<NetworkProxyHandle> {
let current_cfg = self.state.current_cfg().await?;
if !current_cfg.network_proxy.enabled {
warn!("network_proxy.enabled is false; skipping proxy listeners");
if !current_cfg.network.enabled {
warn!("network.enabled is false; skipping proxy listeners");
return Ok(NetworkProxyHandle::noop());
}

Expand All @@ -109,12 +109,12 @@ impl NetworkProxy {
self.http_addr,
self.policy_decider.clone(),
));
let socks_task = if current_cfg.network_proxy.enable_socks5 {
let socks_task = if current_cfg.network.enable_socks5 {
Some(tokio::spawn(socks5::run_socks5(
self.state.clone(),
self.socks_addr,
self.policy_decider.clone(),
current_cfg.network_proxy.enable_socks5_udp,
current_cfg.network.enable_socks5_udp,
)))
} else {
None
Expand Down
Loading
Loading