diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index b976c9e4efb8..2621a0bd1eac 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -5,26 +5,6 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, - "ActivePermissionProfile": { - "properties": { - "extends": { - "default": null, - "description": "Parent profile identifier once permissions profiles support inheritance. This is currently always `null`.", - "type": [ - "string", - "null" - ] - }, - "id": { - "description": "Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.]` profile.", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, "AddCreditsNudgeCreditType": { "enum": [ "credits", diff --git a/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json b/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json index b6e939386bf9..d00a0b60e50a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json @@ -5,26 +5,6 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, - "ActivePermissionProfile": { - "properties": { - "extends": { - "default": null, - "description": "Parent profile identifier once permissions profiles support inheritance. This is currently always `null`.", - "type": [ - "string", - "null" - ] - }, - "id": { - "description": "Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.]` profile.", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, "CommandExecTerminalSize": { "description": "PTY size in character cells for `command/exec` PTY sessions.", "properties": { diff --git a/codex-rs/app-server-protocol/src/export.rs b/codex-rs/app-server-protocol/src/export.rs index d44b67825d5e..fcaa8a1eb5ab 100644 --- a/codex-rs/app-server-protocol/src/export.rs +++ b/codex-rs/app-server-protocol/src/export.rs @@ -2747,7 +2747,6 @@ export type Config = { stableField: Keep, unstableField: string | null } & ({ [k let _guard = TempDirGuard(output_dir.clone()); let path = output_dir.join("CommandExecParams.ts"); let content = r#"import type { CommandExecTerminalSize } from "./CommandExecTerminalSize"; -import type { ActivePermissionProfile } from "./ActivePermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; export type CommandExecParams = {/** @@ -2770,12 +2769,12 @@ size?: CommandExecTerminalSize | null, /** */ sandboxPolicy?: SandboxPolicy | null, /** - * Optional active permissions profile for this command. + * Optional active permissions profile id for this command. * * Defaults to the user's configured permissions when omitted. Cannot be * combined with `sandboxPolicy`. */ -permissionProfile?: ActivePermissionProfile | null}; +permissionProfile?: string | null}; "#; fs::write(&path, content)?; @@ -2788,16 +2787,7 @@ permissionProfile?: ActivePermissionProfile | null}; filter_experimental_type_fields_ts(&output_dir, &[&CUSTOM_FIELD])?; let filtered = fs::read_to_string(&path)?; - assert_eq!( - filtered.contains("permissionProfile?: ActivePermissionProfile"), - false - ); - assert_eq!( - filtered.contains( - r#"import type { ActivePermissionProfile } from "./ActivePermissionProfile";"# - ), - false - ); + assert_eq!(filtered.contains("permissionProfile?: string"), false); assert_eq!(filtered.contains("sandboxPolicy?: SandboxPolicy"), true); assert_eq!( filtered.contains(r#"import type { SandboxPolicy } from "./SandboxPolicy";"#), diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index 4e6cef308e0c..7a7fe5642c99 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -1555,6 +1555,7 @@ mod tests { use anyhow::Result; use codex_protocol::ThreadId; use codex_protocol::account::PlanType; + use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY; use codex_protocol::parse_command::ParsedCommand; use codex_protocol::protocol::RealtimeConversationVersion; use codex_protocol::protocol::RealtimeOutputModality; @@ -2994,7 +2995,7 @@ mod tests { env: None, size: None, sandbox_policy: None, - permission_profile: Some(v2::ActivePermissionProfile::read_only()), + permission_profile: Some(BUILT_IN_PERMISSION_PROFILE_READ_ONLY.to_string()), }, }; diff --git a/codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs b/codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs index d476dcb90e00..8f913b5bcfb5 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs @@ -1,4 +1,3 @@ -use super::ActivePermissionProfile; use super::SandboxPolicy; use codex_experimental_api_macros::ExperimentalApi; use schemars::JsonSchema; @@ -100,13 +99,13 @@ pub struct CommandExecParams { /// combined with `permissionProfile`. #[ts(optional = nullable)] pub sandbox_policy: Option, - /// Optional active permissions profile for this command. + /// Optional active permissions profile id for this command. /// /// Defaults to the user's configured permissions when omitted. Cannot be /// combined with `sandboxPolicy`. #[experimental("command/exec.permissionProfile")] #[ts(optional = nullable)] - pub permission_profile: Option, + pub permission_profile: Option, } /// Final buffered result for `command/exec`. diff --git a/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs b/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs index 3299695497c2..f00bcfaefb31 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs @@ -18,9 +18,7 @@ use codex_protocol::request_permissions::RequestPermissionProfile as CoreRequest use codex_utils_absolute_path::AbsolutePathBuf; use schemars::JsonSchema; use serde::Deserialize; -use serde::Deserializer; use serde::Serialize; -use serde::Serializer; use std::num::NonZeroUsize; use std::path::PathBuf; use ts_rs::TS; @@ -333,102 +331,6 @@ impl From for CoreActivePermissionProfile { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PermissionProfileSelectionParams { - id: String, - legacy_additional_writable_roots: Vec, -} - -impl PermissionProfileSelectionParams { - pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - legacy_additional_writable_roots: Vec::new(), - } - } - - pub fn id(&self) -> &str { - &self.id - } - - pub fn into_id(self) -> String { - self.id - } - - pub fn legacy_additional_writable_roots(&self) -> &[AbsolutePathBuf] { - &self.legacy_additional_writable_roots - } -} - -impl From for PermissionProfileSelectionParams { - fn from(id: String) -> Self { - Self::new(id) - } -} - -impl Serialize for PermissionProfileSelectionParams { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.id) - } -} - -impl<'de> Deserialize<'de> for PermissionProfileSelectionParams { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(untagged)] - enum Wire { - Id(String), - LegacyProfile { - #[serde(rename = "type")] - _type: LegacyPermissionProfileSelectionType, - id: String, - #[serde(default)] - modifications: Option>, - }, - } - - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - enum LegacyPermissionProfileSelectionType { - Profile, - } - - #[derive(Deserialize)] - #[serde(tag = "type", rename_all = "camelCase")] - enum LegacyPermissionProfileModificationParams { - #[serde(rename_all = "camelCase")] - AdditionalWritableRoot { path: AbsolutePathBuf }, - } - - match Wire::deserialize(deserializer)? { - Wire::Id(id) => Ok(Self::new(id)), - Wire::LegacyProfile { - id, modifications, .. - } => { - let legacy_additional_writable_roots = modifications - .unwrap_or_default() - .into_iter() - .map(|modification| match modification { - LegacyPermissionProfileModificationParams::AdditionalWritableRoot { - path, - } => path, - }) - .collect(); - Ok(Self { - id, - legacy_additional_writable_roots, - }) - } - } - } -} - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] diff --git a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs index 40ec247338bf..b445fc4d01af 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs @@ -14,6 +14,7 @@ use codex_protocol::mcp::CallToolResult; use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation; use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry; use codex_protocol::models::AdditionalPermissionProfile as CoreAdditionalPermissionProfile; +use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE; use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions; use codex_protocol::models::ImageDetail; use codex_protocol::models::MessagePhase; @@ -614,57 +615,49 @@ fn permissions_request_approval_response_accepts_strict_auto_review() { } #[test] -fn permission_profile_selection_accepts_legacy_object_shape() { - let additional_root = absolute_path("additional-root"); - let params = json!({ - "permissions": { - "type": "profile", - "id": ":workspace", - "modifications": [ - { - "type": "additionalWritableRoot", - "path": additional_root, - } - ], - }, - }); +fn permission_profile_selection_uses_id_string() { + let start: ThreadStartParams = serde_json::from_value(json!({ + "permissions": BUILT_IN_PERMISSION_PROFILE_WORKSPACE, + })) + .expect("thread/start params deserialize"); + assert_eq!( + start.permissions, + Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()) + ); + + let turn: TurnStartParams = serde_json::from_value(json!({ + "threadId": "thread-1", + "input": [], + "permissions": "dev", + })) + .expect("turn/start params deserialize"); + assert_eq!(turn.permissions, Some("dev".to_string())); - let start: ThreadStartParams = - serde_json::from_value(params.clone()).expect("thread/start params deserialize"); - assert_legacy_permission_profile_selection(start.permissions, &additional_root); + let command: CommandExecParams = serde_json::from_value(json!({ + "command": ["echo", "hello"], + "permissionProfile": "dev", + })) + .expect("command/exec params deserialize"); + assert_eq!(command.permission_profile, Some("dev".to_string())); let resume: ThreadResumeParams = serde_json::from_value(json!({ "threadId": "thread-1", - "permissions": params["permissions"].clone(), + "permissions": BUILT_IN_PERMISSION_PROFILE_WORKSPACE, })) .expect("thread/resume params deserialize"); - assert_legacy_permission_profile_selection(resume.permissions, &additional_root); + assert_eq!( + resume.permissions, + Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()) + ); let fork: ThreadForkParams = serde_json::from_value(json!({ "threadId": "thread-1", - "permissions": params["permissions"].clone(), + "permissions": BUILT_IN_PERMISSION_PROFILE_WORKSPACE, })) .expect("thread/fork params deserialize"); - assert_legacy_permission_profile_selection(fork.permissions, &additional_root); - - let turn: TurnStartParams = serde_json::from_value(json!({ - "threadId": "thread-1", - "input": [], - "permissions": params["permissions"].clone(), - })) - .expect("turn/start params deserialize"); - assert_legacy_permission_profile_selection(turn.permissions, &additional_root); -} - -fn assert_legacy_permission_profile_selection( - selection: Option, - additional_root: &AbsolutePathBuf, -) { - let selection = selection.expect("permissions should be present"); - assert_eq!(selection.id(), ":workspace"); assert_eq!( - selection.legacy_additional_writable_roots(), - std::slice::from_ref(additional_root) + fork.permissions, + Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()) ); } diff --git a/codex-rs/app-server-protocol/src/protocol/v2/thread.rs b/codex-rs/app-server-protocol/src/protocol/v2/thread.rs index 53f942cf80fb..41994e59b682 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/thread.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/thread.rs @@ -1,7 +1,6 @@ use super::ActivePermissionProfile; use super::ApprovalsReviewer; use super::AskForApproval; -use super::PermissionProfileSelectionParams; use super::SandboxMode; use super::SandboxPolicy; use super::Thread; @@ -122,10 +121,8 @@ pub struct ThreadStartParams { pub sandbox: Option, /// Named profile id for this thread. Cannot be combined with `sandbox`. #[experimental("thread/start.permissions")] - #[schemars(with = "Option")] - #[ts(type = "string | null")] #[ts(optional = nullable)] - pub permissions: Option, + pub permissions: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] @@ -284,10 +281,8 @@ pub struct ThreadResumeParams { /// Named profile id for the resumed thread. Cannot be combined with /// `sandbox`. #[experimental("thread/resume.permissions")] - #[schemars(with = "Option")] - #[ts(type = "string | null")] #[ts(optional = nullable)] - pub permissions: Option, + pub permissions: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] @@ -395,10 +390,8 @@ pub struct ThreadForkParams { /// Named profile id for the forked thread. Cannot be combined with /// `sandbox`. #[experimental("thread/fork.permissions")] - #[schemars(with = "Option")] - #[ts(type = "string | null")] #[ts(optional = nullable)] - pub permissions: Option, + pub permissions: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] diff --git a/codex-rs/app-server-protocol/src/protocol/v2/turn.rs b/codex-rs/app-server-protocol/src/protocol/v2/turn.rs index 8781dd2bd5ed..50660af1d7d4 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/turn.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/turn.rs @@ -1,6 +1,5 @@ use super::ApprovalsReviewer; use super::AskForApproval; -use super::PermissionProfileSelectionParams; use super::SandboxPolicy; use super::Turn; use codex_experimental_api_macros::ExperimentalApi; @@ -85,10 +84,8 @@ pub struct TurnStartParams { /// Select a named permissions profile id for this turn and subsequent /// turns. Cannot be combined with `sandboxPolicy`. #[experimental("turn/start.permissions")] - #[schemars(with = "Option")] - #[ts(type = "string | null")] #[ts(optional = nullable)] - pub permissions: Option, + pub permissions: Option, /// Override the model for this turn and subsequent turns. #[ts(optional = nullable)] pub model: Option, diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 4f9cb7c34425..e2978861de11 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -927,7 +927,7 @@ Run a standalone command (argv vector) in the server’s sandbox without creatin "cwd": "/Users/me/project", // optional; defaults to server cwd "env": { "FOO": "override" }, // optional; merges into the server env and overrides matching names "size": { "rows": 40, "cols": 120 }, // optional; PTY size in character cells, only valid with tty=true - "permissionProfile": { "id": ":workspace", "extends": null }, // optional; defaults to user config + "permissionProfile": ":workspace", // optional profile id; defaults to user config "outputBytesCap": 1048576, // optional; per-stream capture cap "disableOutputCap": false, // optional; cannot be combined with outputBytesCap "timeoutMs": 10000, // optional; ms timeout; defaults to server timeout diff --git a/codex-rs/app-server/src/request_processors.rs b/codex-rs/app-server/src/request_processors.rs index e941caca091e..ba28840f5046 100644 --- a/codex-rs/app-server/src/request_processors.rs +++ b/codex-rs/app-server/src/request_processors.rs @@ -103,7 +103,6 @@ use codex_app_server_protocol::MockExperimentalMethodParams; use codex_app_server_protocol::MockExperimentalMethodResponse; use codex_app_server_protocol::ModelListParams; use codex_app_server_protocol::ModelListResponse; -use codex_app_server_protocol::PermissionProfileSelectionParams; use codex_app_server_protocol::PluginDetail; use codex_app_server_protocol::PluginInstallParams; use codex_app_server_protocol::PluginInstallResponse; diff --git a/codex-rs/app-server/src/request_processors/command_exec_processor.rs b/codex-rs/app-server/src/request_processors/command_exec_processor.rs index 2b07588c8ae5..1219eb17f98c 100644 --- a/codex-rs/app-server/src/request_processors/command_exec_processor.rs +++ b/codex-rs/app-server/src/request_processors/command_exec_processor.rs @@ -117,13 +117,6 @@ impl CommandExecRequestProcessor { "`permissionProfile` cannot be combined with `sandboxPolicy`", )); } - let permission_profile = if let Some(active_permission_profile) = permission_profile { - Some(PermissionProfileSelectionParams::new( - active_permission_profile.id, - )) - } else { - None - }; if size.is_some() && !tty { return Err(invalid_params("command/exec size requires tty: true")); @@ -199,14 +192,11 @@ impl CommandExecRequestProcessor { network_proxy_permission_profile, managed_network_requirements_enabled, ) = if let Some(permission_profile) = permission_profile { - let mut overrides = ConfigOverrides { + let overrides = ConfigOverrides { cwd: Some(cwd.to_path_buf()), + default_permissions: Some(permission_profile), ..Default::default() }; - apply_permission_profile_selection_to_config_overrides( - &mut overrides, - Some(permission_profile), - ); let config = self .config_manager .load_for_cwd( diff --git a/codex-rs/app-server/src/request_processors/thread_processor.rs b/codex-rs/app-server/src/request_processors/thread_processor.rs index 21160950ab5a..dd2dd6a57e35 100644 --- a/codex-rs/app-server/src/request_processors/thread_processor.rs +++ b/codex-rs/app-server/src/request_processors/thread_processor.rs @@ -1239,17 +1239,18 @@ impl ThreadRequestProcessor { approval_policy: Option, approvals_reviewer: Option, sandbox: Option, - permissions: Option, + permissions: Option, base_instructions: Option, developer_instructions: Option, personality: Option, ) -> ConfigOverrides { - let mut overrides = ConfigOverrides { + ConfigOverrides { model, model_provider, service_tier, cwd: cwd.map(PathBuf::from), workspace_roots: runtime_workspace_roots, + default_permissions: permissions, approval_policy: approval_policy .map(codex_app_server_protocol::AskForApproval::to_core), approvals_reviewer: approvals_reviewer @@ -1261,9 +1262,7 @@ impl ThreadRequestProcessor { developer_instructions, personality, ..Default::default() - }; - apply_permission_profile_selection_to_config_overrides(&mut overrides, permissions); - overrides + } } fn parse_environment_selections( diff --git a/codex-rs/app-server/src/request_processors/thread_summary.rs b/codex-rs/app-server/src/request_processors/thread_summary.rs index 63ceeb55e2a6..fea49b163791 100644 --- a/codex-rs/app-server/src/request_processors/thread_summary.rs +++ b/codex-rs/app-server/src/request_processors/thread_summary.rs @@ -175,29 +175,6 @@ pub(super) fn thread_response_active_permission_profile( active_permission_profile.map(Into::into) } -pub(super) fn apply_permission_profile_selection_to_config_overrides( - overrides: &mut ConfigOverrides, - permissions: Option, -) { - let Some(selection) = permissions else { - return; - }; - overrides.default_permissions = Some(selection.id().to_string()); - if selection.legacy_additional_writable_roots().is_empty() { - return; - } - - let legacy_roots = selection - .legacy_additional_writable_roots() - .iter() - .map(AbsolutePathBuf::to_path_buf); - if let Some(workspace_roots) = overrides.workspace_roots.as_mut() { - workspace_roots.extend(legacy_roots); - } else { - overrides.additional_writable_roots.extend(legacy_roots); - } -} - pub(super) fn thread_response_sandbox_policy( permission_profile: &codex_protocol::models::PermissionProfile, cwd: &Path, diff --git a/codex-rs/app-server/src/request_processors/thread_summary_tests.rs b/codex-rs/app-server/src/request_processors/thread_summary_tests.rs index 699db34ed437..f8902e132d54 100644 --- a/codex-rs/app-server/src/request_processors/thread_summary_tests.rs +++ b/codex-rs/app-server/src/request_processors/thread_summary_tests.rs @@ -66,43 +66,3 @@ fn extract_conversation_summary_prefers_plain_user_messages() -> Result<()> { assert_eq!(summary, expected); Ok(()) } - -#[test] -fn legacy_permission_profile_modifications_extend_runtime_roots() -> Result<()> { - let root = if cfg!(windows) { - AbsolutePathBuf::try_from("C:\\workspace-extra")? - } else { - AbsolutePathBuf::try_from("/workspace-extra")? - }; - let selection = serde_json::from_value::(json!({ - "type": "profile", - "id": ":workspace", - "modifications": [ - { - "type": "additionalWritableRoot", - "path": root, - } - ], - }))?; - - let mut overrides = ConfigOverrides::default(); - apply_permission_profile_selection_to_config_overrides(&mut overrides, Some(selection.clone())); - assert_eq!( - overrides.default_permissions, - Some(":workspace".to_string()) - ); - assert_eq!( - overrides.additional_writable_roots, - vec![root.to_path_buf()] - ); - - let mut overrides = ConfigOverrides { - workspace_roots: Some(Vec::new()), - ..ConfigOverrides::default() - }; - apply_permission_profile_selection_to_config_overrides(&mut overrides, Some(selection)); - assert_eq!(overrides.additional_writable_roots, Vec::::new()); - assert_eq!(overrides.workspace_roots, Some(vec![root.to_path_buf()])); - - Ok(()) -} diff --git a/codex-rs/app-server/src/request_processors/turn_processor.rs b/codex-rs/app-server/src/request_processors/turn_processor.rs index 54fc0383e44b..55a4e3a838c7 100644 --- a/codex-rs/app-server/src/request_processors/turn_processor.rs +++ b/codex-rs/app-server/src/request_processors/turn_processor.rs @@ -425,7 +425,7 @@ impl TurnRequestProcessor { "turn/start permission selection missing thread snapshot", )); }; - let mut overrides = ConfigOverrides { + let overrides = ConfigOverrides { cwd: cwd.clone(), workspace_roots: Some(runtime_workspace_roots_request.clone().unwrap_or_else( || { @@ -436,14 +436,11 @@ impl TurnRequestProcessor { .collect() }, )), + default_permissions: Some(permissions), codex_linux_sandbox_exe: self.arg0_paths.codex_linux_sandbox_exe.clone(), main_execve_wrapper_exe: self.arg0_paths.main_execve_wrapper_exe.clone(), ..Default::default() }; - apply_permission_profile_selection_to_config_overrides( - &mut overrides, - Some(permissions), - ); let config = self .config_manager .load_for_cwd( diff --git a/codex-rs/app-server/tests/suite/v2/command_exec.rs b/codex-rs/app-server/tests/suite/v2/command_exec.rs index e4c573e72f07..b4038299cf3a 100644 --- a/codex-rs/app-server/tests/suite/v2/command_exec.rs +++ b/codex-rs/app-server/tests/suite/v2/command_exec.rs @@ -5,7 +5,6 @@ use app_test_support::create_mock_responses_server_sequence_unchecked; use app_test_support::to_response; use base64::Engine; use base64::engine::general_purpose::STANDARD; -use codex_app_server_protocol::ActivePermissionProfile; use codex_app_server_protocol::CommandExecOutputDeltaNotification; use codex_app_server_protocol::CommandExecOutputStream; use codex_app_server_protocol::CommandExecParams; @@ -18,6 +17,7 @@ use codex_app_server_protocol::JSONRPCMessage; use codex_app_server_protocol::JSONRPCNotification; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::SandboxPolicy; +use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY; use pretty_assertions::assert_eq; use std::collections::HashMap; use std::path::Path; @@ -219,7 +219,7 @@ async fn command_exec_accepts_permission_profile() -> Result<()> { env: None, size: None, sandbox_policy: None, - permission_profile: Some(ActivePermissionProfile::read_only()), + permission_profile: Some(BUILT_IN_PERMISSION_PROFILE_READ_ONLY.to_string()), }) .await?; @@ -270,7 +270,7 @@ async fn command_exec_permission_profile_starts_selected_network_proxy() -> Resu env: None, size: None, sandbox_policy: None, - permission_profile: Some(ActivePermissionProfile::new("networked")), + permission_profile: Some("networked".to_string()), }) .await?; @@ -318,7 +318,7 @@ async fn command_exec_permission_profile_does_not_reuse_default_network_proxy() env: None, size: None, sandbox_policy: None, - permission_profile: Some(ActivePermissionProfile::read_only()), + permission_profile: Some(BUILT_IN_PERMISSION_PROFILE_READ_ONLY.to_string()), }) .await?; @@ -376,7 +376,7 @@ async fn command_exec_permission_profile_project_roots_use_command_cwd() -> Resu env: None, size: None, sandbox_policy: None, - permission_profile: Some(ActivePermissionProfile::new("command-cwd")), + permission_profile: Some("command-cwd".to_string()), }) .await?; @@ -423,7 +423,7 @@ async fn command_exec_rejects_sandbox_policy_with_permission_profile() -> Result env: None, size: None, sandbox_policy: Some(SandboxPolicy::DangerFullAccess), - permission_profile: Some(ActivePermissionProfile::read_only()), + permission_profile: Some(BUILT_IN_PERMISSION_PROFILE_READ_ONLY.to_string()), }) .await?; diff --git a/codex-rs/app-server/tests/suite/v2/turn_start.rs b/codex-rs/app-server/tests/suite/v2/turn_start.rs index 844d9ab1bbe1..ae74b3432fc1 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_start.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_start.rs @@ -889,11 +889,7 @@ async fn turn_start_rejects_invalid_permission_selection_before_starting_turn() text: "Hello".to_string(), text_elements: Vec::new(), }], - permissions: Some( - BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS - .to_string() - .into(), - ), + permissions: Some(BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS.to_string()), ..Default::default() }) .await?; @@ -2147,7 +2143,7 @@ stream_max_retries = 0 text_elements: Vec::new(), }], runtime_workspace_roots: Some(vec![old_root]), - permissions: Some("dev".to_string().into()), + permissions: Some("dev".to_string()), ..Default::default() }) .await?; diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 3e2cf210511e..a8965aa37f0d 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -24,7 +24,6 @@ use codex_app_server_protocol::ConfigWarningNotification; use codex_app_server_protocol::JSONRPCErrorError; use codex_app_server_protocol::McpServerElicitationAction; use codex_app_server_protocol::McpServerElicitationRequestResponse; -use codex_app_server_protocol::PermissionProfileSelectionParams; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::ReviewStartParams; use codex_app_server_protocol::ReviewStartResponse; @@ -1007,17 +1006,15 @@ fn thread_resume_params_from_config(config: &Config, thread_id: String) -> Threa } } -fn permissions_selection_from_config(config: &Config) -> Option { +fn permissions_selection_from_config(config: &Config) -> Option { config .permissions .active_permission_profile() - .map(permissions_selection_from_active_profile) + .map(permission_profile_id_from_active_profile) } -fn permissions_selection_from_active_profile( - active: ActivePermissionProfile, -) -> PermissionProfileSelectionParams { - PermissionProfileSelectionParams::new(active.id) +fn permission_profile_id_from_active_profile(active: ActivePermissionProfile) -> String { + active.id } fn sandbox_mode_from_permission_profile( diff --git a/codex-rs/exec/src/lib_tests.rs b/codex-rs/exec/src/lib_tests.rs index 92dc0678e5b4..6cbcc3b154d7 100644 --- a/codex-rs/exec/src/lib_tests.rs +++ b/codex-rs/exec/src/lib_tests.rs @@ -460,14 +460,11 @@ async fn thread_start_params_include_review_policy_when_auto_review_is_enabled() #[test] fn active_profile_selection_uses_profile_id_only() { - let selection = permissions_selection_from_active_profile(ActivePermissionProfile::new( + let selection = permission_profile_id_from_active_profile(ActivePermissionProfile::new( BUILT_IN_PERMISSION_PROFILE_WORKSPACE, )); - assert_eq!( - selection, - PermissionProfileSelectionParams::new(BUILT_IN_PERMISSION_PROFILE_WORKSPACE) - ); + assert_eq!(selection, BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()); } #[tokio::test] diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs index 2620f80d5352..22e47765593e 100644 --- a/codex-rs/tui/src/app_server_session.rs +++ b/codex-rs/tui/src/app_server_session.rs @@ -34,7 +34,6 @@ use codex_app_server_protocol::MemoryResetResponse; use codex_app_server_protocol::Model as ApiModel; use codex_app_server_protocol::ModelListParams; use codex_app_server_protocol::ModelListResponse; -use codex_app_server_protocol::PermissionProfileSelectionParams; use codex_app_server_protocol::RateLimitSnapshot; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::ReviewDelivery; @@ -1182,10 +1181,8 @@ fn sandbox_mode_from_permission_profile( } } -fn permissions_selection_from_active_profile( - active: ActivePermissionProfile, -) -> PermissionProfileSelectionParams { - PermissionProfileSelectionParams::new(active.id) +fn permission_profile_id_from_active_profile(active: ActivePermissionProfile) -> String { + active.id } fn turn_permissions_overrides( @@ -1193,13 +1190,13 @@ fn turn_permissions_overrides( cwd: &std::path::Path, ) -> ( Option, - Option, + Option, ) { match permissions_override { TurnPermissionsOverride::Preserve => (None, None), TurnPermissionsOverride::ActiveProfile(active_permission_profile) => ( None, - Some(permissions_selection_from_active_profile( + Some(permission_profile_id_from_active_profile( active_permission_profile, )), ), @@ -1220,7 +1217,7 @@ fn turn_permissions_overrides( fn permissions_selection_from_config( config: &Config, thread_params_mode: ThreadParamsMode, -) -> Option { +) -> Option { if matches!(thread_params_mode, ThreadParamsMode::Remote) { return None; } @@ -1228,7 +1225,7 @@ fn permissions_selection_from_config( config .permissions .active_permission_profile() - .map(permissions_selection_from_active_profile) + .map(permission_profile_id_from_active_profile) } fn thread_start_params_from_config( @@ -1671,7 +1668,7 @@ mod tests { config .permissions .active_permission_profile() - .map(permissions_selection_from_active_profile) + .map(permission_profile_id_from_active_profile) ); assert_eq!(params.model_provider, Some(config.model_provider_id)); assert_eq!(params.thread_source, Some(ThreadSource::User)); @@ -1698,7 +1695,7 @@ mod tests { let active_permission_profile = ActivePermissionProfile::new(BUILT_IN_PERMISSION_PROFILE_WORKSPACE); let expected_permissions = - permissions_selection_from_active_profile(active_permission_profile.clone()); + permission_profile_id_from_active_profile(active_permission_profile.clone()); let (sandbox_policy, permissions) = turn_permissions_overrides( TurnPermissionsOverride::ActiveProfile(active_permission_profile), @@ -1723,9 +1720,7 @@ mod tests { assert_eq!(sandbox_policy, None); assert_eq!( permissions, - Some(PermissionProfileSelectionParams::new( - BUILT_IN_PERMISSION_PROFILE_WORKSPACE - )) + Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()) ); } @@ -1763,7 +1758,7 @@ mod tests { let cwd = test_path_buf("/workspace/project").abs(); let active_permission_profile = ActivePermissionProfile::new("strict"); let expected_permissions = - permissions_selection_from_active_profile(active_permission_profile.clone()); + permission_profile_id_from_active_profile(active_permission_profile.clone()); let (sandbox_policy, permissions) = turn_permissions_overrides( TurnPermissionsOverride::ActiveProfile(active_permission_profile),