[codex] Fix bridge restart approval floor (#2978)

* fix bridge restart approval floor

* address bridge permission review cleanup
This commit is contained in:
Henry Park
2026-04-27 14:14:07 -07:00
committed by GitHub
parent 91c4c7ca7b
commit f11a49be0b
2 changed files with 37 additions and 16 deletions

View File

@@ -30,7 +30,9 @@ use crate::bridge::action_projector::ActionProjector;
use crate::bridge::capability_projector::CapabilityProjector;
use crate::bridge::router::synthetic_action_call_id;
use crate::bridge::sandbox::{InterceptOutcome, maybe_intercept};
use crate::bridge::tool_permissions::{ToolPermissionResolution, ToolPermissionSnapshot};
use crate::bridge::tool_permissions::{
ToolPermissionResolution, ToolPermissionSnapshot, canonical_tool_name,
};
use crate::context::JobContext;
use crate::extensions::InstalledExtension;
use crate::extensions::naming::extension_name_candidates;
@@ -317,15 +319,29 @@ impl EffectBridgeAdapter {
}
fn apply_user_permission_override(
lookup_name: &str,
base_requirement: ApprovalRequirement,
explicit_user_permission: Option<PermissionState>,
user_permission: ToolPermissionResolution,
) -> ApprovalRequirement {
match explicit_user_permission {
Some(PermissionState::AskEachTime) => ApprovalRequirement::Always,
if matches!(user_permission.explicit, Some(PermissionState::AskEachTime)) {
return ApprovalRequirement::Always;
}
match (base_requirement, user_permission.configured) {
(ApprovalRequirement::Never, Some(PermissionState::AskEachTime))
if Self::enforce_static_ask_floor_for_base_never_tool(lookup_name) =>
{
ApprovalRequirement::Always
}
_ => base_requirement,
}
}
fn enforce_static_ask_floor_for_base_never_tool(lookup_name: &str) -> bool {
// Other base-Never bridge tools manage auth/install gates internally.
// Restart's command-level confirmation does not cover direct v2 calls.
canonical_tool_name(lookup_name) == "restart"
}
fn ensure_tool_not_disabled(
action_name: &str,
user_permission: ToolPermissionResolution,
@@ -356,7 +372,7 @@ impl EffectBridgeAdapter {
} else {
tool.requires_approval(parameters)
};
Self::apply_user_permission_override(base_requirement, user_permission.explicit)
Self::apply_user_permission_override(lookup_name, base_requirement, user_permission)
}
async fn enforce_tool_approval(

View File

@@ -2,12 +2,13 @@ use std::collections::HashMap;
use crate::settings::Settings;
use crate::tools::ToolRegistry;
use crate::tools::permissions::{PermissionState, effective_permission};
use crate::tools::permissions::{PermissionState, TOOL_RISK_DEFAULTS};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ToolPermissionResolution {
pub(crate) effective: PermissionState,
pub(crate) explicit: Option<PermissionState>,
pub(crate) configured: Option<PermissionState>,
}
#[derive(Clone, Default)]
@@ -37,25 +38,29 @@ impl ToolPermissionSnapshot {
}
pub(crate) fn resolve_permission(&self, tool_name: &str) -> ToolPermissionResolution {
let explicit = self.explicit_permission(tool_name);
let effective = explicit.unwrap_or_else(|| {
effective_permission(&canonical_tool_name(tool_name), &self.overrides)
});
let canonical = canonical_tool_name(tool_name);
let hyphenated = canonical.replace('_', "-");
let explicit = self.explicit_permission_with_names(tool_name, &canonical, &hyphenated);
let configured = explicit.or_else(|| TOOL_RISK_DEFAULTS.get(canonical.as_str()).copied());
let effective = configured.unwrap_or(PermissionState::AskEachTime);
ToolPermissionResolution {
effective,
explicit,
configured,
}
}
pub(crate) fn explicit_permission(&self, tool_name: &str) -> Option<PermissionState> {
let canonical = canonical_tool_name(tool_name);
let hyphenated = canonical.replace('_', "-");
fn explicit_permission_with_names(
&self,
tool_name: &str,
canonical: &str,
hyphenated: &str,
) -> Option<PermissionState> {
self.overrides
.get(tool_name)
.copied()
.or_else(|| self.overrides.get(&canonical).copied())
.or_else(|| self.overrides.get(&hyphenated).copied())
.or_else(|| self.overrides.get(canonical).copied())
.or_else(|| self.overrides.get(hyphenated).copied())
}
}