core: refresh active permission profiles at runtime (#22931)

## Why

Once a named permission profile is selected, runtime state has to keep
that profile identity intact instead of collapsing back to anonymous
effective permissions. The session refresh path also needs to rebuild
profile-derived network proxy state so active profile switches take
effect consistently.

## What changed

- Preserve the active permission profile through session updates.
- Rebuild profile-derived runtime/network configuration when the active
profile changes.
- Keep the runtime path aligned with the current session configuration
APIs.
- Tighten the affected tests, including the Windows delete-pending
memory-file case that was intermittently tripping CI.

## Stack

1. **This PR**: runtime/session/network propagation for active
permission profiles.
2. [#23708](https://github.com/openai/codex/pull/23708): TUI selection
plumbing and guardrail flow.
3. [#21559](https://github.com/openai/codex/pull/21559): profile-aware
`/permissions` menu and custom profile display.

<img width="1296" height="906" alt="image"
src="https://github.com/user-attachments/assets/077fa3a7-80cb-4925-80b1-d2395018d90a"
/>
This commit is contained in:
viyatb-oai
2026-05-20 14:55:21 -07:00
committed by GitHub
Unverified
parent 896ee672cc
commit 40ad7be2b5
20 changed files with 324 additions and 45 deletions
+82 -22
View File
@@ -495,6 +495,39 @@ fn profile_allows_configured_network_proxy(permission_profile: &PermissionProfil
}
}
fn build_network_proxy_spec(
configured_network_proxy_config: NetworkProxyConfig,
network_requirements: Option<Sourced<codex_config::NetworkConstraints>>,
permission_profile: &PermissionProfile,
) -> std::io::Result<Option<NetworkProxySpec>> {
let (network_requirements, network_requirements_source) = match network_requirements {
Some(Sourced { value, source }) => (Some(value), Some(source)),
None => (None, None),
};
let has_network_requirements = network_requirements.is_some();
let network = NetworkProxySpec::from_config_and_constraints(
configured_network_proxy_config,
network_requirements,
permission_profile,
)
.map_err(|err| {
if let Some(source) = network_requirements_source.as_ref() {
std::io::Error::new(
err.kind(),
format!("failed to build managed network proxy from {source}: {err}"),
)
} else {
err
}
})?;
Ok(if has_network_requirements {
Some(network)
} else {
network.enabled().then_some(network)
})
}
/// Configured thread persistence backend.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum ThreadStoreConfig {
@@ -3320,32 +3353,12 @@ impl Config {
let mcp_servers = constrain_mcp_servers(cfg.mcp_servers.clone(), mcp_servers.as_ref())
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("{e}")))?;
let (network_requirements, network_requirements_source) = match network_requirements {
Some(Sourced { value, source }) => (Some(value), Some(source)),
None => (None, None),
};
let has_network_requirements = network_requirements.is_some();
let network_permission_profile = constrained_permission_profile.get().clone();
let network = NetworkProxySpec::from_config_and_constraints(
let network = build_network_proxy_spec(
configured_network_proxy_config,
network_requirements,
&network_permission_profile,
)
.map_err(|err| {
if let Some(source) = network_requirements_source.as_ref() {
std::io::Error::new(
err.kind(),
format!("failed to build managed network proxy from {source}: {err}"),
)
} else {
err
}
})?;
let network = if has_network_requirements {
Some(network)
} else {
network.enabled().then_some(network)
};
)?;
let helper_readable_roots = get_readable_roots_required_for_codex_runtime(
&codex_home,
zsh_path.as_ref(),
@@ -3700,6 +3713,53 @@ impl Config {
.is_some()
}
pub(crate) fn network_proxy_spec_for_active_permission_profile(
&self,
active_permission_profile: &ActivePermissionProfile,
permission_profile: &PermissionProfile,
) -> std::io::Result<Option<NetworkProxySpec>> {
let profile_allows_network_proxy =
profile_allows_configured_network_proxy(permission_profile);
let configured_network_proxy_config = if profile_allows_network_proxy {
let cfg: ConfigToml = self
.config_layer_stack
.effective_config()
.try_into()
.map_err(|err| {
std::io::Error::new(
ErrorKind::InvalidInput,
format!(
"failed to read effective config for selected permission profile: {err}"
),
)
})?;
let mut configured_network_proxy_config = network_proxy_config_for_profile_selection(
cfg.permissions.as_ref(),
active_permission_profile.id.as_str(),
)?;
if self.features.enabled(Feature::NetworkProxy)
&& permission_profile.network_sandbox_policy().is_enabled()
{
if let Some(network_proxy) = network_proxy_toml_config(cfg.features.as_ref()) {
apply_network_proxy_feature_config(
&mut configured_network_proxy_config,
network_proxy,
);
}
configured_network_proxy_config.network.enabled = true;
}
configured_network_proxy_config
} else {
NetworkProxyConfig::default()
};
build_network_proxy_spec(
configured_network_proxy_config,
self.config_layer_stack.requirements().network.clone(),
permission_profile,
)
}
pub fn bundled_skills_enabled(&self) -> bool {
crate::manager::bundled_skills_enabled_from_stack(&self.config_layer_stack)
}
+2 -1
View File
@@ -635,7 +635,8 @@ pub(super) async fn run_guardian_review_session(
schema: serde_json::Value,
external_cancel: Option<CancellationToken>,
) -> (GuardianReviewOutcome, GuardianReviewAnalyticsResult) {
let live_network_config = match session.services.network_proxy.as_ref() {
let network_proxy = session.services.network_proxy.load_full();
let live_network_config = match network_proxy.as_ref() {
Some(network_proxy) => match network_proxy.proxy().current_cfg().await {
Ok(config) => Some(config),
Err(err) => {
+33 -6
View File
@@ -952,9 +952,6 @@ impl Session {
}
async fn refresh_managed_network_proxy_for_current_permission_profile(&self) {
let Some(started_proxy) = self.services.network_proxy.as_ref() else {
return;
};
let Ok(_refresh_guard) = self.managed_network_proxy_refresh_lock.acquire().await else {
error!("managed network proxy refresh semaphore closed");
return;
@@ -968,7 +965,9 @@ impl Session {
.permissions
.network
.as_ref()
.cloned()
else {
self.services.network_proxy.store(None);
return;
};
@@ -991,8 +990,36 @@ impl Session {
spec
}
};
if let Err(err) = spec.apply_to_started_proxy(started_proxy).await {
warn!("failed to refresh managed network proxy for sandbox change: {err}");
if let Some(started_proxy) = self.services.network_proxy.load_full() {
if let Err(err) = spec.apply_to_started_proxy(started_proxy.as_ref()).await {
warn!("failed to refresh managed network proxy for sandbox change: {err}");
}
return;
}
match Self::start_managed_network_proxy(
&spec,
current_exec_policy.as_ref(),
&session_configuration.permission_profile(),
/*network_policy_decider*/ None,
self.services
.managed_network_requirements_configured
.then(|| {
build_blocked_request_observer(Arc::clone(&self.services.network_approval))
}),
self.services.managed_network_requirements_configured,
self.services.network_proxy_audit_metadata.clone(),
)
.await
{
Ok((started_proxy, _session_network_proxy)) => {
self.services
.network_proxy
.store(Some(Arc::new(started_proxy)));
}
Err(err) => {
warn!("failed to start managed network proxy for sandbox change: {err}");
}
}
}
@@ -1886,7 +1913,7 @@ impl Session {
let execpolicy_amendment =
execpolicy_network_rule_amendment(amendment, network_approval_context, &host);
if let Some(started_network_proxy) = self.services.network_proxy.as_ref() {
if let Some(started_network_proxy) = self.services.network_proxy.load_full() {
let proxy = started_network_proxy.proxy();
match amendment.action {
NetworkPolicyRuleAction::Allow => proxy
+32 -2
View File
@@ -1,5 +1,6 @@
use super::input_queue::InputQueue;
use super::*;
use crate::config::ConstraintError;
use crate::goals::GoalRuntimeState;
use crate::skills::SkillError;
use crate::state::ActiveTurn;
@@ -291,6 +292,33 @@ impl SessionConfiguration {
updates.profile_workspace_roots.clone().unwrap_or_default(),
Some(&current_file_system_sandbox_policy),
)?;
if let Some(active_permission_profile) = next_configuration.active_permission_profile()
{
let mut config = (*next_configuration.original_config_do_not_use).clone();
let permission_profile = next_configuration.permission_profile();
config.permissions.network = config
.network_proxy_spec_for_active_permission_profile(
&active_permission_profile,
&permission_profile,
)
.map_err(|err| ConstraintError::InvalidValue {
field_name: "default_permissions",
candidate: active_permission_profile.id.clone(),
allowed: format!(
"configured permission profile with valid network policy ({err})"
),
requirement_source: codex_config::RequirementSource::Unknown,
})?;
config
.permissions
.set_permission_profile_from_session_snapshot(
PermissionProfileSnapshot::active(
permission_profile,
active_permission_profile,
),
)?;
next_configuration.original_config_do_not_use = Arc::new(config);
}
} else if let Some(sandbox_policy) = updates.sandbox_policy.clone() {
let file_system_sandbox_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
@@ -885,7 +913,7 @@ impl Session {
network_policy_decider.as_ref().map(Arc::clone),
blocked_request_observer.as_ref().map(Arc::clone),
managed_network_requirements_configured,
network_proxy_audit_metadata,
network_proxy_audit_metadata.clone(),
)
.instrument(info_span!(
"session_init.network_proxy",
@@ -977,7 +1005,9 @@ impl Session {
session_extension_data,
thread_extension_data,
agent_control,
network_proxy,
network_proxy: arc_swap::ArcSwapOption::from(network_proxy.map(Arc::new)),
network_proxy_audit_metadata,
managed_network_requirements_configured,
network_approval: Arc::clone(&network_approval),
state_db: state_db_ctx.clone(),
live_thread: live_thread_init.as_ref().cloned(),
+126 -5
View File
@@ -1,6 +1,7 @@
use super::turn_context::TurnEnvironment;
use super::*;
use crate::config::ConfigBuilder;
use crate::config::ConfigOverrides;
use crate::config::test_config;
use crate::context::ContextualUserFragment;
use crate::context::TurnAborted;
@@ -80,6 +81,11 @@ use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::McpElicitationSchema;
use codex_config::config_toml::ConfigToml;
use codex_config::config_toml::ProjectConfig;
use codex_config::permissions_toml::FilesystemPermissionToml;
use codex_config::permissions_toml::FilesystemPermissionsToml;
use codex_config::permissions_toml::NetworkToml;
use codex_config::permissions_toml::PermissionProfileToml;
use codex_config::permissions_toml::PermissionsToml;
use codex_execpolicy::Decision;
use codex_execpolicy::NetworkRuleProtocol;
use codex_execpolicy::Policy;
@@ -818,7 +824,7 @@ async fn managed_network_proxy_decider_survives_full_access_start() -> anyhow::R
#[tokio::test]
async fn new_turn_refreshes_managed_network_proxy_for_sandbox_change() -> anyhow::Result<()> {
let (mut session, _turn_context) = make_session_and_context().await;
let (session, _turn_context) = make_session_and_context().await;
let initial_permission_profile = PermissionProfile::workspace_write();
let mut network_config = NetworkProxyConfig::default();
@@ -873,7 +879,10 @@ async fn new_turn_refreshes_managed_network_proxy_for_sandbox_change() -> anyhow
.set_permission_profile_for_tests(initial_permission_profile)
.expect("test setup should allow permission profile");
}
session.services.network_proxy = Some(started_proxy);
session
.services
.network_proxy
.store(Some(Arc::new(started_proxy)));
session
.new_turn_with_sub_id(
@@ -888,7 +897,7 @@ async fn new_turn_refreshes_managed_network_proxy_for_sandbox_change() -> anyhow
let started_proxy = session
.services
.network_proxy
.as_ref()
.load_full()
.expect("managed network proxy should be present");
assert_eq!(
started_proxy
@@ -3805,6 +3814,114 @@ async fn session_configuration_apply_retargets_implicit_workspace_root_on_cwd_up
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd.as_path()));
}
#[tokio::test]
async fn active_profile_update_rebuilds_network_proxy_config() -> std::io::Result<()> {
let codex_home = tempfile::tempdir().expect("create codex home");
let cwd = tempfile::tempdir().expect("create cwd");
let permissions = PermissionsToml {
entries: std::collections::BTreeMap::from([
(
"locked-down".to_string(),
PermissionProfileToml {
description: None,
extends: None,
workspace_roots: None,
filesystem: Some(FilesystemPermissionsToml {
glob_scan_max_depth: None,
entries: std::collections::BTreeMap::from([(
":minimal".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
)]),
}),
network: None,
},
),
(
"web-enabled".to_string(),
PermissionProfileToml {
description: None,
extends: None,
workspace_roots: None,
filesystem: Some(FilesystemPermissionsToml {
glob_scan_max_depth: None,
entries: std::collections::BTreeMap::from([(
":minimal".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
)]),
}),
network: Some(NetworkToml {
enabled: Some(true),
proxy_url: Some("http://127.0.0.1:43128".to_string()),
enable_socks5: Some(false),
..Default::default()
}),
},
),
]),
};
let base_config = ConfigToml {
features: Some(toml::from_str("network_proxy = true").expect("valid features")),
default_permissions: Some("locked-down".to_string()),
permissions: Some(permissions),
..Default::default()
};
std::fs::write(
codex_home.path().join(codex_config::CONFIG_TOML_FILE),
toml::to_string(&base_config).expect("serialize config"),
)?;
let locked_config = Arc::new(
ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.harness_overrides(ConfigOverrides {
cwd: Some(cwd.path().to_path_buf()),
..Default::default()
})
.build()
.await?,
);
assert_ne!(
locked_config
.permissions
.network
.as_ref()
.map(crate::config::NetworkProxySpec::proxy_host_and_port)
.as_deref(),
Some("127.0.0.1:43128")
);
let selected_config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.harness_overrides(ConfigOverrides {
cwd: Some(cwd.path().to_path_buf()),
default_permissions: Some("web-enabled".to_string()),
..Default::default()
})
.build()
.await?;
let mut session_configuration = make_session_configuration_for_tests().await;
session_configuration.permission_profile_state =
locked_config.permissions.permission_profile_state().clone();
session_configuration.original_config_do_not_use = Arc::clone(&locked_config);
let updated = session_configuration
.apply(&SessionSettingsUpdate {
permission_profile: Some(selected_config.permissions.permission_profile().clone()),
active_permission_profile: selected_config.permissions.active_permission_profile(),
..Default::default()
})
.expect("active profile update should apply");
let network = updated
.original_config_do_not_use
.permissions
.network
.as_ref()
.expect("selected profile proxy should become the session proxy config");
assert_eq!(network.proxy_host_and_port(), "127.0.0.1:43128");
assert!(!network.socks_enabled());
Ok(())
}
#[cfg_attr(windows, ignore)]
#[tokio::test]
async fn new_default_turn_uses_config_aware_skills_for_role_overrides() {
@@ -4359,7 +4476,9 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
),
thread_extension_data: codex_extension_api::ExtensionData::new(thread_id.to_string()),
agent_control,
network_proxy: None,
network_proxy: arc_swap::ArcSwapOption::from(None),
network_proxy_audit_metadata: crate::config::NetworkProxyAuditMetadata::default(),
managed_network_requirements_configured: false,
network_approval: Arc::clone(&network_approval),
state_db: None,
live_thread: None,
@@ -6186,7 +6305,9 @@ where
),
thread_extension_data: codex_extension_api::ExtensionData::new(thread_id.to_string()),
agent_control,
network_proxy: None,
network_proxy: arc_swap::ArcSwapOption::from(None),
network_proxy_audit_metadata: crate::config::NetworkProxyAuditMetadata::default(),
managed_network_requirements_configured: false,
network_approval: Arc::clone(&network_approval),
state_db: state_db.clone(),
live_thread: None,
@@ -704,6 +704,7 @@ impl Session {
&self.services.models_manager,
self.services
.network_proxy
.load_full()
.as_ref()
.and_then(|started_proxy| {
Self::managed_network_proxy_active_for_permission_profile(
+5 -1
View File
@@ -5,6 +5,7 @@ use crate::SkillsManager;
use crate::agent::AgentControl;
use crate::attestation::AttestationProvider;
use crate::client::ModelClient;
use crate::config::NetworkProxyAuditMetadata;
use crate::config::StartedNetworkProxy;
use crate::exec_policy::ExecPolicyManager;
use crate::guardian::GuardianRejection;
@@ -15,6 +16,7 @@ use crate::tools::network_approval::NetworkApprovalService;
use crate::tools::sandboxing::ApprovalStore;
use crate::unified_exec::UnifiedExecProcessManager;
use arc_swap::ArcSwap;
use arc_swap::ArcSwapOption;
use codex_analytics::AnalyticsEventsClient;
use codex_core_plugins::PluginsManager;
use codex_exec_server::EnvironmentManager;
@@ -65,7 +67,9 @@ pub(crate) struct SessionServices {
pub(crate) session_extension_data: ExtensionData,
pub(crate) thread_extension_data: ExtensionData,
pub(crate) agent_control: AgentControl,
pub(crate) network_proxy: Option<StartedNetworkProxy>,
pub(crate) network_proxy: ArcSwapOption<StartedNetworkProxy>,
pub(crate) network_proxy_audit_metadata: NetworkProxyAuditMetadata,
pub(crate) managed_network_requirements_configured: bool,
pub(crate) network_approval: Arc<NetworkApprovalService>,
pub(crate) state_db: Option<StateDbHandle>,
pub(crate) live_thread: Option<LiveThread>,
+2 -1
View File
@@ -655,7 +655,8 @@ impl Session {
"false"
},
);
let network_proxy_active = match self.services.network_proxy.as_ref() {
let network_proxy = self.services.network_proxy.load_full();
let network_proxy_active = match network_proxy.as_ref() {
Some(started_network_proxy) => {
match started_network_proxy.proxy().current_cfg().await {
Ok(config) => config.network.enabled,
@@ -360,6 +360,7 @@ impl App {
/*cwd*/ None,
approval_policy_override,
approvals_reviewer_override,
permission_profile_override,
active_permission_profile_override,
/*windows_sandbox_level*/ None,
/*model*/ None,
@@ -387,6 +388,7 @@ impl App {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
#[cfg(target_os = "windows")]
Some(windows_sandbox_level),
+2
View File
@@ -1125,6 +1125,7 @@ impl App {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
#[cfg(target_os = "windows")]
Some(windows_sandbox_level),
@@ -1150,6 +1151,7 @@ impl App {
/*cwd*/ None,
Some(AskForApproval::from(preset.approval)),
Some(self.config.approvals_reviewer),
Some(preset.permission_profile.clone()),
Some(preset.active_permission_profile.clone()),
#[cfg(target_os = "windows")]
Some(windows_sandbox_level),
+7
View File
@@ -1695,6 +1695,7 @@ async fn update_feature_flags_enabling_guardian_selects_auto_review() -> Result<
cwd: None,
approval_policy: Some(auto_review.approval_policy),
approvals_reviewer: Some(auto_review.approvals_reviewer),
permission_profile: Some(auto_review.permission_profile()),
active_permission_profile: Some(auto_review.active_permission_profile.clone()),
windows_sandbox_level: None,
model: None,
@@ -1787,6 +1788,7 @@ async fn update_feature_flags_disabling_guardian_clears_review_policy_and_restor
cwd: None,
approval_policy: None,
approvals_reviewer: Some(ApprovalsReviewer::User),
permission_profile: None,
active_permission_profile: None,
windows_sandbox_level: None,
model: None,
@@ -1865,6 +1867,7 @@ async fn update_feature_flags_enabling_guardian_overrides_explicit_manual_review
cwd: None,
approval_policy: Some(auto_review.approval_policy),
approvals_reviewer: Some(auto_review.approvals_reviewer),
permission_profile: Some(auto_review.permission_profile()),
active_permission_profile: Some(auto_review.active_permission_profile.clone()),
windows_sandbox_level: None,
model: None,
@@ -1922,6 +1925,7 @@ async fn update_feature_flags_disabling_guardian_clears_manual_review_policy_wit
cwd: None,
approval_policy: None,
approvals_reviewer: Some(ApprovalsReviewer::User),
permission_profile: None,
active_permission_profile: None,
windows_sandbox_level: None,
model: None,
@@ -1981,6 +1985,7 @@ async fn update_feature_flags_enabling_guardian_in_profile_sets_profile_auto_rev
cwd: None,
approval_policy: Some(auto_review.approval_policy),
approvals_reviewer: Some(auto_review.approvals_reviewer),
permission_profile: Some(auto_review.permission_profile()),
active_permission_profile: Some(auto_review.active_permission_profile.clone()),
windows_sandbox_level: None,
model: None,
@@ -2068,6 +2073,7 @@ guardian_approval = true
cwd: None,
approval_policy: None,
approvals_reviewer: Some(ApprovalsReviewer::User),
permission_profile: None,
active_permission_profile: None,
windows_sandbox_level: None,
model: None,
@@ -5276,6 +5282,7 @@ async fn override_turn_context_sends_thread_settings_update() {
/*cwd*/ None,
Some(AskForApproval::OnRequest),
Some(ApprovalsReviewer::AutoReview),
/*permission_profile*/ None,
Some(ActivePermissionProfile::new(
codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
)),
+1
View File
@@ -101,6 +101,7 @@ impl App {
cwd,
approval_policy,
approvals_reviewer,
permission_profile: _,
active_permission_profile,
windows_sandbox_level: _,
model,
+4
View File
@@ -17,6 +17,7 @@ use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::ActivePermissionProfile;
use codex_protocol::models::PermissionProfile;
use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig;
use codex_protocol::request_permissions::RequestPermissionsResponse;
use serde::Serialize;
@@ -54,6 +55,7 @@ pub(crate) enum AppCommand {
cwd: Option<PathBuf>,
approval_policy: Option<AskForApproval>,
approvals_reviewer: Option<ApprovalsReviewer>,
permission_profile: Option<PermissionProfile>,
active_permission_profile: Option<ActivePermissionProfile>,
windows_sandbox_level: Option<WindowsSandboxLevel>,
model: Option<String>,
@@ -172,6 +174,7 @@ impl AppCommand {
cwd: Option<PathBuf>,
approval_policy: Option<AskForApproval>,
approvals_reviewer: Option<ApprovalsReviewer>,
permission_profile: Option<PermissionProfile>,
active_permission_profile: Option<ActivePermissionProfile>,
windows_sandbox_level: Option<WindowsSandboxLevel>,
model: Option<String>,
@@ -185,6 +188,7 @@ impl AppCommand {
cwd,
approval_policy,
approvals_reviewer,
permission_profile,
active_permission_profile,
windows_sandbox_level,
model,
@@ -124,6 +124,7 @@ impl ChatWidget {
} else {
Self::approval_preset_actions(
preset_approval,
preset.permission_profile.clone(),
preset.active_permission_profile.clone(),
base_name.clone(),
ApprovalsReviewer::User,
@@ -134,6 +135,7 @@ impl ChatWidget {
{
Self::approval_preset_actions(
preset_approval,
preset.permission_profile.clone(),
preset.active_permission_profile.clone(),
base_name.clone(),
ApprovalsReviewer::User,
@@ -142,6 +144,7 @@ impl ChatWidget {
} else {
Self::approval_preset_actions(
preset_approval,
preset.permission_profile.clone(),
preset.active_permission_profile.clone(),
base_name.clone(),
ApprovalsReviewer::User,
@@ -180,6 +183,7 @@ impl ChatWidget {
),
actions: Self::approval_preset_actions(
preset_approval,
preset.permission_profile.clone(),
preset.active_permission_profile.clone(),
"Auto-review".to_string(),
ApprovalsReviewer::AutoReview,
@@ -308,6 +312,7 @@ impl ChatWidget {
pub(super) fn approval_preset_actions(
approval: AskForApproval,
permission_profile: PermissionProfile,
active_permission_profile: ActivePermissionProfile,
label: String,
approvals_reviewer: ApprovalsReviewer,
@@ -317,6 +322,7 @@ impl ChatWidget {
/*cwd*/ None,
Some(approval),
Some(approvals_reviewer),
Some(permission_profile.clone()),
Some(active_permission_profile.clone()),
/*windows_sandbox_level*/ None,
/*model*/ None,
@@ -402,6 +408,7 @@ impl ChatWidget {
let mut accept_actions = Self::approval_preset_actions(
approval,
preset.permission_profile.clone(),
preset.active_permission_profile.clone(),
selected_name.clone(),
ApprovalsReviewer::User,
@@ -412,6 +419,7 @@ impl ChatWidget {
let mut accept_and_remember_actions = Self::approval_preset_actions(
approval,
preset.permission_profile,
preset.active_permission_profile,
selected_name,
ApprovalsReviewer::User,
@@ -308,6 +308,7 @@ impl ChatWidget {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
/*windows_sandbox_level*/ None,
Some(switch_model_for_events.clone()),
@@ -107,6 +107,7 @@ impl ChatWidget {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
/*windows_sandbox_level*/ None,
/*model*/ None,
+1
View File
@@ -734,6 +734,7 @@ impl ChatWidget {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
/*windows_sandbox_level*/ None,
/*model*/ None,
@@ -53,6 +53,7 @@ impl ChatWidget {
/*cwd*/ None,
/*approval_policy*/ None,
/*approvals_reviewer*/ None,
/*permission_profile*/ None,
/*active_permission_profile*/ None,
/*windows_sandbox_level*/ None,
/*model*/ None,
@@ -743,6 +743,7 @@ async fn permissions_selection_sends_approvals_reviewer_in_override_turn_context
cwd: None,
approval_policy: Some(AskForApproval::OnRequest),
approvals_reviewer: Some(ApprovalsReviewer::AutoReview),
permission_profile: Some(PermissionProfile::workspace_write()),
active_permission_profile: Some(ActivePermissionProfile::new(
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
)),
@@ -42,12 +42,13 @@ impl ChatWidget {
extra_count: usize,
failed_scan: bool,
) {
let (approval, active_permission_profile) = match &preset {
let (approval, permission_profile, active_permission_profile) = match &preset {
Some(p) => (
Some(AskForApproval::from(p.approval)),
Some(p.permission_profile.clone()),
Some(p.active_permission_profile.clone()),
),
None => (None, None),
None => (None, None, None),
};
let mut header_children: Vec<Box<dyn Renderable>> = Vec::new();
let describe_profile = |profile: &PermissionProfile| {
@@ -110,11 +111,14 @@ impl ChatWidget {
tx.send(AppEvent::SkipNextWorldWritableScan);
}));
}
if let (Some(approval), Some(active_permission_profile)) =
(approval, active_permission_profile.clone())
{
if let (Some(approval), Some(permission_profile), Some(active_permission_profile)) = (
approval,
permission_profile.clone(),
active_permission_profile.clone(),
) {
accept_actions.extend(Self::approval_preset_actions(
approval,
permission_profile,
active_permission_profile,
mode_label.to_string(),
ApprovalsReviewer::User,
@@ -126,11 +130,12 @@ impl ChatWidget {
tx.send(AppEvent::UpdateWorldWritableWarningAcknowledged(true));
tx.send(AppEvent::PersistWorldWritableWarningAcknowledged);
}));
if let (Some(approval), Some(active_permission_profile)) =
(approval, active_permission_profile)
if let (Some(approval), Some(permission_profile), Some(active_permission_profile)) =
(approval, permission_profile, active_permission_profile)
{
accept_and_remember_actions.extend(Self::approval_preset_actions(
approval,
permission_profile,
active_permission_profile,
mode_label.to_string(),
ApprovalsReviewer::User,