Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12348,6 +12348,84 @@
],
"type": "string"
},
"NetworkRequirements": {
"properties": {
"allowLocalBinding": {
"type": [
"boolean",
"null"
]
},
"allowUnixSockets": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"allowUpstreamProxy": {
"type": [
"boolean",
"null"
]
},
"allowedDomains": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"dangerouslyAllowNonLoopbackAdmin": {
"type": [
"boolean",
"null"
]
},
"dangerouslyAllowNonLoopbackProxy": {
"type": [
"boolean",
"null"
]
},
"deniedDomains": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"enabled": {
"type": [
"boolean",
"null"
]
},
"httpPort": {
"format": "uint16",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"socksPort": {
"format": "uint16",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"OverriddenMetadata": {
"properties": {
"effectiveValue": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,84 @@
},
"type": "object"
},
"NetworkRequirements": {
"properties": {
"allowLocalBinding": {
"type": [
"boolean",
"null"
]
},
"allowUnixSockets": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"allowUpstreamProxy": {
"type": [
"boolean",
"null"
]
},
"allowedDomains": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"dangerouslyAllowNonLoopbackAdmin": {
"type": [
"boolean",
"null"
]
},
"dangerouslyAllowNonLoopbackProxy": {
"type": [
"boolean",
"null"
]
},
"deniedDomains": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"enabled": {
"type": [
"boolean",
"null"
]
},
"httpPort": {
"format": "uint16",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"socksPort": {
"format": "uint16",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"type": "object"
},
"ResidencyRequirement": {
"enum": [
"us"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ import type { AskForApproval } from "./AskForApproval";
import type { ResidencyRequirement } from "./ResidencyRequirement";
import type { SandboxMode } from "./SandboxMode";

export type ConfigRequirements = { allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, enforceResidency: ResidencyRequirement | null, };
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, enforceResidency: ResidencyRequirement | null};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!

// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

export type NetworkRequirements = { enabled: boolean | null, httpPort: number | null, socksPort: number | null, allowUpstreamProxy: boolean | null, dangerouslyAllowNonLoopbackProxy: boolean | null, dangerouslyAllowNonLoopbackAdmin: boolean | null, allowedDomains: Array<string> | null, deniedDomains: Array<string> | null, allowUnixSockets: Array<string> | null, allowLocalBinding: boolean | null, };
1 change: 1 addition & 0 deletions codex-rs/app-server-protocol/schema/typescript/v2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export type { Model } from "./Model";
export type { ModelListParams } from "./ModelListParams";
export type { ModelListResponse } from "./ModelListResponse";
export type { NetworkAccess } from "./NetworkAccess";
export type { NetworkRequirements } from "./NetworkRequirements";
export type { OverriddenMetadata } from "./OverriddenMetadata";
export type { PatchApplyStatus } from "./PatchApplyStatus";
export type { PatchChangeKind } from "./PatchChangeKind";
Expand Down
20 changes: 19 additions & 1 deletion codex-rs/app-server-protocol/src/protocol/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,14 +527,32 @@ pub struct ConfigReadResponse {
pub layers: Option<Vec<ConfigLayer>>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ConfigRequirements {
pub allowed_approval_policies: Option<Vec<AskForApproval>>,
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
pub enforce_residency: Option<ResidencyRequirement>,
#[experimental("configRequirements/read.network")]
pub network: Option<NetworkRequirements>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct NetworkRequirements {
pub enabled: Option<bool>,
pub http_port: Option<u16>,
pub socks_port: Option<u16>,
pub allow_upstream_proxy: Option<bool>,
pub dangerously_allow_non_loopback_proxy: Option<bool>,
pub dangerously_allow_non_loopback_admin: Option<bool>,
pub allowed_domains: Option<Vec<String>>,
pub denied_domains: Option<Vec<String>>,
pub allow_unix_sockets: Option<Vec<String>>,
pub allow_local_binding: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Example (from OpenAI's official VSCode extension):
- `config/read` — fetch the effective config on disk after resolving config layering.
- `config/value/write` — write a single config key/value to the user's config.toml on disk.
- `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk.
- `configRequirements/read` — fetch the loaded requirements allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`) and `enforceResidency` from `requirements.toml` and/or MDM (or `null` if none are configured).
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), `enforceResidency`, and `network` constraints.

### Example: Start or resume a thread

Expand Down
48 changes: 48 additions & 0 deletions codex-rs/app-server/src/config_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use codex_app_server_protocol::ConfigValueWriteParams;
use codex_app_server_protocol::ConfigWriteErrorCode;
use codex_app_server_protocol::ConfigWriteResponse;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_app_server_protocol::NetworkRequirements;
use codex_app_server_protocol::SandboxMode;
use codex_core::config::ConfigService;
use codex_core::config::ConfigServiceError;
Expand Down Expand Up @@ -129,6 +130,7 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR
enforce_residency: requirements
.enforce_residency
.map(map_residency_requirement_to_api),
network: requirements.network.map(map_network_requirements_to_api),
}
}

Expand All @@ -149,6 +151,23 @@ fn map_residency_requirement_to_api(
}
}

fn map_network_requirements_to_api(
network: codex_core::config_loader::NetworkRequirementsToml,
) -> NetworkRequirements {
NetworkRequirements {
enabled: network.enabled,
http_port: network.http_port,
socks_port: network.socks_port,
allow_upstream_proxy: network.allow_upstream_proxy,
dangerously_allow_non_loopback_proxy: network.dangerously_allow_non_loopback_proxy,
dangerously_allow_non_loopback_admin: network.dangerously_allow_non_loopback_admin,
allowed_domains: network.allowed_domains,
denied_domains: network.denied_domains,
allow_unix_sockets: network.allow_unix_sockets,
allow_local_binding: network.allow_local_binding,
}
}

fn map_error(err: ConfigServiceError) -> JSONRPCErrorError {
if let Some(code) = err.write_error_code() {
return config_write_error(code, err.to_string());
Expand All @@ -174,6 +193,7 @@ fn config_write_error(code: ConfigWriteErrorCode, message: impl Into<String>) ->
#[cfg(test)]
mod tests {
use super::*;
use codex_core::config_loader::NetworkRequirementsToml as CoreNetworkRequirementsToml;
use codex_protocol::protocol::AskForApproval as CoreAskForApproval;
use pretty_assertions::assert_eq;

Expand All @@ -194,6 +214,18 @@ mod tests {
mcp_servers: None,
rules: None,
enforce_residency: Some(CoreResidencyRequirement::Us),
network: Some(CoreNetworkRequirementsToml {
enabled: Some(true),
http_port: Some(8080),
socks_port: Some(1080),
allow_upstream_proxy: Some(false),
dangerously_allow_non_loopback_proxy: Some(false),
dangerously_allow_non_loopback_admin: Some(false),
allowed_domains: Some(vec!["api.openai.com".to_string()]),
denied_domains: Some(vec!["example.com".to_string()]),
allow_unix_sockets: Some(vec!["/tmp/proxy.sock".to_string()]),
allow_local_binding: Some(true),
}),
};

let mapped = map_requirements_toml_to_api(requirements);
Expand All @@ -217,6 +249,21 @@ mod tests {
mapped.enforce_residency,
Some(codex_app_server_protocol::ResidencyRequirement::Us),
);
assert_eq!(
mapped.network,
Some(NetworkRequirements {
enabled: Some(true),
http_port: Some(8080),
socks_port: Some(1080),
allow_upstream_proxy: Some(false),
dangerously_allow_non_loopback_proxy: Some(false),
dangerously_allow_non_loopback_admin: Some(false),
allowed_domains: Some(vec!["api.openai.com".to_string()]),
denied_domains: Some(vec!["example.com".to_string()]),
allow_unix_sockets: Some(vec!["/tmp/proxy.sock".to_string()]),
allow_local_binding: Some(true),
}),
);
}

#[test]
Expand All @@ -228,6 +275,7 @@ mod tests {
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
};

let mapped = map_requirements_toml_to_api(requirements);
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/cloud-requirements/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ mod tests {
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
})
);
}
Expand Down Expand Up @@ -426,6 +427,7 @@ mod tests {
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
})
);
}
Expand Down Expand Up @@ -470,6 +472,7 @@ mod tests {
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
})
);
assert_eq!(fetcher.request_count.load(Ordering::SeqCst), 2);
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,7 @@ impl Config {
mcp_servers,
exec_policy: _,
enforce_residency,
network: _network_requirements,
} = requirements;

apply_requirement_constrained_value(
Expand Down Expand Up @@ -4379,6 +4380,7 @@ model_verbosity = "high"
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
};
let requirement_source = crate::config_loader::RequirementSource::Unknown;
let requirement_source_for_error = requirement_source.clone();
Expand Down Expand Up @@ -4936,6 +4938,7 @@ mcp_oauth_callback_port = 5678
mcp_servers: None,
rules: None,
enforce_residency: None,
network: None,
};

let config = ConfigBuilder::default()
Expand Down
Loading
Loading