mirror of
https://github.com/openai/codex.git
synced 2026-05-01 03:42:05 +03:00
chore: refactor network permissions to use explicit domain and unix socket rule maps (#15120)
## Summary This PR replaces the legacy network allow/deny list model with explicit rule maps for domains and unix sockets across managed requirements, permissions profiles, the network proxy config, and the app server protocol. Concretely, it: - introduces typed domain (`allow` / `deny`) and unix socket permission (`allow` / `none`) entries instead of separate `allowed_domains`, `denied_domains`, and `allow_unix_sockets` lists - updates config loading, managed requirements merging, and exec-policy overlays to read and upsert rule entries consistently - exposes the new shape through protocol/schema outputs, debug surfaces, and app-server config APIs - rejects the legacy list-based keys and updates docs/tests to reflect the new config format ## Why The previous representation split related network policy across multiple parallel lists, which made merging and overriding rules harder to reason about. Moving to explicit keyed permission maps gives us a single source of truth per host/socket entry, makes allow/deny precedence clearer, and gives protocol consumers access to the full rule state instead of derived projections only. ## Backward Compatibility ### Backward compatible - Managed requirements still accept the legacy `experimental_network.allowed_domains`, `experimental_network.denied_domains`, and `experimental_network.allow_unix_sockets` fields. They are normalized into the new canonical `domains` and `unix_sockets` maps internally. - App-server v2 still deserializes legacy `allowedDomains`, `deniedDomains`, and `allowUnixSockets` payloads, so older clients can continue reading managed network requirements. - App-server v2 responses still populate `allowedDomains`, `deniedDomains`, and `allowUnixSockets` as legacy compatibility views derived from the canonical maps. - `managed_allowed_domains_only` keeps the same behavior after normalization. Legacy managed allowlists still participate in the same enforcement path as canonical `domains` entries. ### Not backward compatible - Permissions profiles under `[permissions.<profile>.network]` no longer accept the legacy list-based keys. Those configs must use the canonical `[domains]` and `[unix_sockets]` tables instead of `allowed_domains`, `denied_domains`, or `allow_unix_sockets`. - Managed `experimental_network` config cannot mix canonical and legacy forms in the same block. For example, `domains` cannot be combined with `allowed_domains` or `denied_domains`, and `unix_sockets` cannot be combined with `allow_unix_sockets`. - The canonical format can express explicit `"none"` entries for unix sockets, but those entries do not round-trip through the legacy compatibility fields because the legacy fields only represent allow/deny lists. ## Testing `/target/debug/codex sandbox macos --log-denials /bin/zsh -c 'curl https://www.example.com' ` gives 200 with config ``` [permissions.workspace.network.domains] "www.example.com" = "allow" ``` and fails when set to deny: `curl: (56) CONNECT tunnel failed, response 403`. Also tested backward compatibility path by verifying that adding the following to `/etc/codex/requirements.toml` works: ``` [experimental_network] allowed_domains = ["www.example.com"] ```
This commit is contained in:
@@ -5,6 +5,7 @@ use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde::de::Error as _;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
@@ -132,7 +133,93 @@ pub struct McpServerRequirement {
|
||||
pub identity: McpServerIdentity,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct NetworkDomainPermissionsToml {
|
||||
#[serde(flatten)]
|
||||
pub entries: BTreeMap<String, NetworkDomainPermissionToml>,
|
||||
}
|
||||
|
||||
impl NetworkDomainPermissionsToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entries.is_empty()
|
||||
}
|
||||
|
||||
pub fn allowed_domains(&self) -> Option<Vec<String>> {
|
||||
let allowed_domains: Vec<String> = self
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|(_, permission)| matches!(permission, NetworkDomainPermissionToml::Allow))
|
||||
.map(|(pattern, _)| pattern.clone())
|
||||
.collect();
|
||||
(!allowed_domains.is_empty()).then_some(allowed_domains)
|
||||
}
|
||||
|
||||
pub fn denied_domains(&self) -> Option<Vec<String>> {
|
||||
let denied_domains: Vec<String> = self
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|(_, permission)| matches!(permission, NetworkDomainPermissionToml::Deny))
|
||||
.map(|(pattern, _)| pattern.clone())
|
||||
.collect();
|
||||
(!denied_domains.is_empty()).then_some(denied_domains)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum NetworkDomainPermissionToml {
|
||||
Allow,
|
||||
Deny,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NetworkDomainPermissionToml {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let permission = match self {
|
||||
Self::Allow => "allow",
|
||||
Self::Deny => "deny",
|
||||
};
|
||||
f.write_str(permission)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct NetworkUnixSocketPermissionsToml {
|
||||
#[serde(flatten)]
|
||||
pub entries: BTreeMap<String, NetworkUnixSocketPermissionToml>,
|
||||
}
|
||||
|
||||
impl NetworkUnixSocketPermissionsToml {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entries.is_empty()
|
||||
}
|
||||
|
||||
pub fn allow_unix_sockets(&self) -> Vec<String> {
|
||||
self.entries
|
||||
.iter()
|
||||
.filter(|(_, permission)| matches!(permission, NetworkUnixSocketPermissionToml::Allow))
|
||||
.map(|(path, _)| path.clone())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum NetworkUnixSocketPermissionToml {
|
||||
Allow,
|
||||
None,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NetworkUnixSocketPermissionToml {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let permission = match self {
|
||||
Self::Allow => "allow",
|
||||
Self::None => "none",
|
||||
};
|
||||
f.write_str(permission)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct NetworkRequirementsToml {
|
||||
pub enabled: Option<bool>,
|
||||
pub http_port: Option<u16>,
|
||||
@@ -140,17 +227,121 @@ pub struct NetworkRequirementsToml {
|
||||
pub allow_upstream_proxy: Option<bool>,
|
||||
pub dangerously_allow_non_loopback_proxy: Option<bool>,
|
||||
pub dangerously_allow_all_unix_sockets: Option<bool>,
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
pub domains: Option<NetworkDomainPermissionsToml>,
|
||||
/// When true, only managed `allowed_domains` are respected while managed
|
||||
/// network enforcement is active. User allowlist entries are ignored.
|
||||
pub managed_allowed_domains_only: Option<bool>,
|
||||
pub denied_domains: Option<Vec<String>>,
|
||||
pub allow_unix_sockets: Option<Vec<String>>,
|
||||
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
|
||||
pub allow_local_binding: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RawNetworkRequirementsToml {
|
||||
enabled: Option<bool>,
|
||||
http_port: Option<u16>,
|
||||
socks_port: Option<u16>,
|
||||
allow_upstream_proxy: Option<bool>,
|
||||
dangerously_allow_non_loopback_proxy: Option<bool>,
|
||||
dangerously_allow_all_unix_sockets: Option<bool>,
|
||||
domains: Option<NetworkDomainPermissionsToml>,
|
||||
#[serde(default)]
|
||||
allowed_domains: Option<Vec<String>>,
|
||||
/// When true, only managed `allowed_domains` are respected while managed
|
||||
/// network enforcement is active. User allowlist entries are ignored.
|
||||
managed_allowed_domains_only: Option<bool>,
|
||||
#[serde(default)]
|
||||
denied_domains: Option<Vec<String>>,
|
||||
unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
|
||||
#[serde(default)]
|
||||
allow_unix_sockets: Option<Vec<String>>,
|
||||
allow_local_binding: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NetworkRequirementsToml {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let raw = RawNetworkRequirementsToml::deserialize(deserializer)?;
|
||||
let RawNetworkRequirementsToml {
|
||||
enabled,
|
||||
http_port,
|
||||
socks_port,
|
||||
allow_upstream_proxy,
|
||||
dangerously_allow_non_loopback_proxy,
|
||||
dangerously_allow_all_unix_sockets,
|
||||
domains,
|
||||
allowed_domains,
|
||||
managed_allowed_domains_only,
|
||||
denied_domains,
|
||||
unix_sockets,
|
||||
allow_unix_sockets,
|
||||
allow_local_binding,
|
||||
} = raw;
|
||||
|
||||
if domains.is_some() && (allowed_domains.is_some() || denied_domains.is_some()) {
|
||||
return Err(D::Error::custom(
|
||||
"`experimental_network.domains` cannot be combined with legacy `allowed_domains` or `denied_domains`",
|
||||
));
|
||||
}
|
||||
|
||||
if unix_sockets.is_some() && allow_unix_sockets.is_some() {
|
||||
return Err(D::Error::custom(
|
||||
"`experimental_network.unix_sockets` cannot be combined with legacy `allow_unix_sockets`",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
enabled,
|
||||
http_port,
|
||||
socks_port,
|
||||
allow_upstream_proxy,
|
||||
dangerously_allow_non_loopback_proxy,
|
||||
dangerously_allow_all_unix_sockets,
|
||||
domains: domains
|
||||
.or_else(|| legacy_domain_permissions_from_lists(allowed_domains, denied_domains)),
|
||||
managed_allowed_domains_only,
|
||||
unix_sockets: unix_sockets
|
||||
.or_else(|| legacy_unix_socket_permissions_from_list(allow_unix_sockets)),
|
||||
allow_local_binding,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Legacy list normalization is intentionally lossy: explicit empty legacy
|
||||
/// lists are treated as unset when converted to the canonical network
|
||||
/// permission shape.
|
||||
fn legacy_domain_permissions_from_lists(
|
||||
allowed_domains: Option<Vec<String>>,
|
||||
denied_domains: Option<Vec<String>>,
|
||||
) -> Option<NetworkDomainPermissionsToml> {
|
||||
let mut entries = BTreeMap::new();
|
||||
|
||||
for pattern in allowed_domains.unwrap_or_default() {
|
||||
entries.insert(pattern, NetworkDomainPermissionToml::Allow);
|
||||
}
|
||||
|
||||
for pattern in denied_domains.unwrap_or_default() {
|
||||
entries.insert(pattern, NetworkDomainPermissionToml::Deny);
|
||||
}
|
||||
|
||||
(!entries.is_empty()).then_some(NetworkDomainPermissionsToml { entries })
|
||||
}
|
||||
|
||||
fn legacy_unix_socket_permissions_from_list(
|
||||
allow_unix_sockets: Option<Vec<String>>,
|
||||
) -> Option<NetworkUnixSocketPermissionsToml> {
|
||||
let entries = allow_unix_sockets
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|path| (path, NetworkUnixSocketPermissionToml::Allow))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
(!entries.is_empty()).then_some(NetworkUnixSocketPermissionsToml { entries })
|
||||
}
|
||||
|
||||
/// Normalized network constraints derived from requirements TOML.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
|
||||
pub struct NetworkConstraints {
|
||||
pub enabled: Option<bool>,
|
||||
pub http_port: Option<u16>,
|
||||
@@ -158,15 +349,24 @@ pub struct NetworkConstraints {
|
||||
pub allow_upstream_proxy: Option<bool>,
|
||||
pub dangerously_allow_non_loopback_proxy: Option<bool>,
|
||||
pub dangerously_allow_all_unix_sockets: Option<bool>,
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
pub domains: Option<NetworkDomainPermissionsToml>,
|
||||
/// When true, only managed `allowed_domains` are respected while managed
|
||||
/// network enforcement is active. User allowlist entries are ignored.
|
||||
pub managed_allowed_domains_only: Option<bool>,
|
||||
pub denied_domains: Option<Vec<String>>,
|
||||
pub allow_unix_sockets: Option<Vec<String>>,
|
||||
pub unix_sockets: Option<NetworkUnixSocketPermissionsToml>,
|
||||
pub allow_local_binding: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NetworkConstraints {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let requirements = NetworkRequirementsToml::deserialize(deserializer)?;
|
||||
Ok(requirements.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NetworkRequirementsToml> for NetworkConstraints {
|
||||
fn from(value: NetworkRequirementsToml) -> Self {
|
||||
let NetworkRequirementsToml {
|
||||
@@ -176,10 +376,9 @@ impl From<NetworkRequirementsToml> for NetworkConstraints {
|
||||
allow_upstream_proxy,
|
||||
dangerously_allow_non_loopback_proxy,
|
||||
dangerously_allow_all_unix_sockets,
|
||||
allowed_domains,
|
||||
domains,
|
||||
managed_allowed_domains_only,
|
||||
denied_domains,
|
||||
allow_unix_sockets,
|
||||
unix_sockets,
|
||||
allow_local_binding,
|
||||
} = value;
|
||||
Self {
|
||||
@@ -189,10 +388,9 @@ impl From<NetworkRequirementsToml> for NetworkConstraints {
|
||||
allow_upstream_proxy,
|
||||
dangerously_allow_non_loopback_proxy,
|
||||
dangerously_allow_all_unix_sockets,
|
||||
allowed_domains,
|
||||
domains,
|
||||
managed_allowed_domains_only,
|
||||
denied_domains,
|
||||
allow_unix_sockets,
|
||||
unix_sockets,
|
||||
allow_local_binding,
|
||||
}
|
||||
}
|
||||
@@ -1470,6 +1668,78 @@ guardian_developer_instructions = """
|
||||
|
||||
#[test]
|
||||
fn network_requirements_are_preserved_as_constraints_with_source() -> Result<()> {
|
||||
let toml_str = r#"
|
||||
[experimental_network]
|
||||
enabled = true
|
||||
allow_upstream_proxy = false
|
||||
dangerously_allow_all_unix_sockets = true
|
||||
managed_allowed_domains_only = true
|
||||
allow_local_binding = false
|
||||
|
||||
[experimental_network.domains]
|
||||
"api.example.com" = "allow"
|
||||
"*.openai.com" = "allow"
|
||||
"blocked.example.com" = "deny"
|
||||
|
||||
[experimental_network.unix_sockets]
|
||||
"/tmp/example.sock" = "allow"
|
||||
"#;
|
||||
|
||||
let source = RequirementSource::CloudRequirements;
|
||||
let mut requirements_with_sources = ConfigRequirementsWithSources::default();
|
||||
requirements_with_sources.merge_unset_fields(source.clone(), from_str(toml_str)?);
|
||||
|
||||
let requirements = ConfigRequirements::try_from(requirements_with_sources)?;
|
||||
let sourced_network = requirements
|
||||
.network
|
||||
.expect("network requirements should be preserved as constraints");
|
||||
|
||||
assert_eq!(sourced_network.source, source);
|
||||
assert_eq!(sourced_network.value.enabled, Some(true));
|
||||
assert_eq!(sourced_network.value.allow_upstream_proxy, Some(false));
|
||||
assert_eq!(
|
||||
sourced_network.value.dangerously_allow_all_unix_sockets,
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.domains.as_ref(),
|
||||
Some(&NetworkDomainPermissionsToml {
|
||||
entries: BTreeMap::from([
|
||||
(
|
||||
"*.openai.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"api.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"blocked.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Deny,
|
||||
),
|
||||
]),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.managed_allowed_domains_only,
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.unix_sockets.as_ref(),
|
||||
Some(&NetworkUnixSocketPermissionsToml {
|
||||
entries: BTreeMap::from([(
|
||||
"/tmp/example.sock".to_string(),
|
||||
NetworkUnixSocketPermissionToml::Allow,
|
||||
)]),
|
||||
})
|
||||
);
|
||||
assert_eq!(sourced_network.value.allow_local_binding, Some(false));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_network_requirements_are_preserved_as_constraints_with_source() -> Result<()> {
|
||||
let toml_str = r#"
|
||||
[experimental_network]
|
||||
enabled = true
|
||||
@@ -1499,29 +1769,137 @@ guardian_developer_instructions = """
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.allowed_domains.as_ref(),
|
||||
Some(&vec![
|
||||
"api.example.com".to_string(),
|
||||
"*.openai.com".to_string()
|
||||
])
|
||||
sourced_network.value.domains.as_ref(),
|
||||
Some(&NetworkDomainPermissionsToml {
|
||||
entries: BTreeMap::from([
|
||||
(
|
||||
"*.openai.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"api.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"blocked.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Deny,
|
||||
),
|
||||
]),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.managed_allowed_domains_only,
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.denied_domains.as_ref(),
|
||||
Some(&vec!["blocked.example.com".to_string()])
|
||||
);
|
||||
assert_eq!(
|
||||
sourced_network.value.allow_unix_sockets.as_ref(),
|
||||
Some(&vec!["/tmp/example.sock".to_string()])
|
||||
sourced_network.value.unix_sockets.as_ref(),
|
||||
Some(&NetworkUnixSocketPermissionsToml {
|
||||
entries: BTreeMap::from([(
|
||||
"/tmp/example.sock".to_string(),
|
||||
NetworkUnixSocketPermissionToml::Allow,
|
||||
)]),
|
||||
})
|
||||
);
|
||||
assert_eq!(sourced_network.value.allow_local_binding, Some(false));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_legacy_and_canonical_network_requirements_are_rejected() {
|
||||
let err = from_str::<ConfigRequirementsToml>(
|
||||
r#"
|
||||
[experimental_network]
|
||||
allowed_domains = ["api.example.com"]
|
||||
|
||||
[experimental_network.domains]
|
||||
"*.openai.com" = "allow"
|
||||
"#,
|
||||
)
|
||||
.expect_err("mixed network domain shapes should fail");
|
||||
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("`experimental_network.domains` cannot be combined"),
|
||||
"unexpected error: {err:#}"
|
||||
);
|
||||
|
||||
let err = from_str::<ConfigRequirementsToml>(
|
||||
r#"
|
||||
[experimental_network]
|
||||
allow_unix_sockets = ["/tmp/example.sock"]
|
||||
|
||||
[experimental_network.unix_sockets]
|
||||
"/tmp/another.sock" = "allow"
|
||||
"#,
|
||||
)
|
||||
.expect_err("mixed network unix socket shapes should fail");
|
||||
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("`experimental_network.unix_sockets` cannot be combined"),
|
||||
"unexpected error: {err:#}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn network_permission_containers_project_allowed_and_denied_entries() {
|
||||
let domains = NetworkDomainPermissionsToml {
|
||||
entries: BTreeMap::from([
|
||||
(
|
||||
"*.openai.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"api.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"blocked.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Deny,
|
||||
),
|
||||
]),
|
||||
};
|
||||
let unix_sockets = NetworkUnixSocketPermissionsToml {
|
||||
entries: BTreeMap::from([
|
||||
(
|
||||
"/tmp/example.sock".to_string(),
|
||||
NetworkUnixSocketPermissionToml::Allow,
|
||||
),
|
||||
(
|
||||
"/tmp/ignored.sock".to_string(),
|
||||
NetworkUnixSocketPermissionToml::None,
|
||||
),
|
||||
]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
domains.allowed_domains(),
|
||||
Some(vec![
|
||||
"*.openai.com".to_string(),
|
||||
"api.example.com".to_string()
|
||||
])
|
||||
);
|
||||
assert_eq!(
|
||||
domains.denied_domains(),
|
||||
Some(vec!["blocked.example.com".to_string()])
|
||||
);
|
||||
assert_eq!(
|
||||
NetworkDomainPermissionsToml {
|
||||
entries: BTreeMap::from([(
|
||||
"api.example.com".to_string(),
|
||||
NetworkDomainPermissionToml::Allow,
|
||||
)]),
|
||||
}
|
||||
.denied_domains(),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
unix_sockets.allow_unix_sockets(),
|
||||
vec!["/tmp/example.sock".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_mcp_server_requirements() -> Result<()> {
|
||||
let toml_str = r#"
|
||||
|
||||
@@ -25,7 +25,11 @@ pub use config_requirements::FeatureRequirementsToml;
|
||||
pub use config_requirements::McpServerIdentity;
|
||||
pub use config_requirements::McpServerRequirement;
|
||||
pub use config_requirements::NetworkConstraints;
|
||||
pub use config_requirements::NetworkDomainPermissionToml;
|
||||
pub use config_requirements::NetworkDomainPermissionsToml;
|
||||
pub use config_requirements::NetworkRequirementsToml;
|
||||
pub use config_requirements::NetworkUnixSocketPermissionToml;
|
||||
pub use config_requirements::NetworkUnixSocketPermissionsToml;
|
||||
pub use config_requirements::RequirementSource;
|
||||
pub use config_requirements::ResidencyRequirement;
|
||||
pub use config_requirements::SandboxModeRequirement;
|
||||
|
||||
Reference in New Issue
Block a user