mirror of
https://github.com/openai/codex.git
synced 2026-04-24 22:54:54 +00:00
bypass sandbox for policy approved commands (#7110)
allowing cmds greenlit by execpolicy to bypass sandbox + minor refactor for a world where we have execpolicy rules with specific sandbox requirements
This commit is contained in:
@@ -107,7 +107,9 @@ fn evaluate_with_policy(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Decision::Allow => Some(ApprovalRequirement::Skip),
|
Decision::Allow => Some(ApprovalRequirement::Skip {
|
||||||
|
bypass_sandbox: true,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Evaluation::NoMatch { .. } => None,
|
Evaluation::NoMatch { .. } => None,
|
||||||
}
|
}
|
||||||
@@ -132,7 +134,9 @@ pub(crate) fn create_approval_requirement_for_command(
|
|||||||
) {
|
) {
|
||||||
ApprovalRequirement::NeedsApproval { reason: None }
|
ApprovalRequirement::NeedsApproval { reason: None }
|
||||||
} else {
|
} else {
|
||||||
ApprovalRequirement::Skip
|
ApprovalRequirement::Skip {
|
||||||
|
bypass_sandbox: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use crate::tools::sandboxing::ApprovalCtx;
|
|||||||
use crate::tools::sandboxing::ApprovalRequirement;
|
use crate::tools::sandboxing::ApprovalRequirement;
|
||||||
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
||||||
use crate::tools::sandboxing::SandboxAttempt;
|
use crate::tools::sandboxing::SandboxAttempt;
|
||||||
|
use crate::tools::sandboxing::SandboxOverride;
|
||||||
use crate::tools::sandboxing::ToolCtx;
|
use crate::tools::sandboxing::ToolCtx;
|
||||||
use crate::tools::sandboxing::ToolError;
|
use crate::tools::sandboxing::ToolError;
|
||||||
use crate::tools::sandboxing::ToolRuntime;
|
use crate::tools::sandboxing::ToolRuntime;
|
||||||
@@ -57,7 +58,7 @@ impl ToolOrchestrator {
|
|||||||
default_approval_requirement(approval_policy, &turn_ctx.sandbox_policy)
|
default_approval_requirement(approval_policy, &turn_ctx.sandbox_policy)
|
||||||
});
|
});
|
||||||
match requirement {
|
match requirement {
|
||||||
ApprovalRequirement::Skip => {
|
ApprovalRequirement::Skip { .. } => {
|
||||||
otel.tool_decision(otel_tn, otel_ci, ReviewDecision::Approved, otel_cfg);
|
otel.tool_decision(otel_tn, otel_ci, ReviewDecision::Approved, otel_cfg);
|
||||||
}
|
}
|
||||||
ApprovalRequirement::Forbidden { reason } => {
|
ApprovalRequirement::Forbidden { reason } => {
|
||||||
@@ -100,12 +101,13 @@ impl ToolOrchestrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2) First attempt under the selected sandbox.
|
// 2) First attempt under the selected sandbox.
|
||||||
let mut initial_sandbox = self
|
let initial_sandbox = match tool.sandbox_mode_for_first_attempt(req) {
|
||||||
.sandbox
|
SandboxOverride::BypassSandboxFirstAttempt => crate::exec::SandboxType::None,
|
||||||
.select_initial(&turn_ctx.sandbox_policy, tool.sandbox_preference());
|
SandboxOverride::NoOverride => self
|
||||||
if tool.wants_escalated_first_attempt(req) {
|
.sandbox
|
||||||
initial_sandbox = crate::exec::SandboxType::None;
|
.select_initial(&turn_ctx.sandbox_policy, tool.sandbox_preference()),
|
||||||
}
|
};
|
||||||
|
|
||||||
// Platform-specific flag gating is handled by SandboxManager::select_initial
|
// Platform-specific flag gating is handled by SandboxManager::select_initial
|
||||||
// via crate::safety::get_platform_sandbox().
|
// via crate::safety::get_platform_sandbox().
|
||||||
let initial_attempt = SandboxAttempt {
|
let initial_attempt = SandboxAttempt {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use crate::tools::sandboxing::ApprovalCtx;
|
|||||||
use crate::tools::sandboxing::ApprovalRequirement;
|
use crate::tools::sandboxing::ApprovalRequirement;
|
||||||
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
||||||
use crate::tools::sandboxing::SandboxAttempt;
|
use crate::tools::sandboxing::SandboxAttempt;
|
||||||
|
use crate::tools::sandboxing::SandboxOverride;
|
||||||
use crate::tools::sandboxing::SandboxRetryData;
|
use crate::tools::sandboxing::SandboxRetryData;
|
||||||
use crate::tools::sandboxing::Sandboxable;
|
use crate::tools::sandboxing::Sandboxable;
|
||||||
use crate::tools::sandboxing::SandboxablePreference;
|
use crate::tools::sandboxing::SandboxablePreference;
|
||||||
@@ -117,8 +118,19 @@ impl Approvable<ShellRequest> for ShellRuntime {
|
|||||||
Some(req.approval_requirement.clone())
|
Some(req.approval_requirement.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wants_escalated_first_attempt(&self, req: &ShellRequest) -> bool {
|
fn sandbox_mode_for_first_attempt(&self, req: &ShellRequest) -> SandboxOverride {
|
||||||
req.with_escalated_permissions.unwrap_or(false)
|
if req.with_escalated_permissions.unwrap_or(false)
|
||||||
|
|| matches!(
|
||||||
|
req.approval_requirement,
|
||||||
|
ApprovalRequirement::Skip {
|
||||||
|
bypass_sandbox: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SandboxOverride::BypassSandboxFirstAttempt
|
||||||
|
} else {
|
||||||
|
SandboxOverride::NoOverride
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use crate::tools::sandboxing::ApprovalCtx;
|
|||||||
use crate::tools::sandboxing::ApprovalRequirement;
|
use crate::tools::sandboxing::ApprovalRequirement;
|
||||||
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
use crate::tools::sandboxing::ProvidesSandboxRetryData;
|
||||||
use crate::tools::sandboxing::SandboxAttempt;
|
use crate::tools::sandboxing::SandboxAttempt;
|
||||||
|
use crate::tools::sandboxing::SandboxOverride;
|
||||||
use crate::tools::sandboxing::SandboxRetryData;
|
use crate::tools::sandboxing::SandboxRetryData;
|
||||||
use crate::tools::sandboxing::Sandboxable;
|
use crate::tools::sandboxing::Sandboxable;
|
||||||
use crate::tools::sandboxing::SandboxablePreference;
|
use crate::tools::sandboxing::SandboxablePreference;
|
||||||
@@ -135,8 +136,19 @@ impl Approvable<UnifiedExecRequest> for UnifiedExecRuntime<'_> {
|
|||||||
Some(req.approval_requirement.clone())
|
Some(req.approval_requirement.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wants_escalated_first_attempt(&self, req: &UnifiedExecRequest) -> bool {
|
fn sandbox_mode_for_first_attempt(&self, req: &UnifiedExecRequest) -> SandboxOverride {
|
||||||
req.with_escalated_permissions.unwrap_or(false)
|
if req.with_escalated_permissions.unwrap_or(false)
|
||||||
|
|| matches!(
|
||||||
|
req.approval_requirement,
|
||||||
|
ApprovalRequirement::Skip {
|
||||||
|
bypass_sandbox: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SandboxOverride::BypassSandboxFirstAttempt
|
||||||
|
} else {
|
||||||
|
SandboxOverride::NoOverride
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,12 @@ pub(crate) struct ApprovalCtx<'a> {
|
|||||||
// Specifies what tool orchestrator should do with a given tool call.
|
// Specifies what tool orchestrator should do with a given tool call.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum ApprovalRequirement {
|
pub(crate) enum ApprovalRequirement {
|
||||||
/// No approval required for this tool call
|
/// No approval required for this tool call.
|
||||||
Skip,
|
Skip {
|
||||||
|
/// The first attempt should skip sandboxing (e.g., when explicitly
|
||||||
|
/// greenlit by policy).
|
||||||
|
bypass_sandbox: bool,
|
||||||
|
},
|
||||||
/// Approval required for this tool call
|
/// Approval required for this tool call
|
||||||
NeedsApproval { reason: Option<String> },
|
NeedsApproval { reason: Option<String> },
|
||||||
/// Execution forbidden for this tool call
|
/// Execution forbidden for this tool call
|
||||||
@@ -113,10 +117,18 @@ pub(crate) fn default_approval_requirement(
|
|||||||
if needs_approval {
|
if needs_approval {
|
||||||
ApprovalRequirement::NeedsApproval { reason: None }
|
ApprovalRequirement::NeedsApproval { reason: None }
|
||||||
} else {
|
} else {
|
||||||
ApprovalRequirement::Skip
|
ApprovalRequirement::Skip {
|
||||||
|
bypass_sandbox: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub(crate) enum SandboxOverride {
|
||||||
|
NoOverride,
|
||||||
|
BypassSandboxFirstAttempt,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) trait Approvable<Req> {
|
pub(crate) trait Approvable<Req> {
|
||||||
type ApprovalKey: Hash + Eq + Clone + Debug + Serialize;
|
type ApprovalKey: Hash + Eq + Clone + Debug + Serialize;
|
||||||
|
|
||||||
@@ -124,9 +136,9 @@ pub(crate) trait Approvable<Req> {
|
|||||||
|
|
||||||
/// Some tools may request to skip the sandbox on the first attempt
|
/// Some tools may request to skip the sandbox on the first attempt
|
||||||
/// (e.g., when the request explicitly asks for escalated permissions).
|
/// (e.g., when the request explicitly asks for escalated permissions).
|
||||||
/// Defaults to `false`.
|
/// Defaults to `NoOverride`.
|
||||||
fn wants_escalated_first_attempt(&self, _req: &Req) -> bool {
|
fn sandbox_mode_for_first_attempt(&self, _req: &Req) -> SandboxOverride {
|
||||||
false
|
SandboxOverride::NoOverride
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_bypass_approval(&self, policy: AskForApproval, already_approved: bool) -> bool {
|
fn should_bypass_approval(&self, policy: AskForApproval, already_approved: bool) -> bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user