fix(network-proxy): add unix socket allow-all and update seatbelt rules (#11368)

## Summary
Adds support for a Unix socket escape hatch so we can bypass socket
allowlisting when explicitly enabled.

## Description
* added a new flag, `network.dangerously_allow_all_unix_sockets` as an
explicit escape hatch
* In codex-network-proxy, enabling that flag now allows any absolute
Unix socket path from x-unix-socket instead of requiring each path to be
explicitly allowlisted. Relative paths are still rejected.
* updated the macOS seatbelt path in core so it enforces the same Unix
socket behavior:
  * allowlisted sockets generate explicit network* subpath rules
  * allow-all generates a broad network* (subpath "/") rule

---------

Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
This commit is contained in:
viyatb-oai
2026-02-20 10:56:57 -08:00
committed by GitHub
parent 73fd939296
commit 28c0089060
19 changed files with 553 additions and 18 deletions

View File

@@ -1,5 +1,6 @@
use crate::config::NetworkMode;
use crate::config::NetworkProxyConfig;
use crate::config::ValidatedUnixSocketPath;
use crate::policy::Host;
use crate::policy::is_loopback_host;
use crate::policy::is_non_public_ip;
@@ -418,6 +419,10 @@ impl NetworkProxyState {
}
let guard = self.state.read().await;
if guard.config.network.dangerously_allow_all_unix_sockets {
return Ok(true);
}
// Normalize the path while keeping the absolute-path requirement explicit.
let requested_abs = match AbsolutePathBuf::from_absolute_path(requested_path) {
Ok(path) => path,
@@ -425,7 +430,16 @@ impl NetworkProxyState {
};
let requested_canonical = std::fs::canonicalize(requested_abs.as_path()).ok();
for allowed in &guard.config.network.allow_unix_sockets {
if allowed == path {
let allowed_path = match ValidatedUnixSocketPath::parse(allowed) {
Ok(ValidatedUnixSocketPath::Native(path)) => path,
Ok(ValidatedUnixSocketPath::UnixStyleAbsolute(_)) => continue,
Err(err) => {
warn!("ignoring invalid network.allow_unix_sockets entry at runtime: {err:#}");
continue;
}
};
if allowed_path.as_path() == requested_abs.as_path() {
return Ok(true);
}
@@ -434,7 +448,7 @@ impl NetworkProxyState {
let Some(requested_canonical) = &requested_canonical else {
continue;
};
if let Ok(allowed_canonical) = std::fs::canonicalize(allowed)
if let Ok(allowed_canonical) = std::fs::canonicalize(allowed_path.as_path())
&& &allowed_canonical == requested_canonical
{
return Ok(true);
@@ -1075,6 +1089,77 @@ mod tests {
assert!(validate_policy_against_constraints(&config, &constraints).is_ok());
}
#[test]
fn validate_policy_against_constraints_disallows_allow_all_unix_sockets_without_managed_opt_in()
{
let constraints = NetworkProxyConstraints {
dangerously_allow_all_unix_sockets: Some(false),
..NetworkProxyConstraints::default()
};
let config = NetworkProxyConfig {
network: NetworkProxySettings {
enabled: true,
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
},
};
assert!(validate_policy_against_constraints(&config, &constraints).is_err());
}
#[test]
fn validate_policy_against_constraints_disallows_allow_all_unix_sockets_when_allowlist_is_managed()
{
let constraints = NetworkProxyConstraints {
allow_unix_sockets: Some(vec!["/tmp/allowed.sock".to_string()]),
..NetworkProxyConstraints::default()
};
let config = NetworkProxyConfig {
network: NetworkProxySettings {
enabled: true,
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
},
};
assert!(validate_policy_against_constraints(&config, &constraints).is_err());
}
#[test]
fn validate_policy_against_constraints_allows_allow_all_unix_sockets_with_managed_opt_in() {
let constraints = NetworkProxyConstraints {
dangerously_allow_all_unix_sockets: Some(true),
..NetworkProxyConstraints::default()
};
let config = NetworkProxyConfig {
network: NetworkProxySettings {
enabled: true,
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
},
};
assert!(validate_policy_against_constraints(&config, &constraints).is_ok());
}
#[test]
fn validate_policy_against_constraints_allows_allow_all_unix_sockets_when_unmanaged() {
let constraints = NetworkProxyConstraints::default();
let config = NetworkProxyConfig {
network: NetworkProxySettings {
enabled: true,
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
},
};
assert!(validate_policy_against_constraints(&config, &constraints).is_ok());
}
#[test]
fn compile_globset_is_case_insensitive() {
let patterns = vec!["ExAmPle.CoM".to_string()];
@@ -1172,6 +1257,19 @@ mod tests {
assert!(state.is_unix_socket_allowed(&link_s).await.unwrap());
}
#[cfg(target_os = "macos")]
#[tokio::test]
async fn unix_socket_allow_all_flag_bypasses_allowlist() {
let state = network_proxy_state_for_policy(NetworkProxySettings {
allowed_domains: vec!["example.com".to_string()],
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
});
assert!(state.is_unix_socket_allowed("/tmp/any.sock").await.unwrap());
assert!(!state.is_unix_socket_allowed("relative.sock").await.unwrap());
}
#[cfg(not(target_os = "macos"))]
#[tokio::test]
async fn unix_socket_allowlist_is_rejected_on_non_macos() {
@@ -1179,6 +1277,7 @@ mod tests {
let state = network_proxy_state_for_policy(NetworkProxySettings {
allowed_domains: vec!["example.com".to_string()],
allow_unix_sockets: vec![socket_path.clone()],
dangerously_allow_all_unix_sockets: true,
..NetworkProxySettings::default()
});