app-server: use permission ids and runtime workspace roots

This commit is contained in:
Michael Bolin
2026-05-14 17:17:40 -07:00
parent 149b0e978d
commit 31f2bc6511
57 changed files with 802 additions and 607 deletions

View File

@@ -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::PermissionProfileModificationParams;
use codex_app_server_protocol::PermissionProfileSelectionParams;
use codex_app_server_protocol::RequestId;
use codex_app_server_protocol::ReviewStartParams;
@@ -790,6 +789,7 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> {
responsesapi_client_metadata: None,
environments: None,
cwd: Some(default_cwd),
runtime_workspace_roots: None,
approval_policy: Some(default_approval_policy.into()),
approvals_reviewer: None,
sandbox_policy: None,
@@ -961,6 +961,13 @@ fn thread_start_params_from_config(config: &Config) -> ThreadStartParams {
model: config.model.clone(),
model_provider: Some(config.model_provider_id.clone()),
cwd: Some(config.cwd.to_string_lossy().to_string()),
runtime_workspace_roots: Some(
config
.workspace_roots
.iter()
.map(AbsolutePathBuf::to_path_buf)
.collect(),
),
approval_policy: Some(config.permissions.approval_policy.value().into()),
approvals_reviewer: approvals_reviewer_override_from_config(config),
sandbox: sandbox.flatten(),
@@ -984,6 +991,13 @@ fn thread_resume_params_from_config(config: &Config, thread_id: String) -> Threa
model: config.model.clone(),
model_provider: Some(config.model_provider_id.clone()),
cwd: Some(config.cwd.to_string_lossy().to_string()),
runtime_workspace_roots: Some(
config
.workspace_roots
.iter()
.map(AbsolutePathBuf::to_path_buf)
.collect(),
),
approval_policy: Some(config.permissions.approval_policy.value().into()),
approvals_reviewer: approvals_reviewer_override_from_config(config),
sandbox: sandbox.flatten(),
@@ -997,30 +1011,13 @@ fn permissions_selection_from_config(config: &Config) -> Option<PermissionProfil
config
.permissions
.active_permission_profile()
.map(|active| {
permissions_selection_from_active_profile(
active,
config.cwd.as_path(),
config.permissions.user_visible_workspace_roots(),
)
})
.map(permissions_selection_from_active_profile)
}
fn permissions_selection_from_active_profile(
active: ActivePermissionProfile,
cwd: &Path,
workspace_roots: &[AbsolutePathBuf],
) -> PermissionProfileSelectionParams {
let modifications = workspace_roots
.iter()
.filter(|root| root.as_path() != cwd)
.cloned()
.map(|path| PermissionProfileModificationParams::AdditionalWritableRoot { path })
.collect::<Vec<_>>();
PermissionProfileSelectionParams::Profile {
id: active.id,
modifications: (!modifications.is_empty()).then_some(modifications),
}
PermissionProfileSelectionParams::new(active.id)
}
fn sandbox_mode_from_permission_profile(

View File

@@ -458,24 +458,14 @@ async fn thread_start_params_include_review_policy_when_auto_review_is_enabled()
}
#[test]
fn active_profile_selection_includes_extra_workspace_roots_as_modifications() {
let cwd = test_path_buf("/workspace/project").abs();
let extra_root = test_path_buf("/workspace/cache").abs();
let selection = permissions_selection_from_active_profile(
ActivePermissionProfile::new(BUILT_IN_PERMISSION_PROFILE_WORKSPACE),
cwd.as_path(),
&[cwd.clone(), extra_root.clone()],
);
fn active_profile_selection_uses_profile_id_only() {
let selection = permissions_selection_from_active_profile(ActivePermissionProfile::new(
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
));
assert_eq!(
selection,
PermissionProfileSelectionParams::Profile {
id: BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string(),
modifications: Some(vec![
PermissionProfileModificationParams::AdditionalWritableRoot { path: extra_root }
]),
}
PermissionProfileSelectionParams::new(BUILT_IN_PERMISSION_PROFILE_WORKSPACE)
);
}
@@ -582,6 +572,7 @@ fn sample_thread_start_response() -> ThreadStartResponse {
model_provider: "openai".to_string(),
service_tier: None,
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: codex_app_server_protocol::AskForApproval::OnRequest,
approvals_reviewer: codex_app_server_protocol::ApprovalsReviewer::AutoReview,