diff --git a/codex-rs/core/src/session/session.rs b/codex-rs/core/src/session/session.rs index 0734f3090a..7247d267c4 100644 --- a/codex-rs/core/src/session/session.rs +++ b/codex-rs/core/src/session/session.rs @@ -116,19 +116,19 @@ impl SessionConfiguration { &self.environments.environments } - pub(super) fn workspace_roots(&self) -> Vec { + pub(super) fn primary_workspace_roots(&self) -> Vec { self.environments .environments .first() - .and_then(|environment| { + .map(|environment| { environment .workspace_roots .iter() .map(PathUri::to_abs_path) .collect::>>() - .ok() + .unwrap_or_default() }) - .unwrap_or_else(|| vec![self.cwd().clone()]) + .unwrap_or_default() } pub(crate) fn codex_home(&self) -> &AbsolutePathBuf { @@ -140,10 +140,12 @@ impl SessionConfiguration { } pub(super) fn permission_profile(&self) -> PermissionProfile { - self.permission_profile_state - .permission_profile() - .clone() - .materialize_project_roots_with_workspace_roots(&self.workspace_roots()) + self.permission_profile_state.permission_profile().clone() + } + + fn materialized_permission_profile(&self) -> PermissionProfile { + self.permission_profile() + .materialize_project_roots_with_workspace_roots(&self.primary_workspace_roots()) } pub(super) fn active_permission_profile(&self) -> Option { @@ -171,7 +173,7 @@ impl SessionConfiguration { } pub(super) fn sandbox_policy(&self) -> SandboxPolicy { - let permission_profile = self.permission_profile(); + let permission_profile = self.materialized_permission_profile(); codex_sandboxing::compatibility_sandbox_policy_for_permission_profile( &permission_profile, self.cwd(), @@ -179,7 +181,8 @@ impl SessionConfiguration { } pub(super) fn file_system_sandbox_policy(&self) -> FileSystemSandboxPolicy { - self.permission_profile().file_system_sandbox_policy() + self.materialized_permission_profile() + .file_system_sandbox_policy() } pub(super) fn network_sandbox_policy(&self) -> NetworkSandboxPolicy { @@ -198,7 +201,7 @@ impl SessionConfiguration { permission_profile: self.permission_profile(), active_permission_profile: self.active_permission_profile(), environments: self.environments.clone(), - workspace_roots: self.workspace_roots(), + workspace_roots: self.primary_workspace_roots(), profile_workspace_roots: self.profile_workspace_roots().to_vec(), ephemeral: self.original_config_do_not_use.ephemeral, reasoning_effort: self.collaboration_mode.reasoning_effort(), diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 9791813dde..041970b012 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -4502,7 +4502,9 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd ) .expect("set permission profile"); let expected_file_system_sandbox_policy = file_system_sandbox_policy - .materialize_project_roots_with_workspace_roots(&session_configuration.workspace_roots()); + .materialize_project_roots_with_workspace_roots( + &session_configuration.primary_workspace_roots(), + ); let updated = session_configuration .apply(&SessionSettingsUpdate { @@ -4564,7 +4566,9 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_ .expect("permission profile update should succeed"); let mut expected_file_system_policy = requested_file_system_policy - .materialize_project_roots_with_workspace_roots(&session_configuration.workspace_roots()); + .materialize_project_roots_with_workspace_roots( + &session_configuration.primary_workspace_roots(), + ); expected_file_system_policy.glob_scan_max_depth = Some(2); expected_file_system_policy.entries.push(deny_entry); assert_eq!( @@ -4821,59 +4825,6 @@ enabled = false ); } -#[tokio::test] -async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_update() { - let mut session_configuration = make_session_configuration_for_tests().await; - let workspace = tempfile::tempdir().expect("create temp dir"); - let original_cwd = workspace.path().join("repo-a").abs(); - let project_root = workspace.path().join("repo-b").abs(); - session_configuration.environments = - TurnEnvironmentSelections::new(original_cwd.clone(), Vec::new()); - let sandbox_policy = SandboxPolicy::WorkspaceWrite { - writable_roots: Vec::new(), - network_access: false, - exclude_tmpdir_env_var: true, - exclude_slash_tmp: true, - }; - let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd( - &sandbox_policy, - session_configuration.cwd(), - ); - session_configuration - .set_permission_profile_for_tests( - PermissionProfile::from_runtime_permissions_with_enforcement( - SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy), - &file_system_sandbox_policy, - NetworkSandboxPolicy::from(&sandbox_policy), - ), - ) - .expect("set permission profile"); - - let updated = session_configuration - .apply(&SessionSettingsUpdate { - environments: Some(TurnEnvironmentSelections::new( - project_root.clone(), - Vec::new(), - )), - ..Default::default() - }) - .expect("cwd-only update should succeed"); - - assert_eq!(updated.workspace_roots(), vec![project_root.clone()]); - assert!( - updated - .file_system_sandbox_policy() - .can_write_path_with_cwd(project_root.as_path(), updated.cwd().as_path()), - "cwd-only update should keep the new cwd writable" - ); - assert!( - !updated - .file_system_sandbox_policy() - .can_write_path_with_cwd(original_cwd.as_path(), updated.cwd().as_path()), - "cwd-only update should not keep the old implicit cwd writable" - ); -} - #[tokio::test] async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_update() { let mut session_configuration = make_session_configuration_for_tests().await; @@ -5275,7 +5226,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) { let per_turn_config = Session::build_per_turn_config( &session_configuration, session_configuration.cwd().clone(), - session_configuration.workspace_roots(), + session_configuration.primary_workspace_roots(), ); let model_info = construct_model_info_offline_for_tests( session_configuration.collaboration_mode.model(), @@ -7409,7 +7360,7 @@ where let per_turn_config = Session::build_per_turn_config( &session_configuration, session_configuration.cwd().clone(), - session_configuration.workspace_roots(), + session_configuration.primary_workspace_roots(), ); let model_info = construct_model_info_offline_for_tests( session_configuration.collaboration_mode.model(), diff --git a/codex-rs/core/src/session/turn_context.rs b/codex-rs/core/src/session/turn_context.rs index bf50a5b206..65157cde83 100644 --- a/codex-rs/core/src/session/turn_context.rs +++ b/codex-rs/core/src/session/turn_context.rs @@ -471,7 +471,7 @@ impl Session { pub(crate) fn build_effective_session_config( session_configuration: &SessionConfiguration, ) -> Config { - let workspace_roots = session_configuration.workspace_roots(); + let workspace_roots = session_configuration.primary_workspace_roots(); let mut config = Self::build_per_turn_config( session_configuration, session_configuration.cwd().clone(), @@ -718,7 +718,7 @@ impl Session { .transpose() .ok() .flatten() - .unwrap_or_else(|| session_configuration.workspace_roots()); + .unwrap_or_default(); let per_turn_config = Self::build_per_turn_config(&session_configuration, cwd.clone(), workspace_roots); {