mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
config: express implicit sandbox defaults as permission profiles (#25926)
## Why `PermissionProfile` is becoming the default way to represent Codex permissions, but the implicit default behavior should stay the same for now: - trusted projects use `:workspace` - untrusted projects also use `:workspace` - roots without a trust decision use `:read-only` - unsandboxed Windows falls back to `:read-only` This keeps the existing sandbox semantics while making silent config defaults observable as built-in permission profiles instead of treating the legacy `SandboxPolicy` projection as the primary shape. ## What Changed - Refactored legacy sandbox derivation to resolve the configured sandbox mode once, then apply the implicit project fallback only when no sandbox mode was configured. - Preserved the existing trust-decision fallback: trusted and untrusted projects default to workspace-write where supported. - Added empty-config coverage asserting that an untrusted project resolves to the built-in active permission profile (`:workspace` outside unsandboxed Windows). ## Verification - `just fmt` - `just test -p codex-core 'config::'` - `just test -p codex-config` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/25926). * __->__ #25926
This commit is contained in:
@@ -728,29 +728,23 @@ impl ConfigToml {
|
||||
active_project: Option<&ProjectConfig>,
|
||||
permission_profile_constraint: Option<&crate::Constrained<PermissionProfile>>,
|
||||
) -> PermissionProfile {
|
||||
let sandbox_mode_was_explicit =
|
||||
sandbox_mode_override.is_some() || self.sandbox_mode.is_some();
|
||||
let resolved_sandbox_mode = sandbox_mode_override
|
||||
.or(self.sandbox_mode)
|
||||
.or(if sandbox_mode_was_explicit {
|
||||
None
|
||||
} else {
|
||||
let configured_sandbox_mode = sandbox_mode_override.or(self.sandbox_mode);
|
||||
let resolved_sandbox_mode = configured_sandbox_mode
|
||||
.or_else(|| {
|
||||
// If no sandbox_mode is set but this directory has a trust decision,
|
||||
// default to workspace-write except on unsandboxed Windows where we
|
||||
// default to read-only.
|
||||
active_project.and_then(|p| {
|
||||
if p.is_trusted() || p.is_untrusted() {
|
||||
active_project
|
||||
.filter(|project| project.is_trusted() || project.is_untrusted())
|
||||
.map(|_| {
|
||||
if cfg!(target_os = "windows")
|
||||
&& windows_sandbox_level == WindowsSandboxLevel::Disabled
|
||||
{
|
||||
Some(SandboxMode::ReadOnly)
|
||||
SandboxMode::ReadOnly
|
||||
} else {
|
||||
Some(SandboxMode::WorkspaceWrite)
|
||||
SandboxMode::WorkspaceWrite
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let effective_sandbox_mode = if cfg!(target_os = "windows")
|
||||
@@ -788,7 +782,7 @@ impl ConfigToml {
|
||||
},
|
||||
SandboxMode::DangerFullAccess => PermissionProfile::Disabled,
|
||||
};
|
||||
if !sandbox_mode_was_explicit
|
||||
if configured_sandbox_mode.is_none()
|
||||
&& let Some(constraint) = permission_profile_constraint
|
||||
&& let Err(err) = constraint.can_set(&permission_profile)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user