chore: migrate additional permissions to PermissionProfile (#12731)

This PR replaces the old `additional_permissions.fs_read/fs_write` shape
with a shared `PermissionProfile`
model and wires it through the command approval, sandboxing, protocol,
and TUI layers. The schema is adopted from the
`SkillManifestPermissions`, which is also refactored to use this unified
struct. This helps us easily expose permission profiles in app
server/core as a follow-up.
This commit is contained in:
Celia Chen
2026-02-25 03:35:28 +00:00
committed by GitHub
parent e6bb5d8553
commit 16ca527c80
26 changed files with 572 additions and 263 deletions
+5 -5
View File
@@ -24,7 +24,7 @@ use crate::function_tool::FunctionCallError;
use crate::sandboxing::SandboxPermissions;
use crate::sandboxing::normalize_additional_permissions;
pub use apply_patch::ApplyPatchHandler;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::protocol::AskForApproval;
pub use dynamic::DynamicToolHandler;
pub use grep_files::GrepFilesHandler;
@@ -62,9 +62,9 @@ pub(super) fn normalize_and_validate_additional_permissions(
request_permission_enabled: bool,
approval_policy: AskForApproval,
sandbox_permissions: SandboxPermissions,
additional_permissions: Option<AdditionalPermissions>,
additional_permissions: Option<PermissionProfile>,
cwd: &Path,
) -> Result<Option<AdditionalPermissions>, String> {
) -> Result<Option<PermissionProfile>, String> {
let uses_additional_permissions = matches!(
sandbox_permissions,
SandboxPermissions::WithAdditionalPermissions
@@ -87,14 +87,14 @@ pub(super) fn normalize_and_validate_additional_permissions(
}
let Some(additional_permissions) = additional_permissions else {
return Err(
"missing `additional_permissions`; provide `fs_read` and/or `fs_write` when using `with_additional_permissions`"
"missing `additional_permissions`; provide `file_system.read` and/or `file_system.write` when using `with_additional_permissions`"
.to_string(),
);
};
let normalized = normalize_additional_permissions(additional_permissions, cwd)?;
if normalized.is_empty() {
return Err(
"`additional_permissions` must include at least one path in `fs_read` or `fs_write`"
"`additional_permissions` must include at least one path in `file_system.read` or `file_system.write`"
.to_string(),
);
}
+2 -2
View File
@@ -33,7 +33,7 @@ use crate::tools::runtimes::shell::ShellRuntime;
use crate::tools::runtimes::shell::ShellRuntimeBackend;
use crate::tools::sandboxing::ToolCtx;
use crate::tools::spec::ShellCommandBackendConfig;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::PermissionProfile;
pub struct ShellHandler;
@@ -50,7 +50,7 @@ pub struct ShellCommandHandler {
struct RunExecLikeArgs {
tool_name: String,
exec_params: ExecParams,
additional_permissions: Option<AdditionalPermissions>,
additional_permissions: Option<PermissionProfile>,
prefix_rule: Option<Vec<String>>,
session: Arc<crate::codex::Session>,
turn: Arc<TurnContext>,
@@ -21,8 +21,8 @@ use crate::unified_exec::UnifiedExecProcessManager;
use crate::unified_exec::UnifiedExecResponse;
use crate::unified_exec::WriteStdinRequest;
use async_trait::async_trait;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::PermissionProfile;
use serde::Deserialize;
use std::path::PathBuf;
use std::sync::Arc;
@@ -47,7 +47,7 @@ pub(crate) struct ExecCommandArgs {
#[serde(default)]
sandbox_permissions: SandboxPermissions,
#[serde(default)]
additional_permissions: Option<AdditionalPermissions>,
additional_permissions: Option<PermissionProfile>,
#[serde(default)]
justification: Option<String>,
#[serde(default)]
+2 -2
View File
@@ -10,7 +10,7 @@ use crate::sandboxing::CommandSpec;
use crate::sandboxing::SandboxPermissions;
use crate::shell::Shell;
use crate::tools::sandboxing::ToolError;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::PermissionProfile;
use std::collections::HashMap;
use std::path::Path;
@@ -26,7 +26,7 @@ pub(crate) fn build_command_spec(
env: &HashMap<String, String>,
expiration: ExecExpiration,
sandbox_permissions: SandboxPermissions,
additional_permissions: Option<AdditionalPermissions>,
additional_permissions: Option<PermissionProfile>,
justification: Option<String>,
) -> Result<CommandSpec, ToolError> {
let (program, args) = command
+3 -3
View File
@@ -31,7 +31,7 @@ use crate::tools::sandboxing::ToolRuntime;
use crate::tools::sandboxing::sandbox_override_for_first_attempt;
use crate::tools::sandboxing::with_cached_approval;
use codex_network_proxy::NetworkProxy;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::protocol::ReviewDecision;
use futures::future::BoxFuture;
use std::collections::HashMap;
@@ -46,7 +46,7 @@ pub struct ShellRequest {
pub explicit_env_overrides: HashMap<String, String>,
pub network: Option<NetworkProxy>,
pub sandbox_permissions: SandboxPermissions,
pub additional_permissions: Option<AdditionalPermissions>,
pub additional_permissions: Option<PermissionProfile>,
pub justification: Option<String>,
pub exec_approval_requirement: ExecApprovalRequirement,
}
@@ -89,7 +89,7 @@ pub(crate) struct ApprovalKey {
command: Vec<String>,
cwd: PathBuf,
sandbox_permissions: SandboxPermissions,
additional_permissions: Option<AdditionalPermissions>,
additional_permissions: Option<PermissionProfile>,
}
impl ShellRuntime {
@@ -32,7 +32,7 @@ use crate::unified_exec::UnifiedExecError;
use crate::unified_exec::UnifiedExecProcess;
use crate::unified_exec::UnifiedExecProcessManager;
use codex_network_proxy::NetworkProxy;
use codex_protocol::models::AdditionalPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::protocol::ReviewDecision;
use futures::future::BoxFuture;
use std::collections::HashMap;
@@ -47,7 +47,7 @@ pub struct UnifiedExecRequest {
pub network: Option<NetworkProxy>,
pub tty: bool,
pub sandbox_permissions: SandboxPermissions,
pub additional_permissions: Option<AdditionalPermissions>,
pub additional_permissions: Option<PermissionProfile>,
pub justification: Option<String>,
pub exec_approval_requirement: ExecApprovalRequirement,
}
@@ -58,7 +58,7 @@ pub struct UnifiedExecApprovalKey {
pub cwd: PathBuf,
pub tty: bool,
pub sandbox_permissions: SandboxPermissions,
pub additional_permissions: Option<AdditionalPermissions>,
pub additional_permissions: Option<PermissionProfile>,
}
pub struct UnifiedExecRuntime<'a> {
+28 -21
View File
@@ -256,29 +256,36 @@ fn create_approval_parameters(request_permission_enabled: bool) -> BTreeMap<Stri
properties.insert(
"additional_permissions".to_string(),
JsonSchema::Object {
properties: BTreeMap::from([
(
"fs_read".to_string(),
JsonSchema::Array {
items: Box::new(JsonSchema::String { description: None }),
description: Some(
"Additional filesystem paths to grant read access for this command."
.to_string(),
properties: BTreeMap::from([(
"file_system".to_string(),
JsonSchema::Object {
properties: BTreeMap::from([
(
"read".to_string(),
JsonSchema::Array {
items: Box::new(JsonSchema::String { description: None }),
description: Some(
"Additional filesystem paths to grant read access for this command."
.to_string(),
),
},
),
},
),
(
"fs_write".to_string(),
JsonSchema::Array {
items: Box::new(JsonSchema::String { description: None }),
description: Some(
"Additional filesystem paths to grant write access for this command."
.to_string(),
(
"write".to_string(),
JsonSchema::Array {
items: Box::new(JsonSchema::String { description: None }),
description: Some(
"Additional filesystem paths to grant write access for this command."
.to_string(),
),
},
),
},
),
]),
required: None,
]),
required: None,
additional_properties: Some(false.into()),
},
)]),
required: Some(vec!["file_system".to_string()]),
additional_properties: Some(false.into()),
},
);