mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
## What changed - Export `StaticNetworkProxyConfig` to parse and serialize network policy with constraints, and validate them before building proxy state. - Add `--strict` and `from_slice_strict` for managed callers, requiring explicit `constraints` and rejecting unknown fields at every typed level. Default parsing permits top-level `metadata` and omitted constraints while still rejecting unknown policy fields. - Match allowed Unix socket paths case-sensitively when validating constraints. - Bound configuration file reads to the size limit plus one byte. ## Testing Add coverage for constraint round trips, weakened policy rejection, exact socket path matching, parsing modes, and CLI flag selection. Exercise automatic MITM enablement through both parsers. GitOrigin-RevId: c45d094624240f23dd4659128e72a4208d5d5f1c
104 lines
3.2 KiB
Rust
104 lines
3.2 KiB
Rust
use clap::Parser;
|
|
use codex_network_proxy::NetworkMitmCaConfig;
|
|
use codex_network_proxy::StaticNetworkProxyConfig;
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn enables_mitm_for_limited_mode_and_hooks() {
|
|
for (network, expected_mitm, expected_ca) in [
|
|
(json!({"enabled": true, "mode": "full"}), false, None),
|
|
(
|
|
json!({"enabled": true, "mode": "full", "mitm": true}),
|
|
true,
|
|
None,
|
|
),
|
|
(json!({"enabled": true, "mode": "limited"}), true, None),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mitm_hooks": [{"host": "api.example.com"}]
|
|
}),
|
|
true,
|
|
None,
|
|
),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mode": "limited",
|
|
"mitm_ca": {
|
|
"certificate_file": "/run/proxy/ca.pem",
|
|
"private_key_file": "/run/proxy/key.pem"
|
|
}
|
|
}),
|
|
true,
|
|
Some(NetworkMitmCaConfig {
|
|
certificate_file: "/run/proxy/ca.pem".to_string(),
|
|
private_key_file: "/run/proxy/key.pem".to_string(),
|
|
}),
|
|
),
|
|
] {
|
|
let bytes = serde_json::to_vec(&json!({"network": network, "constraints": {}})).unwrap();
|
|
for parse in [
|
|
StaticNetworkProxyConfig::from_slice,
|
|
StaticNetworkProxyConfig::from_slice_strict,
|
|
] {
|
|
let config = parse(&bytes).unwrap();
|
|
assert_eq!(
|
|
(config.network.mitm, config.network.mitm_ca),
|
|
(expected_mitm, expected_ca.clone())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn accepts_dynamic_domain_socket_and_hook_matcher_keys() {
|
|
let bytes = serde_json::to_vec(&json!({
|
|
"network": {
|
|
"enabled": true,
|
|
"domains": {"api.example.com": "allow"},
|
|
"unix_sockets": {"/tmp/example.sock": "allow"},
|
|
"mitm_hooks": [{
|
|
"host": "api.example.com",
|
|
"match": {
|
|
"query": {"scope": ["read"]},
|
|
"headers": {"authorization": ["Bearer token"]}
|
|
}
|
|
}]
|
|
},
|
|
"constraints": {}
|
|
}))
|
|
.unwrap();
|
|
|
|
let config = StaticNetworkProxyConfig::from_slice_strict(&bytes).unwrap();
|
|
|
|
assert_eq!(
|
|
config.network.allowed_domains(),
|
|
Some(vec!["api.example.com".to_string()])
|
|
);
|
|
assert_eq!(
|
|
config.network.allow_unix_sockets(),
|
|
vec!["/tmp/example.sock".to_string()]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn strict_flag_controls_config_parsing() {
|
|
let base = ["codex-network-proxy", "--config", "policy.json"];
|
|
let lenient = super::Args::try_parse_from(base).unwrap();
|
|
let strict = super::Args::try_parse_from(base.into_iter().chain(["--strict"])).unwrap();
|
|
for bytes in [
|
|
br#"{"network":{"enabled":true}}"#.as_slice(),
|
|
br#"{"network":{"enabled":true},"metadata":{"future_setting":true},"constraints":{}}"#,
|
|
] {
|
|
assert!(lenient.parse_config(bytes).is_ok());
|
|
assert!(strict.parse_config(bytes).is_err());
|
|
}
|
|
assert!(
|
|
strict
|
|
.parse_config(br#"{"network":{"enabled":true},"constraints":{}}"#)
|
|
.is_ok()
|
|
);
|
|
}
|