mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
app-server: use permission ids and runtime workspace roots
This commit is contained in:
@@ -146,6 +146,8 @@ pub(super) async fn user_input_or_turn_inner(
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer,
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
workspace_roots: None,
|
||||
profile_workspace_roots: None,
|
||||
permission_profile,
|
||||
active_permission_profile: None,
|
||||
windows_sandbox_level: None,
|
||||
@@ -163,6 +165,8 @@ pub(super) async fn user_input_or_turn_inner(
|
||||
}
|
||||
Op::UserInputWithTurnContext {
|
||||
cwd,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
approvals_reviewer,
|
||||
sandbox_policy,
|
||||
@@ -195,6 +199,8 @@ pub(super) async fn user_input_or_turn_inner(
|
||||
items,
|
||||
SessionSettingsUpdate {
|
||||
cwd,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
approvals_reviewer,
|
||||
sandbox_policy,
|
||||
|
||||
@@ -621,6 +621,8 @@ impl Codex {
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: environment_selections.to_selections(),
|
||||
|
||||
@@ -75,6 +75,12 @@ pub(crate) struct SessionConfiguration {
|
||||
/// execution sandbox are resolved against this directory **instead** of
|
||||
/// the process-wide current working directory.
|
||||
pub(super) cwd: AbsolutePathBuf,
|
||||
/// Thread-scoped runtime workspace roots for materializing symbolic
|
||||
/// workspace permissions at session runtime.
|
||||
pub(super) workspace_roots: Vec<AbsolutePathBuf>,
|
||||
/// Immutable workspace roots configured directly on the selected
|
||||
/// permissions profile.
|
||||
pub(super) profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
/// Directory containing all Codex state for this session.
|
||||
pub(super) codex_home: AbsolutePathBuf,
|
||||
/// Optional user-facing name for the thread, updated during the session.
|
||||
@@ -104,7 +110,10 @@ impl SessionConfiguration {
|
||||
}
|
||||
|
||||
pub(super) fn permission_profile(&self) -> PermissionProfile {
|
||||
self.permission_profile.get().clone()
|
||||
self.permission_profile
|
||||
.get()
|
||||
.clone()
|
||||
.materialize_project_roots_with_workspace_roots(&self.workspace_roots)
|
||||
}
|
||||
|
||||
pub(super) fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
|
||||
@@ -126,7 +135,7 @@ impl SessionConfiguration {
|
||||
}
|
||||
|
||||
pub(super) fn file_system_sandbox_policy(&self) -> FileSystemSandboxPolicy {
|
||||
self.permission_profile.get().file_system_sandbox_policy()
|
||||
self.permission_profile().file_system_sandbox_policy()
|
||||
}
|
||||
|
||||
pub(super) fn network_sandbox_policy(&self) -> NetworkSandboxPolicy {
|
||||
@@ -143,6 +152,8 @@ impl SessionConfiguration {
|
||||
permission_profile: self.permission_profile(),
|
||||
active_permission_profile: self.active_permission_profile(),
|
||||
cwd: self.cwd.clone(),
|
||||
workspace_roots: self.workspace_roots.clone(),
|
||||
profile_workspace_roots: self.profile_workspace_roots.clone(),
|
||||
ephemeral: self.original_config_do_not_use.ephemeral,
|
||||
reasoning_effort: self.collaboration_mode.reasoning_effort(),
|
||||
personality: self.personality,
|
||||
@@ -222,6 +233,9 @@ impl SessionConfiguration {
|
||||
|
||||
let cwd_changed = absolute_cwd.as_path() != self.cwd.as_path();
|
||||
next_configuration.cwd = absolute_cwd;
|
||||
if let Some(workspace_roots) = updates.workspace_roots.clone() {
|
||||
next_configuration.workspace_roots = workspace_roots;
|
||||
}
|
||||
|
||||
if let Some(permission_profile) = updates.permission_profile.clone() {
|
||||
let active_permission_profile =
|
||||
@@ -237,6 +251,8 @@ impl SessionConfiguration {
|
||||
Some(¤t_file_system_sandbox_policy),
|
||||
)?;
|
||||
next_configuration.active_permission_profile = active_permission_profile;
|
||||
next_configuration.profile_workspace_roots =
|
||||
updates.profile_workspace_roots.clone().unwrap_or_default();
|
||||
} else if let Some(sandbox_policy) = updates.sandbox_policy.clone() {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
@@ -253,6 +269,7 @@ impl SessionConfiguration {
|
||||
),
|
||||
)?;
|
||||
next_configuration.active_permission_profile = None;
|
||||
next_configuration.profile_workspace_roots.clear();
|
||||
} else if cwd_changed
|
||||
&& file_system_policy_matches_legacy
|
||||
&& file_system_policy_has_rebindable_project_root_write
|
||||
@@ -309,6 +326,8 @@ impl SessionConfiguration {
|
||||
#[derive(Default, Clone)]
|
||||
pub(crate) struct SessionSettingsUpdate {
|
||||
pub(crate) cwd: Option<PathBuf>,
|
||||
pub(crate) workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub(crate) profile_workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub(crate) approval_policy: Option<AskForApproval>,
|
||||
pub(crate) approvals_reviewer: Option<ApprovalsReviewer>,
|
||||
pub(crate) sandbox_policy: Option<SandboxPolicy>,
|
||||
|
||||
@@ -36,6 +36,7 @@ use codex_protocol::account::PlanType as AccountPlanType;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::config_types::TrustLevel;
|
||||
use codex_protocol::exec_output::ExecToolCallOutput;
|
||||
use codex_protocol::models::ActivePermissionProfile;
|
||||
use codex_protocol::models::FileSystemPermissions;
|
||||
use codex_protocol::models::FunctionCallOutputBody;
|
||||
use codex_protocol::models::FunctionCallOutputPayload;
|
||||
@@ -2891,6 +2892,8 @@ async fn set_rate_limits_retains_previous_credits() {
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
@@ -2995,6 +2998,8 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
@@ -3468,6 +3473,8 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
@@ -3647,6 +3654,49 @@ async fn session_configuration_apply_permission_profile_accepts_direct_write_roo
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn session_configuration_apply_rebinds_symbolic_profile_to_updated_workspace_roots() {
|
||||
let mut session_configuration = make_session_configuration_for_tests().await;
|
||||
let old_root = tempfile::tempdir().expect("create old root");
|
||||
let new_root = tempfile::tempdir().expect("create new root");
|
||||
let profile_root = tempfile::tempdir().expect("create profile root");
|
||||
let old_root = old_root.path().abs();
|
||||
let new_root = new_root.path().abs();
|
||||
let profile_root = profile_root.path().abs();
|
||||
session_configuration.workspace_roots = vec![old_root.clone()];
|
||||
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(/*subpath*/ None),
|
||||
},
|
||||
access: FileSystemAccessMode::Write,
|
||||
}]);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
);
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
workspace_roots: Some(vec![new_root.clone()]),
|
||||
permission_profile: Some(permission_profile),
|
||||
active_permission_profile: Some(ActivePermissionProfile::new("dev")),
|
||||
profile_workspace_roots: Some(vec![profile_root.clone()]),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("permission profile update should succeed");
|
||||
|
||||
let updated_policy = updated.file_system_sandbox_policy();
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd.as_path()));
|
||||
assert_eq!(
|
||||
updated.active_permission_profile(),
|
||||
Some(ActivePermissionProfile::new("dev"))
|
||||
);
|
||||
assert_eq!(updated.profile_workspace_roots, vec![profile_root]);
|
||||
}
|
||||
|
||||
#[cfg_attr(windows, ignore)]
|
||||
#[tokio::test]
|
||||
async fn new_default_turn_uses_config_aware_skills_for_role_overrides() {
|
||||
@@ -4001,6 +4051,8 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
@@ -4110,6 +4162,8 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
@@ -4342,6 +4396,8 @@ async fn make_session_with_config_and_rx(
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
@@ -4445,6 +4501,8 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
@@ -5094,6 +5152,8 @@ fn op_kind_distinguishes_turn_ops() {
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
cwd: None,
|
||||
workspace_roots: None,
|
||||
profile_workspace_roots: None,
|
||||
approval_policy: None,
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: None,
|
||||
@@ -5962,6 +6022,8 @@ where
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
profile_workspace_roots: config.permissions.profile_workspace_roots().to_vec(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
|
||||
@@ -432,6 +432,10 @@ impl Session {
|
||||
let config = session_configuration.original_config_do_not_use.clone();
|
||||
let mut per_turn_config = (*config).clone();
|
||||
per_turn_config.cwd = cwd;
|
||||
per_turn_config.workspace_roots = session_configuration.workspace_roots.clone();
|
||||
per_turn_config
|
||||
.permissions
|
||||
.set_workspace_roots(session_configuration.workspace_roots.clone());
|
||||
per_turn_config.model_reasoning_effort =
|
||||
session_configuration.collaboration_mode.reasoning_effort();
|
||||
per_turn_config.model_reasoning_summary = session_configuration.model_reasoning_summary;
|
||||
@@ -440,9 +444,10 @@ impl Session {
|
||||
per_turn_config.approvals_reviewer = session_configuration.approvals_reviewer;
|
||||
per_turn_config
|
||||
.permissions
|
||||
.set_constrained_permission_profile_with_active_profile(
|
||||
.set_constrained_permission_profile_with_active_profile_and_workspace_roots(
|
||||
session_configuration.permission_profile.clone(),
|
||||
session_configuration.active_permission_profile.clone(),
|
||||
session_configuration.profile_workspace_roots.clone(),
|
||||
);
|
||||
let permission_profile = session_configuration.permission_profile();
|
||||
let resolved_web_search_mode =
|
||||
@@ -470,6 +475,10 @@ impl Session {
|
||||
Self::build_per_turn_config(session_configuration, session_configuration.cwd.clone());
|
||||
config.model = Some(session_configuration.collaboration_mode.model().to_string());
|
||||
config.permissions.approval_policy = session_configuration.approval_policy.clone();
|
||||
config.workspace_roots = session_configuration.workspace_roots.clone();
|
||||
config
|
||||
.permissions
|
||||
.set_workspace_roots(session_configuration.workspace_roots.clone());
|
||||
config
|
||||
.permissions
|
||||
.set_active_permission_profile_for_current_profile(
|
||||
|
||||
Reference in New Issue
Block a user