Skip to content

Commit 4e95f07

Browse files
committed
Propagate runtime permission profiles
1 parent e76a989 commit 4e95f07

2 files changed

Lines changed: 116 additions & 21 deletions

File tree

codex-rs/tui/src/app/thread_routing.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ impl App {
530530
approval_policy,
531531
approvals_reviewer,
532532
sandbox_policy,
533-
permission_profile,
533+
permission_profile: _,
534534
model,
535535
effort,
536536
summary,
@@ -614,7 +614,10 @@ impl App {
614614
approvals_reviewer
615615
.unwrap_or(self.chat_widget.config_ref().approvals_reviewer),
616616
sandbox_policy.clone(),
617-
permission_profile.clone(),
617+
runtime_permission_profile_for_turn_start(
618+
self.runtime_sandbox_policy_override.as_ref(),
619+
sandbox_policy,
620+
),
618621
model.to_string(),
619622
effort,
620623
*summary,
@@ -1482,3 +1485,47 @@ impl App {
14821485
Ok(())
14831486
}
14841487
}
1488+
1489+
fn runtime_permission_profile_for_turn_start(
1490+
runtime_sandbox_policy_override: Option<&SandboxPolicy>,
1491+
sandbox_policy: &SandboxPolicy,
1492+
) -> Option<codex_protocol::models::PermissionProfile> {
1493+
runtime_sandbox_policy_override?;
1494+
match sandbox_policy {
1495+
SandboxPolicy::ExternalSandbox { .. } => None,
1496+
SandboxPolicy::ReadOnly { .. }
1497+
| SandboxPolicy::WorkspaceWrite { .. }
1498+
| SandboxPolicy::DangerFullAccess => Some(
1499+
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(sandbox_policy),
1500+
),
1501+
}
1502+
}
1503+
1504+
#[cfg(test)]
1505+
mod tests {
1506+
use super::*;
1507+
use codex_protocol::protocol::SandboxPolicy;
1508+
use pretty_assertions::assert_eq;
1509+
1510+
#[test]
1511+
fn runtime_permission_profile_for_turn_start_only_when_sandbox_was_overridden() {
1512+
let sandbox_policy = SandboxPolicy::DangerFullAccess;
1513+
1514+
assert_eq!(
1515+
runtime_permission_profile_for_turn_start(
1516+
/*runtime_sandbox_policy_override*/ None,
1517+
&sandbox_policy,
1518+
),
1519+
None
1520+
);
1521+
1522+
let profile =
1523+
runtime_permission_profile_for_turn_start(Some(&sandbox_policy), &sandbox_policy)
1524+
.expect("runtime sandbox override should send active permissions");
1525+
1526+
assert_eq!(
1527+
profile,
1528+
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy)
1529+
);
1530+
}
1531+
}

codex-rs/tui/src/app_server_session.rs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ impl AppServerSession {
548548
let request_id = self.next_request_id();
549549
let (sandbox_policy, permission_profile) = turn_start_permission_overrides(
550550
self.thread_params_mode(),
551-
sandbox_policy,
551+
&sandbox_policy,
552552
permission_profile,
553553
);
554554
self.client
@@ -1107,19 +1107,19 @@ fn sandbox_mode_from_policy(
11071107
}
11081108

11091109
fn turn_start_permission_overrides(
1110-
mode: ThreadParamsMode,
1111-
sandbox_policy: SandboxPolicy,
1110+
thread_params_mode: ThreadParamsMode,
1111+
sandbox_policy: &SandboxPolicy,
11121112
permission_profile: Option<PermissionProfile>,
11131113
) -> (
11141114
Option<codex_app_server_protocol::SandboxPolicy>,
11151115
Option<codex_app_server_protocol::PermissionProfile>,
11161116
) {
1117-
match (mode, permission_profile) {
1118-
(ThreadParamsMode::Embedded, Some(permission_profile)) => {
1119-
(None, Some(permission_profile.into()))
1120-
}
1121-
(ThreadParamsMode::Embedded, None) => (None, None),
1122-
(ThreadParamsMode::Remote, _) => (Some(sandbox_policy.into()), None),
1117+
if matches!(thread_params_mode, ThreadParamsMode::Remote)
1118+
|| matches!(sandbox_policy, SandboxPolicy::ExternalSandbox { .. })
1119+
{
1120+
(Some(sandbox_policy.clone().into()), None)
1121+
} else {
1122+
(None, permission_profile.map(Into::into))
11231123
}
11241124
}
11251125

@@ -1131,7 +1131,16 @@ fn permission_profile_override_from_config(
11311131
return None;
11321132
}
11331133

1134-
Some(config.permissions.permission_profile().into())
1134+
if matches!(
1135+
config
1136+
.permissions
1137+
.legacy_sandbox_policy(config.cwd.as_path()),
1138+
SandboxPolicy::ExternalSandbox { .. }
1139+
) {
1140+
None
1141+
} else {
1142+
Some(config.permissions.permission_profile().into())
1143+
}
11351144
}
11361145

11371146
fn thread_start_params_from_config(
@@ -1520,6 +1529,48 @@ mod tests {
15201529
assert_eq!(params.model_provider, Some(config.model_provider_id));
15211530
}
15221531

1532+
#[test]
1533+
fn embedded_turn_start_permission_overrides_send_runtime_profile_only_when_provided() {
1534+
let sandbox_policy = SandboxPolicy::DangerFullAccess;
1535+
let permission_profile = PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy);
1536+
1537+
assert_eq!(
1538+
turn_start_permission_overrides(
1539+
ThreadParamsMode::Embedded,
1540+
&sandbox_policy,
1541+
/*permission_profile*/ None,
1542+
),
1543+
(None, None)
1544+
);
1545+
1546+
assert_eq!(
1547+
turn_start_permission_overrides(
1548+
ThreadParamsMode::Embedded,
1549+
&sandbox_policy,
1550+
Some(permission_profile.clone()),
1551+
),
1552+
(None, Some(permission_profile.into()))
1553+
);
1554+
}
1555+
1556+
#[test]
1557+
fn remote_turn_start_permission_overrides_keep_legacy_sandbox_policy() {
1558+
let sandbox_policy = SandboxPolicy::DangerFullAccess;
1559+
let permission_profile = PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy);
1560+
1561+
assert_eq!(
1562+
turn_start_permission_overrides(
1563+
ThreadParamsMode::Remote,
1564+
&sandbox_policy,
1565+
Some(permission_profile),
1566+
),
1567+
(
1568+
Some(codex_app_server_protocol::SandboxPolicy::DangerFullAccess),
1569+
None
1570+
)
1571+
);
1572+
}
1573+
15231574
#[tokio::test]
15241575
async fn thread_start_params_can_mark_clear_source() {
15251576
let temp_dir = tempfile::tempdir().expect("tempdir");
@@ -1632,23 +1683,23 @@ mod tests {
16321683

16331684
let (sandbox, profile) = turn_start_permission_overrides(
16341685
ThreadParamsMode::Embedded,
1635-
workspace_write.clone(),
1686+
&workspace_write,
16361687
Some(workspace_write_profile.clone()),
16371688
);
16381689
assert_eq!(sandbox, None);
16391690
assert_eq!(profile, Some(workspace_write_profile.into()));
16401691

16411692
let (sandbox, profile) = turn_start_permission_overrides(
16421693
ThreadParamsMode::Embedded,
1643-
workspace_write.clone(),
1694+
&workspace_write,
16441695
/*permission_profile*/ None,
16451696
);
16461697
assert_eq!(sandbox, None);
16471698
assert_eq!(profile, None);
16481699

16491700
let (sandbox, profile) = turn_start_permission_overrides(
16501701
ThreadParamsMode::Remote,
1651-
workspace_write.clone(),
1702+
&workspace_write,
16521703
Some(PermissionProfile::from_legacy_sandbox_policy(
16531704
&workspace_write,
16541705
)),
@@ -1661,16 +1712,13 @@ mod tests {
16611712
};
16621713
let (sandbox, profile) = turn_start_permission_overrides(
16631714
ThreadParamsMode::Embedded,
1664-
external_sandbox.clone(),
1715+
&external_sandbox,
16651716
Some(PermissionProfile::from_legacy_sandbox_policy(
16661717
&external_sandbox,
16671718
)),
16681719
);
1669-
assert_eq!(sandbox, None);
1670-
assert_eq!(
1671-
profile,
1672-
Some(PermissionProfile::from_legacy_sandbox_policy(&external_sandbox).into())
1673-
);
1720+
assert_eq!(sandbox, Some(external_sandbox.into()));
1721+
assert_eq!(profile, None);
16741722
}
16751723

16761724
#[tokio::test]

0 commit comments

Comments
 (0)