codex: always confirm admin-required full access

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charles Cunningham
2026-03-25 12:09:29 -07:00
co-authored by Codex
parent 77cebdcb15
commit cbc31b9a2e
6 changed files with 74 additions and 70 deletions
+28 -27
View File
@@ -7139,11 +7139,12 @@ impl ChatWidget {
.clone()
.or_else(|| guardian_disabled_reason(false));
let requires_confirmation = preset.id == "full-access"
&& !self
.config
.notices
.hide_full_access_warning
.unwrap_or(false);
&& (self.config.require_full_access_justification
|| !self
.config
.notices
.hide_full_access_warning
.unwrap_or(false));
let default_actions: Vec<SelectionAction> = if requires_confirmation {
let preset_clone = preset.clone();
vec![Box::new(move |tx| {
@@ -7502,10 +7503,6 @@ impl ChatWidget {
/*persist_warning_acknowledged*/ false,
);
let accept_and_remember_actions = self.full_access_preset_actions(
preset, /*acknowledge_warning*/ true, /*persist_warning_acknowledged*/ true,
);
let deny_actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
if return_to_permissions {
tx.send(AppEvent::OpenPermissionsPopup);
@@ -7514,29 +7511,33 @@ impl ChatWidget {
}
})];
let items = vec![
SelectionItem {
name: "Yes, continue anyway".to_string(),
description: Some("Apply full access for this session".to_string()),
actions: accept_actions,
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
let mut items = vec![SelectionItem {
name: "Yes, continue anyway".to_string(),
description: Some("Apply full access for this session".to_string()),
actions: accept_actions,
dismiss_on_select: true,
..Default::default()
}];
if !self.config.require_full_access_justification {
let accept_and_remember_actions = self.full_access_preset_actions(
preset, /*acknowledge_warning*/ true,
/*persist_warning_acknowledged*/ true,
);
items.push(SelectionItem {
name: "Yes, and don't ask again".to_string(),
description: Some("Enable full access and remember this choice".to_string()),
actions: accept_and_remember_actions,
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
name: "Cancel".to_string(),
description: Some("Go back without enabling full access".to_string()),
actions: deny_actions,
dismiss_on_select: true,
..Default::default()
},
];
});
}
items.push(SelectionItem {
name: "Cancel".to_string(),
description: Some("Go back without enabling full access".to_string()),
actions: deny_actions,
dismiss_on_select: true,
..Default::default()
});
self.bottom_pane.show_selection_view(SelectionViewParams {
footer_hint: Some(standard_popup_hint_line()),
@@ -9,8 +9,7 @@ expression: popup
leaks, or unexpected behavior.
Your admin requires a written justification before full access is enabled.
› 1. Yes, continue anyway Apply full access for this session
2. Yes, and don't ask again Enable full access and remember this choice
3. Cancel Go back without enabling full access
› 1. Yes, continue anyway Apply full access for this session
2. Cancel Go back without enabling full access
Press enter to confirm or esc to go back
+7 -5
View File
@@ -159,11 +159,13 @@ use toml::Value as TomlValue;
async fn test_config() -> Config {
// Use base defaults to avoid depending on host state.
let codex_home = std::env::temp_dir();
ConfigBuilder::default()
let mut config = ConfigBuilder::default()
.codex_home(codex_home.clone())
.build()
.await
.expect("config")
.expect("config");
config.require_full_access_justification = false;
config
}
fn invalid_value(candidate: impl Into<String>, allowed: impl Into<String>) -> ConstraintError {
@@ -9972,7 +9974,7 @@ async fn permissions_full_access_history_cell_emitted_only_after_confirmation()
}
#[tokio::test]
async fn permissions_full_access_requires_justification_when_warning_hidden() {
async fn permissions_full_access_still_confirms_when_warning_hidden_but_justification_required() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
#[cfg(target_os = "windows")]
{
@@ -9990,8 +9992,8 @@ async fn permissions_full_access_requires_justification_when_warning_hidden() {
assert!(
events
.iter()
.any(|event| matches!(event, AppEvent::OpenFullAccessJustificationPrompt { .. })),
"expected full access selection to request a justification prompt: {events:?}"
.any(|event| matches!(event, AppEvent::OpenFullAccessConfirmation { .. })),
"expected full access selection to request a confirmation popup: {events:?}"
);
assert!(
!events
+28 -27
View File
@@ -8319,11 +8319,12 @@ impl ChatWidget {
.clone()
.or_else(|| guardian_disabled_reason(false));
let requires_confirmation = preset.id == "full-access"
&& !self
.config
.notices
.hide_full_access_warning
.unwrap_or(false);
&& (self.config.require_full_access_justification
|| !self
.config
.notices
.hide_full_access_warning
.unwrap_or(false));
let default_actions: Vec<SelectionAction> = if requires_confirmation {
let preset_clone = preset.clone();
vec![Box::new(move |tx| {
@@ -8685,10 +8686,6 @@ impl ChatWidget {
/*persist_warning_acknowledged*/ false,
);
let accept_and_remember_actions = self.full_access_preset_actions(
preset, /*acknowledge_warning*/ true, /*persist_warning_acknowledged*/ true,
);
let deny_actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
if return_to_permissions {
tx.send(AppEvent::OpenPermissionsPopup);
@@ -8697,29 +8694,33 @@ impl ChatWidget {
}
})];
let items = vec![
SelectionItem {
name: "Yes, continue anyway".to_string(),
description: Some("Apply full access for this session".to_string()),
actions: accept_actions,
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
let mut items = vec![SelectionItem {
name: "Yes, continue anyway".to_string(),
description: Some("Apply full access for this session".to_string()),
actions: accept_actions,
dismiss_on_select: true,
..Default::default()
}];
if !self.config.require_full_access_justification {
let accept_and_remember_actions = self.full_access_preset_actions(
preset, /*acknowledge_warning*/ true,
/*persist_warning_acknowledged*/ true,
);
items.push(SelectionItem {
name: "Yes, and don't ask again".to_string(),
description: Some("Enable full access and remember this choice".to_string()),
actions: accept_and_remember_actions,
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
name: "Cancel".to_string(),
description: Some("Go back without enabling full access".to_string()),
actions: deny_actions,
dismiss_on_select: true,
..Default::default()
},
];
});
}
items.push(SelectionItem {
name: "Cancel".to_string(),
description: Some("Go back without enabling full access".to_string()),
actions: deny_actions,
dismiss_on_select: true,
..Default::default()
});
self.bottom_pane.show_selection_view(SelectionViewParams {
footer_hint: Some(standard_popup_hint_line()),
@@ -9,8 +9,7 @@ expression: popup
leaks, or unexpected behavior.
Your admin requires a written justification before full access is enabled.
› 1. Yes, continue anyway Apply full access for this session
2. Yes, and don't ask again Enable full access and remember this choice
3. Cancel Go back without enabling full access
› 1. Yes, continue anyway Apply full access for this session
2. Cancel Go back without enabling full access
Press enter to confirm or esc to go back
@@ -183,11 +183,13 @@ use toml::Value as TomlValue;
async fn test_config() -> Config {
// Use base defaults to avoid depending on host state.
let codex_home = std::env::temp_dir();
ConfigBuilder::default()
let mut config = ConfigBuilder::default()
.codex_home(codex_home.clone())
.build()
.await
.expect("config")
.expect("config");
config.require_full_access_justification = false;
config
}
fn invalid_value(candidate: impl Into<String>, allowed: impl Into<String>) -> ConstraintError {
@@ -10513,7 +10515,7 @@ async fn permissions_full_access_history_cell_emitted_only_after_confirmation()
}
#[tokio::test]
async fn permissions_full_access_requires_justification_when_warning_hidden() {
async fn permissions_full_access_still_confirms_when_warning_hidden_but_justification_required() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
#[cfg(target_os = "windows")]
{
@@ -10533,8 +10535,8 @@ async fn permissions_full_access_requires_justification_when_warning_hidden() {
assert!(
events
.iter()
.any(|event| matches!(event, AppEvent::OpenFullAccessJustificationPrompt { .. })),
"expected full access selection to request a justification prompt: {events:?}"
.any(|event| matches!(event, AppEvent::OpenFullAccessConfirmation { .. })),
"expected full access selection to request a confirmation popup: {events:?}"
);
assert!(
!events