diff --git a/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json b/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json index 5a19a3928..891946fd9 100644 --- a/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json +++ b/codex-rs/app-server-protocol/schema/json/CommandExecutionRequestApprovalParams.json @@ -65,6 +65,17 @@ }, "type": "object" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AdditionalPermissionProfile": { "properties": { "fileSystem": { @@ -88,9 +99,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } ] } }, diff --git a/codex-rs/app-server-protocol/schema/json/EventMsg.json b/codex-rs/app-server-protocol/schema/json/EventMsg.json index a22962cd4..cafd8bc5d 100644 --- a/codex-rs/app-server-protocol/schema/json/EventMsg.json +++ b/codex-rs/app-server-protocol/schema/json/EventMsg.json @@ -3888,6 +3888,17 @@ ], "type": "string" }, + "NetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "NetworkPolicyAmendment": { "properties": { "action": { @@ -4052,9 +4063,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/NetworkPermissions" + }, + { + "type": "null" + } ] } }, diff --git a/codex-rs/app-server-protocol/schema/json/ServerRequest.json b/codex-rs/app-server-protocol/schema/json/ServerRequest.json index 913844054..fce6ec619 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ServerRequest.json @@ -65,6 +65,17 @@ }, "type": "object" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AdditionalPermissionProfile": { "properties": { "fileSystem": { @@ -88,9 +99,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } ] } }, diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 374bdc197..94e9f3a50 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -61,6 +61,17 @@ }, "type": "object" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AdditionalPermissionProfile": { "properties": { "fileSystem": { @@ -84,9 +95,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } ] } }, @@ -5272,6 +5287,17 @@ ], "type": "string" }, + "NetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "NetworkPolicyAmendment": { "properties": { "action": { @@ -5428,9 +5454,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/NetworkPermissions" + }, + { + "type": "null" + } ] } }, diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 2ca096cff..0d1de7448 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -7824,6 +7824,17 @@ ], "type": "string" }, + "NetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "NetworkPolicyAmendment": { "properties": { "action": { @@ -8148,9 +8159,13 @@ ] }, "network": { - "type": [ - "boolean", - "null" + "anyOf": [ + { + "$ref": "#/definitions/NetworkPermissions" + }, + { + "type": "null" + } ] } }, diff --git a/codex-rs/app-server-protocol/schema/typescript/NetworkPermissions.ts b/codex-rs/app-server-protocol/schema/typescript/NetworkPermissions.ts new file mode 100644 index 000000000..7fb197b0e --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/NetworkPermissions.ts @@ -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 NetworkPermissions = { enabled: boolean | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/PermissionProfile.ts b/codex-rs/app-server-protocol/schema/typescript/PermissionProfile.ts index bfc0de27b..c9a60f067 100644 --- a/codex-rs/app-server-protocol/schema/typescript/PermissionProfile.ts +++ b/codex-rs/app-server-protocol/schema/typescript/PermissionProfile.ts @@ -3,5 +3,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { FileSystemPermissions } from "./FileSystemPermissions"; import type { MacOsPermissions } from "./MacOsPermissions"; +import type { NetworkPermissions } from "./NetworkPermissions"; -export type PermissionProfile = { network: boolean | null, file_system: FileSystemPermissions | null, macos: MacOsPermissions | null, }; +export type PermissionProfile = { network: NetworkPermissions | null, file_system: FileSystemPermissions | null, macos: MacOsPermissions | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/index.ts b/codex-rs/app-server-protocol/schema/typescript/index.ts index 228998cdd..faad506df 100644 --- a/codex-rs/app-server-protocol/schema/typescript/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/index.ts @@ -115,6 +115,7 @@ export type { ModelRerouteReason } from "./ModelRerouteReason"; export type { NetworkAccess } from "./NetworkAccess"; export type { NetworkApprovalContext } from "./NetworkApprovalContext"; export type { NetworkApprovalProtocol } from "./NetworkApprovalProtocol"; +export type { NetworkPermissions } from "./NetworkPermissions"; export type { NetworkPolicyAmendment } from "./NetworkPolicyAmendment"; export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction"; export type { ParsedCommand } from "./ParsedCommand"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalNetworkPermissions.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalNetworkPermissions.ts new file mode 100644 index 000000000..823de26ca --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalNetworkPermissions.ts @@ -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 AdditionalNetworkPermissions = { enabled: boolean | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalPermissionProfile.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalPermissionProfile.ts index 4ca4dca12..701ba5431 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalPermissionProfile.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AdditionalPermissionProfile.ts @@ -3,5 +3,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AdditionalFileSystemPermissions } from "./AdditionalFileSystemPermissions"; import type { AdditionalMacOsPermissions } from "./AdditionalMacOsPermissions"; +import type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermissions"; -export type AdditionalPermissionProfile = { network: boolean | null, fileSystem: AdditionalFileSystemPermissions | null, macos: AdditionalMacOsPermissions | null, }; +export type AdditionalPermissionProfile = { network: AdditionalNetworkPermissions | null, fileSystem: AdditionalFileSystemPermissions | null, macos: AdditionalMacOsPermissions | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index 02bf51727..0c9b2dc58 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -6,6 +6,7 @@ export type { AccountRateLimitsUpdatedNotification } from "./AccountRateLimitsUp export type { AccountUpdatedNotification } from "./AccountUpdatedNotification"; export type { AdditionalFileSystemPermissions } from "./AdditionalFileSystemPermissions"; export type { AdditionalMacOsPermissions } from "./AdditionalMacOsPermissions"; +export type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermissions"; export type { AdditionalPermissionProfile } from "./AdditionalPermissionProfile"; export type { AgentMessageDeltaNotification } from "./AgentMessageDeltaNotification"; export type { AnalyticsConfig } from "./AnalyticsConfig"; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 7c69d9fa1..2147295c9 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -31,6 +31,7 @@ use codex_protocol::models::MacOsAutomationValue as CoreMacOsAutomationValue; use codex_protocol::models::MacOsPermissions as CoreMacOsPermissions; use codex_protocol::models::MacOsPreferencesValue as CoreMacOsPreferencesValue; use codex_protocol::models::MessagePhase; +use codex_protocol::models::NetworkPermissions as CoreNetworkPermissions; use codex_protocol::models::PermissionProfile as CorePermissionProfile; use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::InputModality; @@ -852,11 +853,26 @@ impl From for AdditionalMacOsPermissions { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct AdditionalNetworkPermissions { + pub enabled: Option, +} + +impl From for AdditionalNetworkPermissions { + fn from(value: CoreNetworkPermissions) -> Self { + Self { + enabled: value.enabled, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AdditionalPermissionProfile { - pub network: Option, + pub network: Option, pub file_system: Option, pub macos: Option, } @@ -864,7 +880,7 @@ pub struct AdditionalPermissionProfile { impl From for AdditionalPermissionProfile { fn from(value: CorePermissionProfile) -> Self { Self { - network: value.network, + network: value.network.map(AdditionalNetworkPermissions::from), file_system: value.file_system.map(AdditionalFileSystemPermissions::from), macos: value.macos.map(AdditionalMacOsPermissions::from), } diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index b105d411b..658b2e08d 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -742,7 +742,7 @@ Certain actions (shell commands or modifying files) may require explicit user ap Order of messages: 1. `item/started` — shows the pending `commandExecution` item with `command`, `cwd`, and other fields so you can render the proposed action. -2. `item/commandExecution/requestApproval` (request) — carries the same `itemId`, `threadId`, `turnId`, optionally `approvalId` (for subcommand callbacks), and `reason`. For normal command approvals, it also includes `command`, `cwd`, and `commandActions` for friendly display. When `initialize.params.capabilities.experimentalApi = true`, it may also include experimental `additionalPermissions` describing requested per-command sandbox access; any filesystem paths in that payload are absolute on the wire. For network-only approvals, those command fields may be omitted and `networkApprovalContext` is provided instead. Optional persistence hints may also be included via `proposedExecpolicyAmendment` and `proposedNetworkPolicyAmendments`. Clients can prefer `availableDecisions` when present to render the exact set of choices the server wants to expose, while still falling back to the older heuristics if it is omitted. +2. `item/commandExecution/requestApproval` (request) — carries the same `itemId`, `threadId`, `turnId`, optionally `approvalId` (for subcommand callbacks), and `reason`. For normal command approvals, it also includes `command`, `cwd`, and `commandActions` for friendly display. When `initialize.params.capabilities.experimentalApi = true`, it may also include experimental `additionalPermissions` describing requested per-command sandbox access; any filesystem paths in that payload are absolute on the wire, and network access is represented as `additionalPermissions.network.enabled`. For network-only approvals, those command fields may be omitted and `networkApprovalContext` is provided instead. Optional persistence hints may also be included via `proposedExecpolicyAmendment` and `proposedNetworkPolicyAmendments`. Clients can prefer `availableDecisions` when present to render the exact set of choices the server wants to expose, while still falling back to the older heuristics if it is omitted. 3. Client response — for example `{ "decision": "accept" }`, `{ "decision": "acceptForSession" }`, `{ "decision": { "acceptWithExecpolicyAmendment": { "execpolicy_amendment": [...] } } }`, `{ "decision": { "applyNetworkPolicyAmendment": { "network_policy_amendment": { "host": "example.com", "action": "allow" } } } }`, `{ "decision": "decline" }`, or `{ "decision": "cancel" }`. 4. `serverRequest/resolved` — `{ threadId, requestId }` confirms the pending request has been resolved or cleared, including lifecycle cleanup on turn start/complete/interrupt. 5. `item/completed` — final `commandExecution` item with `status: "completed" | "failed" | "declined"` and execution output. Render this as the authoritative result. diff --git a/codex-rs/core/src/sandboxing/mod.rs b/codex-rs/core/src/sandboxing/mod.rs index fe7d077bb..10c5d71da 100644 --- a/codex-rs/core/src/sandboxing/mod.rs +++ b/codex-rs/core/src/sandboxing/mod.rs @@ -193,7 +193,12 @@ fn merge_network_access( base_network_access: bool, additional_permissions: &PermissionProfile, ) -> bool { - base_network_access || matches!(additional_permissions.network, Some(true)) + base_network_access + || additional_permissions + .network + .as_ref() + .and_then(|network| network.enabled) + .unwrap_or(false) } fn sandbox_policy_with_additional_permissions( @@ -431,6 +436,7 @@ mod tests { use crate::tools::sandboxing::SandboxablePreference; use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::models::FileSystemPermissions; + use codex_protocol::models::NetworkPermissions; use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; use dunce::canonicalize; @@ -470,7 +476,9 @@ mod tests { ) .expect("absolute temp dir"); let permissions = normalize_additional_permissions(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![path.clone()]), write: Some(vec![path.clone()]), @@ -479,7 +487,12 @@ mod tests { }) .expect("permissions"); - assert_eq!(permissions.network, Some(true)); + assert_eq!( + permissions.network, + Some(NetworkPermissions { + enabled: Some(true), + }) + ); assert_eq!( permissions.file_system, Some(FileSystemPermissions { @@ -505,7 +518,9 @@ mod tests { network_access: false, }, &PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![path.clone()]), write: Some(Vec::new()), diff --git a/codex-rs/core/src/skills/loader.rs b/codex-rs/core/src/skills/loader.rs index bfa22cf01..751fa0720 100644 --- a/codex-rs/core/src/skills/loader.rs +++ b/codex-rs/core/src/skills/loader.rs @@ -32,6 +32,8 @@ use tracing::error; #[cfg(test)] use crate::config::Config; +#[cfg(test)] +use codex_protocol::models::NetworkPermissions; #[derive(Debug, Deserialize)] struct SkillFrontmatter { @@ -1387,7 +1389,8 @@ policy: {} skill_dir, r#" permissions: - network: true + network: + enabled: true file_system: read: - "./data" @@ -1408,7 +1411,9 @@ permissions: assert_eq!( outcome.skills[0].permission_profile, Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![ AbsolutePathBuf::try_from(normalized(skill_dir.join("data").as_path())) diff --git a/codex-rs/core/src/skills/permissions.rs b/codex-rs/core/src/skills/permissions.rs index 825128307..53b1f7bd9 100644 --- a/codex-rs/core/src/skills/permissions.rs +++ b/codex-rs/core/src/skills/permissions.rs @@ -44,7 +44,7 @@ pub(crate) fn compile_permission_profile( file_system, macos, } = permissions?; - let network_access = network.unwrap_or_default(); + let network_access = network.and_then(|value| value.enabled).unwrap_or_default(); let file_system = file_system.unwrap_or_default(); let fs_read = normalize_permission_paths( file_system.read.as_deref().unwrap_or_default(), @@ -232,6 +232,7 @@ mod tests { use codex_protocol::models::MacOsPermissions; #[cfg(target_os = "macos")] use codex_protocol::models::MacOsPreferencesValue; + use codex_protocol::models::NetworkPermissions; use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; @@ -251,7 +252,9 @@ mod tests { fs::create_dir_all(&read_dir).expect("read dir"); let profile = compile_permission_profile(Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![ absolute_path(&skill_dir.join("data")), @@ -318,7 +321,9 @@ mod tests { fs::create_dir_all(&skill_dir).expect("skill dir"); let profile = compile_permission_profile(Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), ..Default::default() })) .expect("profile"); @@ -353,7 +358,9 @@ mod tests { fs::create_dir_all(&read_dir).expect("read dir"); let profile = compile_permission_profile(Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![absolute_path(&skill_dir.join("data"))]), write: Some(Vec::new()), diff --git a/codex-rs/protocol/src/models.rs b/codex-rs/protocol/src/models.rs index 8be7c9abf..d12eef3b3 100644 --- a/codex-rs/protocol/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -84,6 +84,17 @@ impl MacOsPermissions { } } +#[derive(Debug, Clone, Default, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, TS)] +pub struct NetworkPermissions { + pub enabled: Option, +} + +impl NetworkPermissions { + pub fn is_empty(&self) -> bool { + self.enabled.is_none() + } +} + #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, TS)] #[serde(untagged)] pub enum MacOsPreferencesValue { @@ -126,14 +137,17 @@ pub struct MacOsSeatbeltProfileExtensions { #[derive(Debug, Clone, Default, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, TS)] pub struct PermissionProfile { - pub network: Option, + pub network: Option, pub file_system: Option, pub macos: Option, } impl PermissionProfile { pub fn is_empty(&self) -> bool { - self.network.is_none() + self.network + .as_ref() + .map(NetworkPermissions::is_empty) + .unwrap_or(true) && self .file_system .as_ref() diff --git a/codex-rs/shell-escalation/src/unix/escalate_server.rs b/codex-rs/shell-escalation/src/unix/escalate_server.rs index bb45c3ed7..92d9adb9d 100644 --- a/codex-rs/shell-escalation/src/unix/escalate_server.rs +++ b/codex-rs/shell-escalation/src/unix/escalate_server.rs @@ -277,6 +277,7 @@ async fn handle_escalate_session_with_policy( mod tests { use super::*; use codex_protocol::approvals::EscalationPermissions; + use codex_protocol::models::NetworkPermissions; use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; @@ -513,14 +514,18 @@ mod tests { Arc::new(DeterministicEscalationPolicy { decision: EscalationDecision::escalate(EscalationExecution::Permissions( EscalationPermissions::PermissionProfile(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), ..Default::default() }), )), }), Arc::new(PermissionAssertingShellCommandExecutor { expected_permissions: EscalationPermissions::PermissionProfile(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), ..Default::default() }), }), diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs index 548be7576..21f0261cf 100644 --- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs +++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs @@ -641,7 +641,12 @@ fn format_additional_permissions_rule( additional_permissions: &PermissionProfile, ) -> Option { let mut parts = Vec::new(); - if matches!(additional_permissions.network, Some(true)) { + if additional_permissions + .network + .as_ref() + .and_then(|network| network.enabled) + .unwrap_or(false) + { parts.push("network".to_string()); } if let Some(file_system) = additional_permissions.file_system.as_ref() { @@ -721,6 +726,7 @@ mod tests { use super::*; use crate::app_event::AppEvent; use codex_protocol::models::FileSystemPermissions; + use codex_protocol::models::NetworkPermissions; use codex_protocol::protocol::ExecPolicyAmendment; use codex_protocol::protocol::NetworkApprovalProtocol; use codex_protocol::protocol::NetworkPolicyAmendment; @@ -1077,7 +1083,9 @@ mod tests { available_decisions: vec![ReviewDecision::Approved, ReviewDecision::Abort], network_approval_context: None, additional_permissions: Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![absolute_path("/tmp/readme.txt")]), write: Some(vec![absolute_path("/tmp/out.txt")]), @@ -1123,7 +1131,9 @@ mod tests { available_decisions: vec![ReviewDecision::Approved, ReviewDecision::Abort], network_approval_context: None, additional_permissions: Some(PermissionProfile { - network: Some(true), + network: Some(NetworkPermissions { + enabled: Some(true), + }), file_system: Some(FileSystemPermissions { read: Some(vec![absolute_path("/tmp/readme.txt")]), write: Some(vec![absolute_path("/tmp/out.txt")]),