mirror of
https://github.com/openai/codex.git
synced 2026-04-25 07:05:38 +00:00
## 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"] ```
265 lines
5.9 KiB
JSON
265 lines
5.9 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"definitions": {
|
|
"AskForApproval": {
|
|
"oneOf": [
|
|
{
|
|
"enum": [
|
|
"untrusted",
|
|
"on-failure",
|
|
"on-request",
|
|
"never"
|
|
],
|
|
"type": "string"
|
|
},
|
|
{
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"granular": {
|
|
"properties": {
|
|
"mcp_elicitations": {
|
|
"type": "boolean"
|
|
},
|
|
"request_permissions": {
|
|
"default": false,
|
|
"type": "boolean"
|
|
},
|
|
"rules": {
|
|
"type": "boolean"
|
|
},
|
|
"sandbox_approval": {
|
|
"type": "boolean"
|
|
},
|
|
"skill_approval": {
|
|
"default": false,
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"mcp_elicitations",
|
|
"rules",
|
|
"sandbox_approval"
|
|
],
|
|
"type": "object"
|
|
}
|
|
},
|
|
"required": [
|
|
"granular"
|
|
],
|
|
"title": "GranularAskForApproval",
|
|
"type": "object"
|
|
}
|
|
]
|
|
},
|
|
"ConfigRequirements": {
|
|
"properties": {
|
|
"allowedApprovalPolicies": {
|
|
"items": {
|
|
"$ref": "#/definitions/AskForApproval"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"allowedSandboxModes": {
|
|
"items": {
|
|
"$ref": "#/definitions/SandboxMode"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"allowedWebSearchModes": {
|
|
"items": {
|
|
"$ref": "#/definitions/WebSearchMode"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"enforceResidency": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/ResidencyRequirement"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"featureRequirements": {
|
|
"additionalProperties": {
|
|
"type": "boolean"
|
|
},
|
|
"type": [
|
|
"object",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"NetworkDomainPermission": {
|
|
"enum": [
|
|
"allow",
|
|
"deny"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"NetworkRequirements": {
|
|
"properties": {
|
|
"allowLocalBinding": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"allowUnixSockets": {
|
|
"description": "Legacy compatibility view derived from `unix_sockets`.",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"allowUpstreamProxy": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"allowedDomains": {
|
|
"description": "Legacy compatibility view derived from `domains`.",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"dangerouslyAllowAllUnixSockets": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"dangerouslyAllowNonLoopbackProxy": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"deniedDomains": {
|
|
"description": "Legacy compatibility view derived from `domains`.",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"domains": {
|
|
"additionalProperties": {
|
|
"$ref": "#/definitions/NetworkDomainPermission"
|
|
},
|
|
"description": "Canonical network permission map for `experimental_network`.",
|
|
"type": [
|
|
"object",
|
|
"null"
|
|
]
|
|
},
|
|
"enabled": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"httpPort": {
|
|
"format": "uint16",
|
|
"minimum": 0.0,
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
]
|
|
},
|
|
"managedAllowedDomainsOnly": {
|
|
"description": "When true, only managed allowlist entries are respected while managed network enforcement is active.",
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"socksPort": {
|
|
"format": "uint16",
|
|
"minimum": 0.0,
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
]
|
|
},
|
|
"unixSockets": {
|
|
"additionalProperties": {
|
|
"$ref": "#/definitions/NetworkUnixSocketPermission"
|
|
},
|
|
"description": "Canonical unix socket permission map for `experimental_network`.",
|
|
"type": [
|
|
"object",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"NetworkUnixSocketPermission": {
|
|
"enum": [
|
|
"allow",
|
|
"none"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"ResidencyRequirement": {
|
|
"enum": [
|
|
"us"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"SandboxMode": {
|
|
"enum": [
|
|
"read-only",
|
|
"workspace-write",
|
|
"danger-full-access"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"WebSearchMode": {
|
|
"enum": [
|
|
"disabled",
|
|
"cached",
|
|
"live"
|
|
],
|
|
"type": "string"
|
|
}
|
|
},
|
|
"properties": {
|
|
"requirements": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/ConfigRequirements"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"description": "Null if no requirements are configured (e.g. no requirements.toml/MDM entries)."
|
|
}
|
|
},
|
|
"title": "ConfigRequirementsReadResponse",
|
|
"type": "object"
|
|
} |