mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## What changed - Add optional `network.mitm_ca` configuration with `certificate_file` and `private_key_file` for trusted proxy configuration. Require MITM to be enabled and retain the generated CA when no external CA is configured. - Validate absolute paths, regular files, file sizes, certificate/key matching, and Unix private-key permissions. Reject symlinks on Unix, private keys embedded in certificate files, and external private keys on non-Unix platforms. - Store derived external-CA trust bundles in the proxy artifact directory, include only certificates, and skip inherited generated bundles to avoid retaining stale roots. - Preserve MITM for external CAs when disabling credential brokerage. Reject external CA configuration for remote execution, even when the proxy is disabled, and reject unknown fields in `NetworkProxyConfig`. - Default the upstream request version adapter to HTTP/1.1 and remove the request URI from upstream request failure context. ## Testing Add regression coverage for external CA configuration, mismatched keys, embedded private keys, non-Unix rejection, trust-bundle placement and contents, stale-root exclusion, credential-broker toggling, and remote configuration rejection. GitOrigin-RevId: cb209295c19fbe53a9fa0194f11ff06acccabef6
146 lines
4.2 KiB
Rust
146 lines
4.2 KiB
Rust
use super::parse_standalone_config;
|
|
use codex_network_proxy::NetworkMitmCaConfig;
|
|
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})).unwrap();
|
|
let config = parse_standalone_config(&bytes).unwrap();
|
|
assert_eq!(
|
|
(config.network.mitm, config.network.mitm_ca),
|
|
(expected_mitm, expected_ca)
|
|
);
|
|
}
|
|
}
|
|
|
|
#[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"]}
|
|
}
|
|
}]
|
|
}
|
|
}))
|
|
.unwrap();
|
|
|
|
let config = parse_standalone_config(&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 rejects_unknown_fields_at_every_mitm_hook_level() {
|
|
for (network, unknown_field) in [
|
|
(
|
|
json!({"enabled": true, "unexpected_network": true}),
|
|
"unexpected_network",
|
|
),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mitm_hooks": [{
|
|
"host": "api.example.com",
|
|
"unexpected_hook": true
|
|
}]
|
|
}),
|
|
"unexpected_hook",
|
|
),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mitm_hooks": [{
|
|
"host": "api.example.com",
|
|
"match": {"unexpected_matcher": true}
|
|
}]
|
|
}),
|
|
"unexpected_matcher",
|
|
),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mitm_hooks": [{
|
|
"host": "api.example.com",
|
|
"actions": {"unexpected_action": true}
|
|
}]
|
|
}),
|
|
"unexpected_action",
|
|
),
|
|
(
|
|
json!({
|
|
"enabled": true,
|
|
"mitm_hooks": [{
|
|
"host": "api.example.com",
|
|
"actions": {
|
|
"inject_request_headers": [{
|
|
"name": "authorization",
|
|
"unexpected_header": true
|
|
}]
|
|
}
|
|
}]
|
|
}),
|
|
"unexpected_header",
|
|
),
|
|
] {
|
|
let bytes = serde_json::to_vec(&json!({"network": network})).unwrap();
|
|
let error = parse_standalone_config(&bytes).unwrap_err();
|
|
assert!(
|
|
error.to_string().contains(unknown_field),
|
|
"expected {unknown_field} in {error}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_trailing_json_values() {
|
|
let error = parse_standalone_config(br#"{"network":{"enabled":true}} {}"#).unwrap_err();
|
|
assert!(error.to_string().contains("trailing characters"));
|
|
}
|