mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
Add MITM hook config model
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use codex_network_proxy::MitmHookConfig;
|
||||||
use codex_network_proxy::NetworkDomainPermission as ProxyNetworkDomainPermission;
|
use codex_network_proxy::NetworkDomainPermission as ProxyNetworkDomainPermission;
|
||||||
use codex_network_proxy::NetworkMode;
|
use codex_network_proxy::NetworkMode;
|
||||||
use codex_network_proxy::NetworkProxyConfig;
|
use codex_network_proxy::NetworkProxyConfig;
|
||||||
@@ -158,6 +159,9 @@ pub struct NetworkToml {
|
|||||||
pub domains: Option<NetworkDomainPermissionsToml>,
|
pub domains: Option<NetworkDomainPermissionsToml>,
|
||||||
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
|
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
|
||||||
pub allow_local_binding: Option<bool>,
|
pub allow_local_binding: Option<bool>,
|
||||||
|
pub mitm: Option<bool>,
|
||||||
|
#[schemars(with = "Option<Vec<MitmHookConfigSchema>>")]
|
||||||
|
pub mitm_hooks: Option<Vec<MitmHookConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
@@ -167,6 +171,46 @@ enum NetworkModeSchema {
|
|||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct MitmHookConfigSchema {
|
||||||
|
pub host: String,
|
||||||
|
#[serde(rename = "match", default)]
|
||||||
|
pub matcher: MitmHookMatchConfigSchema,
|
||||||
|
#[serde(default)]
|
||||||
|
pub actions: MitmHookActionsConfigSchema,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct MitmHookMatchConfigSchema {
|
||||||
|
pub methods: Vec<String>,
|
||||||
|
pub path_prefixes: Vec<String>,
|
||||||
|
pub query: BTreeMap<String, Vec<String>>,
|
||||||
|
pub headers: BTreeMap<String, Vec<String>>,
|
||||||
|
pub body: Option<MitmHookBodyConfigSchema>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct MitmHookActionsConfigSchema {
|
||||||
|
pub strip_request_headers: Vec<String>,
|
||||||
|
pub inject_request_headers: Vec<InjectedHeaderConfigSchema>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(default)]
|
||||||
|
struct InjectedHeaderConfigSchema {
|
||||||
|
pub name: String,
|
||||||
|
pub secret_env_var: Option<String>,
|
||||||
|
pub secret_file: Option<String>,
|
||||||
|
pub prefix: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
struct MitmHookBodyConfigSchema(pub serde_json::Value);
|
||||||
|
|
||||||
impl NetworkToml {
|
impl NetworkToml {
|
||||||
pub fn apply_to_network_proxy_config(&self, config: &mut NetworkProxyConfig) {
|
pub fn apply_to_network_proxy_config(&self, config: &mut NetworkProxyConfig) {
|
||||||
if let Some(enabled) = self.enabled {
|
if let Some(enabled) = self.enabled {
|
||||||
@@ -219,6 +263,12 @@ impl NetworkToml {
|
|||||||
if let Some(allow_local_binding) = self.allow_local_binding {
|
if let Some(allow_local_binding) = self.allow_local_binding {
|
||||||
config.network.allow_local_binding = allow_local_binding;
|
config.network.allow_local_binding = allow_local_binding;
|
||||||
}
|
}
|
||||||
|
if let Some(mitm) = self.mitm {
|
||||||
|
config.network.mitm = mitm;
|
||||||
|
}
|
||||||
|
if let Some(mitm_hooks) = self.mitm_hooks.as_ref() {
|
||||||
|
config.network.mitm_hooks = mitm_hooks.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_network_proxy_config(&self) -> NetworkProxyConfig {
|
pub fn to_network_proxy_config(&self) -> NetworkProxyConfig {
|
||||||
|
|||||||
@@ -1098,6 +1098,27 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"InjectedHeaderConfigSchema": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"default": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"prefix": {
|
||||||
|
"default": null,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"secret_env_var": {
|
||||||
|
"default": null,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"secret_file": {
|
||||||
|
"default": null,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"KeybindingsSpec": {
|
"KeybindingsSpec": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
@@ -1278,6 +1299,101 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"MitmHookActionsConfigSchema": {
|
||||||
|
"properties": {
|
||||||
|
"inject_request_headers": {
|
||||||
|
"default": [],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/InjectedHeaderConfigSchema"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"strip_request_headers": {
|
||||||
|
"default": [],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"MitmHookConfigSchema": {
|
||||||
|
"properties": {
|
||||||
|
"actions": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MitmHookActionsConfigSchema"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {
|
||||||
|
"inject_request_headers": [],
|
||||||
|
"strip_request_headers": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"default": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"match": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MitmHookMatchConfigSchema"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {
|
||||||
|
"body": null,
|
||||||
|
"headers": {},
|
||||||
|
"methods": [],
|
||||||
|
"path_prefixes": [],
|
||||||
|
"query": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"MitmHookMatchConfigSchema": {
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"default": null
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"additionalProperties": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"default": {},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"methods": {
|
||||||
|
"default": [],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"path_prefixes": {
|
||||||
|
"default": [],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"additionalProperties": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"default": {},
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"ModelAvailabilityNuxConfig": {
|
"ModelAvailabilityNuxConfig": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"format": "uint32",
|
"format": "uint32",
|
||||||
@@ -1616,6 +1732,15 @@
|
|||||||
"enabled": {
|
"enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"mitm": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"mitm_hooks": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/MitmHookConfigSchema"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
"mode": {
|
"mode": {
|
||||||
"$ref": "#/definitions/NetworkModeSchema"
|
"$ref": "#/definitions/NetworkModeSchema"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ use codex_model_provider_info::LMSTUDIO_OSS_PROVIDER_ID;
|
|||||||
use codex_model_provider_info::OLLAMA_OSS_PROVIDER_ID;
|
use codex_model_provider_info::OLLAMA_OSS_PROVIDER_ID;
|
||||||
use codex_model_provider_info::WireApi;
|
use codex_model_provider_info::WireApi;
|
||||||
use codex_models_manager::bundled_models_response;
|
use codex_models_manager::bundled_models_response;
|
||||||
|
use codex_network_proxy::InjectedHeaderConfig;
|
||||||
|
use codex_network_proxy::MitmHookActionsConfig;
|
||||||
|
use codex_network_proxy::MitmHookConfig;
|
||||||
|
use codex_network_proxy::MitmHookMatchConfig;
|
||||||
|
use codex_network_proxy::NetworkMode;
|
||||||
use codex_protocol::config_types::ServiceTier;
|
use codex_protocol::config_types::ServiceTier;
|
||||||
use codex_protocol::models::ActivePermissionProfile;
|
use codex_protocol::models::ActivePermissionProfile;
|
||||||
use codex_protocol::models::ActivePermissionProfileModification;
|
use codex_protocol::models::ActivePermissionProfileModification;
|
||||||
@@ -727,9 +732,29 @@ enabled = true
|
|||||||
proxy_url = "http://127.0.0.1:43128"
|
proxy_url = "http://127.0.0.1:43128"
|
||||||
enable_socks5 = false
|
enable_socks5 = false
|
||||||
allow_upstream_proxy = false
|
allow_upstream_proxy = false
|
||||||
|
mode = "full"
|
||||||
|
mitm = true
|
||||||
|
|
||||||
[permissions.workspace.network.domains]
|
[permissions.workspace.network.domains]
|
||||||
"openai.com" = "allow"
|
"openai.com" = "allow"
|
||||||
|
|
||||||
|
[[permissions.workspace.network.mitm_hooks]]
|
||||||
|
host = "api.github.com"
|
||||||
|
|
||||||
|
[permissions.workspace.network.mitm_hooks.match]
|
||||||
|
methods = ["POST", "PUT"]
|
||||||
|
path_prefixes = ["/repos/openai/"]
|
||||||
|
|
||||||
|
[permissions.workspace.network.mitm_hooks.match.headers]
|
||||||
|
"x-github-api-version" = ["2022-11-28"]
|
||||||
|
|
||||||
|
[permissions.workspace.network.mitm_hooks.actions]
|
||||||
|
strip_request_headers = ["authorization"]
|
||||||
|
|
||||||
|
[[permissions.workspace.network.mitm_hooks.actions.inject_request_headers]]
|
||||||
|
name = "authorization"
|
||||||
|
secret_env_var = "CODEX_GITHUB_TOKEN"
|
||||||
|
prefix = "Bearer "
|
||||||
"#;
|
"#;
|
||||||
let cfg: ConfigToml =
|
let cfg: ConfigToml =
|
||||||
toml::from_str(toml).expect("TOML deserialization should succeed for permissions profiles");
|
toml::from_str(toml).expect("TOML deserialization should succeed for permissions profiles");
|
||||||
@@ -766,7 +791,7 @@ allow_upstream_proxy = false
|
|||||||
allow_upstream_proxy: Some(false),
|
allow_upstream_proxy: Some(false),
|
||||||
dangerously_allow_non_loopback_proxy: None,
|
dangerously_allow_non_loopback_proxy: None,
|
||||||
dangerously_allow_all_unix_sockets: None,
|
dangerously_allow_all_unix_sockets: None,
|
||||||
mode: None,
|
mode: Some(NetworkMode::Full),
|
||||||
domains: Some(NetworkDomainPermissionsToml {
|
domains: Some(NetworkDomainPermissionsToml {
|
||||||
entries: BTreeMap::from([(
|
entries: BTreeMap::from([(
|
||||||
"openai.com".to_string(),
|
"openai.com".to_string(),
|
||||||
@@ -775,6 +800,29 @@ allow_upstream_proxy = false
|
|||||||
}),
|
}),
|
||||||
unix_sockets: None,
|
unix_sockets: None,
|
||||||
allow_local_binding: None,
|
allow_local_binding: None,
|
||||||
|
mitm: Some(true),
|
||||||
|
mitm_hooks: Some(vec![MitmHookConfig {
|
||||||
|
host: "api.github.com".to_string(),
|
||||||
|
matcher: MitmHookMatchConfig {
|
||||||
|
methods: vec!["POST".to_string(), "PUT".to_string()],
|
||||||
|
path_prefixes: vec!["/repos/openai/".to_string()],
|
||||||
|
query: BTreeMap::new(),
|
||||||
|
headers: BTreeMap::from([(
|
||||||
|
"x-github-api-version".to_string(),
|
||||||
|
vec!["2022-11-28".to_string()],
|
||||||
|
)]),
|
||||||
|
body: None,
|
||||||
|
},
|
||||||
|
actions: MitmHookActionsConfig {
|
||||||
|
strip_request_headers: vec!["authorization".to_string()],
|
||||||
|
inject_request_headers: vec![InjectedHeaderConfig {
|
||||||
|
name: "authorization".to_string(),
|
||||||
|
secret_env_var: Some("CODEX_GITHUB_TOKEN".to_string()),
|
||||||
|
secret_file: None,
|
||||||
|
prefix: Some("Bearer ".to_string()),
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
}]),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
)]),
|
)]),
|
||||||
@@ -782,6 +830,38 @@ allow_upstream_proxy = false
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn permissions_profile_network_to_proxy_config_preserves_mitm_hooks() {
|
||||||
|
let network = NetworkToml {
|
||||||
|
mode: Some(NetworkMode::Full),
|
||||||
|
mitm: Some(true),
|
||||||
|
mitm_hooks: Some(vec![MitmHookConfig {
|
||||||
|
host: "api.github.com".to_string(),
|
||||||
|
matcher: MitmHookMatchConfig {
|
||||||
|
methods: vec!["POST".to_string()],
|
||||||
|
path_prefixes: vec!["/repos/openai/".to_string()],
|
||||||
|
..MitmHookMatchConfig::default()
|
||||||
|
},
|
||||||
|
actions: MitmHookActionsConfig {
|
||||||
|
strip_request_headers: vec!["authorization".to_string()],
|
||||||
|
inject_request_headers: vec![InjectedHeaderConfig {
|
||||||
|
name: "authorization".to_string(),
|
||||||
|
secret_env_var: Some("CODEX_GITHUB_TOKEN".to_string()),
|
||||||
|
secret_file: None,
|
||||||
|
prefix: Some("Bearer ".to_string()),
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
..NetworkToml::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = network.to_network_proxy_config();
|
||||||
|
|
||||||
|
assert_eq!(config.network.mode, NetworkMode::Full);
|
||||||
|
assert!(config.network.mitm);
|
||||||
|
assert_eq!(config.network.mitm_hooks, network.mitm_hooks.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn permissions_profiles_proxy_policy_does_not_start_managed_network_proxy_without_feature()
|
async fn permissions_profiles_proxy_policy_does_not_start_managed_network_proxy_without_feature()
|
||||||
-> std::io::Result<()> {
|
-> std::io::Result<()> {
|
||||||
|
|||||||
@@ -104,6 +104,75 @@ default_permissions = "workspace"
|
|||||||
assert_eq!(config.network.denied_domains(), None);
|
assert_eq!(config.network.denied_domains(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn higher_precedence_profile_network_overrides_mitm_hooks() {
|
||||||
|
let lower_network: toml::Value = toml::from_str(
|
||||||
|
r#"
|
||||||
|
default_permissions = "workspace"
|
||||||
|
|
||||||
|
[permissions.workspace.network]
|
||||||
|
mode = "limited"
|
||||||
|
mitm = false
|
||||||
|
|
||||||
|
[permissions.workspace.network.domains]
|
||||||
|
"lower.example.com" = "allow"
|
||||||
|
|
||||||
|
[[permissions.workspace.network.mitm_hooks]]
|
||||||
|
host = "lower.example.com"
|
||||||
|
|
||||||
|
[permissions.workspace.network.mitm_hooks.match]
|
||||||
|
methods = ["POST"]
|
||||||
|
path_prefixes = ["/repos/openai/"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("lower layer should parse");
|
||||||
|
let higher_network: toml::Value = toml::from_str(
|
||||||
|
r#"
|
||||||
|
default_permissions = "workspace"
|
||||||
|
|
||||||
|
[permissions.workspace.network]
|
||||||
|
mode = "full"
|
||||||
|
mitm = true
|
||||||
|
|
||||||
|
[permissions.workspace.network.domains]
|
||||||
|
"higher.example.com" = "allow"
|
||||||
|
|
||||||
|
[[permissions.workspace.network.mitm_hooks]]
|
||||||
|
host = "api.github.com"
|
||||||
|
|
||||||
|
[permissions.workspace.network.mitm_hooks.match]
|
||||||
|
methods = ["PUT"]
|
||||||
|
path_prefixes = ["/repos/openai/"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("higher layer should parse");
|
||||||
|
|
||||||
|
let mut config = NetworkProxyConfig::default();
|
||||||
|
apply_network_tables(
|
||||||
|
&mut config,
|
||||||
|
network_tables_from_toml(&lower_network).expect("lower layer should deserialize"),
|
||||||
|
)
|
||||||
|
.expect("lower layer should apply");
|
||||||
|
apply_network_tables(
|
||||||
|
&mut config,
|
||||||
|
network_tables_from_toml(&higher_network).expect("higher layer should deserialize"),
|
||||||
|
)
|
||||||
|
.expect("higher layer should apply");
|
||||||
|
|
||||||
|
assert_eq!(config.network.mode, codex_network_proxy::NetworkMode::Full);
|
||||||
|
assert!(config.network.mitm);
|
||||||
|
assert_eq!(
|
||||||
|
config.network.allowed_domains(),
|
||||||
|
Some(vec![
|
||||||
|
"lower.example.com".to_string(),
|
||||||
|
"higher.example.com".to_string()
|
||||||
|
])
|
||||||
|
);
|
||||||
|
assert_eq!(config.network.mitm_hooks.len(), 1);
|
||||||
|
assert_eq!(config.network.mitm_hooks[0].host, "api.github.com");
|
||||||
|
assert_eq!(config.network.mitm_hooks[0].matcher.methods, vec!["PUT"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn execpolicy_network_rules_overlay_network_lists() {
|
fn execpolicy_network_rules_overlay_network_lists() {
|
||||||
let mut config = NetworkProxyConfig::default();
|
let mut config = NetworkProxyConfig::default();
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ use std::path::Path;
|
|||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::mitm_hook::MitmHookConfig;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||||
pub struct NetworkProxyConfig {
|
pub struct NetworkProxyConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -139,6 +141,8 @@ pub struct NetworkProxySettings {
|
|||||||
pub allow_local_binding: bool,
|
pub allow_local_binding: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub mitm: bool,
|
pub mitm: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub mitm_hooks: Vec<MitmHookConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NetworkProxySettings {
|
impl Default for NetworkProxySettings {
|
||||||
@@ -157,6 +161,7 @@ impl Default for NetworkProxySettings {
|
|||||||
unix_sockets: None,
|
unix_sockets: None,
|
||||||
allow_local_binding: false,
|
allow_local_binding: false,
|
||||||
mitm: false,
|
mitm: false,
|
||||||
|
mitm_hooks: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,8 +278,8 @@ pub enum NetworkMode {
|
|||||||
/// blocked unless MITM is enabled so the proxy can enforce method policy on inner requests.
|
/// blocked unless MITM is enabled so the proxy can enforce method policy on inner requests.
|
||||||
/// SOCKS5 remains blocked in limited mode.
|
/// SOCKS5 remains blocked in limited mode.
|
||||||
Limited,
|
Limited,
|
||||||
/// Full network access: all HTTP methods are allowed, and HTTPS CONNECTs are tunneled without
|
/// Full network access: all HTTP methods are allowed. HTTPS CONNECTs are tunneled directly
|
||||||
/// MITM interception.
|
/// unless MITM is needed for host-specific inner-request hooks.
|
||||||
#[default]
|
#[default]
|
||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
@@ -588,6 +593,7 @@ mod tests {
|
|||||||
unix_sockets: None,
|
unix_sockets: None,
|
||||||
allow_local_binding: false,
|
allow_local_binding: false,
|
||||||
mitm: false,
|
mitm: false,
|
||||||
|
mitm_hooks: Vec::new(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -652,6 +658,7 @@ mod tests {
|
|||||||
"unix_sockets": null,
|
"unix_sockets": null,
|
||||||
"allow_local_binding": false,
|
"allow_local_binding": false,
|
||||||
"mitm": false,
|
"mitm": false,
|
||||||
|
"mitm_hooks": [],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod config;
|
|||||||
mod connect_policy;
|
mod connect_policy;
|
||||||
mod http_proxy;
|
mod http_proxy;
|
||||||
mod mitm;
|
mod mitm;
|
||||||
|
mod mitm_hook;
|
||||||
mod network_policy;
|
mod network_policy;
|
||||||
mod policy;
|
mod policy;
|
||||||
mod proxy;
|
mod proxy;
|
||||||
@@ -23,6 +24,11 @@ pub use config::NetworkProxyConfig;
|
|||||||
pub use config::NetworkUnixSocketPermission;
|
pub use config::NetworkUnixSocketPermission;
|
||||||
pub use config::NetworkUnixSocketPermissions;
|
pub use config::NetworkUnixSocketPermissions;
|
||||||
pub use config::host_and_port_from_network_addr;
|
pub use config::host_and_port_from_network_addr;
|
||||||
|
pub use mitm_hook::InjectedHeaderConfig;
|
||||||
|
pub use mitm_hook::MitmHookActionsConfig;
|
||||||
|
pub use mitm_hook::MitmHookBodyConfig;
|
||||||
|
pub use mitm_hook::MitmHookConfig;
|
||||||
|
pub use mitm_hook::MitmHookMatchConfig;
|
||||||
pub use network_policy::NetworkDecision;
|
pub use network_policy::NetworkDecision;
|
||||||
pub use network_policy::NetworkDecisionSource;
|
pub use network_policy::NetworkDecisionSource;
|
||||||
pub use network_policy::NetworkPolicyDecider;
|
pub use network_policy::NetworkPolicyDecider;
|
||||||
|
|||||||
1047
codex-rs/network-proxy/src/mitm_hook.rs
Normal file
1047
codex-rs/network-proxy/src/mitm_hook.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ use crate::config::NetworkProxyConfig;
|
|||||||
use crate::config::NetworkUnixSocketPermissions;
|
use crate::config::NetworkUnixSocketPermissions;
|
||||||
use crate::mitm::MitmState;
|
use crate::mitm::MitmState;
|
||||||
use crate::mitm::MitmUpstreamConfig;
|
use crate::mitm::MitmUpstreamConfig;
|
||||||
|
use crate::mitm_hook::MitmHookConfig;
|
||||||
|
use crate::mitm_hook::validate_mitm_hook_config;
|
||||||
use crate::policy::DomainPattern;
|
use crate::policy::DomainPattern;
|
||||||
use crate::policy::compile_allowlist_globset;
|
use crate::policy::compile_allowlist_globset;
|
||||||
use crate::policy::compile_denylist_globset;
|
use crate::policy::compile_denylist_globset;
|
||||||
@@ -53,6 +55,9 @@ pub struct PartialNetworkConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub unix_sockets: Option<NetworkUnixSocketPermissions>,
|
pub unix_sockets: Option<NetworkUnixSocketPermissions>,
|
||||||
pub allow_local_binding: Option<bool>,
|
pub allow_local_binding: Option<bool>,
|
||||||
|
pub mitm: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub mitm_hooks: Option<Vec<MitmHookConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_config_state(
|
pub fn build_config_state(
|
||||||
@@ -116,6 +121,7 @@ pub fn validate_policy_against_constraints(
|
|||||||
.map(|entry| entry.to_ascii_lowercase())
|
.map(|entry| entry.to_ascii_lowercase())
|
||||||
.collect();
|
.collect();
|
||||||
let config_allow_unix_sockets = config.network.allow_unix_sockets();
|
let config_allow_unix_sockets = config.network.allow_unix_sockets();
|
||||||
|
validate_mitm_hook_config(config).map_err(invalid_mitm_hook_configuration)?;
|
||||||
validate_non_global_wildcard_domain_patterns("network.denied_domains", &config_denied_domains)?;
|
validate_non_global_wildcard_domain_patterns("network.denied_domains", &config_denied_domains)?;
|
||||||
if let Some(max_enabled) = constraints.enabled {
|
if let Some(max_enabled) = constraints.enabled {
|
||||||
validate(enabled, move |candidate| {
|
validate(enabled, move |candidate| {
|
||||||
@@ -376,6 +382,14 @@ pub fn validate_policy_against_constraints(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalid_mitm_hook_configuration(err: anyhow::Error) -> NetworkProxyConstraintError {
|
||||||
|
NetworkProxyConstraintError::InvalidValue {
|
||||||
|
field_name: "network.mitm_hooks",
|
||||||
|
candidate: err.to_string(),
|
||||||
|
allowed: "valid MITM hook configuration".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_non_global_wildcard_domain_patterns(
|
fn validate_non_global_wildcard_domain_patterns(
|
||||||
field_name: &'static str,
|
field_name: &'static str,
|
||||||
patterns: &[String],
|
patterns: &[String],
|
||||||
|
|||||||
Reference in New Issue
Block a user