core: merge built-in permission profiles as TOML

This commit is contained in:
Michael Bolin
2026-06-01 18:05:53 -07:00
parent b89bf1ef47
commit 9c3af9af8d
2 changed files with 87 additions and 36 deletions
+31 -1
View File
@@ -2356,7 +2356,13 @@ async fn default_permissions_profile_can_extend_builtin_workspace() -> std::io::
description: None,
extends: Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()),
workspace_roots: None,
filesystem: None,
filesystem: Some(FilesystemPermissionsToml {
glob_scan_max_depth: None,
entries: BTreeMap::from([(
":tmpdir".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
)]),
}),
network: Some(NetworkToml {
enabled: Some(true),
..Default::default()
@@ -2383,6 +2389,30 @@ async fn default_permissions_profile_can_extend_builtin_workspace() -> std::io::
!policy.can_write_path_with_cwd(&cwd.path().join(".git"), cwd.path()),
"expected profile extending :workspace to keep metadata carveouts, policy: {policy:?}"
);
assert!(
policy.entries.iter().any(|entry| matches!(
entry,
FileSystemSandboxEntry {
path: FileSystemPath::Special {
value: FileSystemSpecialPath::Tmpdir,
},
access: FileSystemAccessMode::Read,
}
)),
"expected child :tmpdir read entry to replace the inherited write entry, policy: {policy:?}"
);
assert!(
!policy.entries.iter().any(|entry| matches!(
entry,
FileSystemSandboxEntry {
path: FileSystemPath::Special {
value: FileSystemSpecialPath::Tmpdir,
},
access: FileSystemAccessMode::Write,
}
)),
"expected inherited :tmpdir write entry to be removed, policy: {policy:?}"
);
assert_eq!(
config.permissions.network_sandbox_policy(),
NetworkSandboxPolicy::Enabled
+56 -35
View File
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::io;
use std::path::Component;
use std::path::Path;
@@ -196,25 +197,59 @@ pub(crate) fn resolve_permission_profile(
profile_name: &str,
) -> io::Result<ResolvedPermissionProfileToml> {
permissions
.resolve_profile(profile_name, extensible_builtin_parent_profile_marker)
.resolve_profile(profile_name, extensible_builtin_parent_profile)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))
}
/// Built-in parents provide their runtime permissions below. Resolution only
/// needs an empty profile marker so inheritance can terminate while preserving
/// the built-in parent id in `inherited_profile_names`.
fn extensible_builtin_parent_profile_marker(profile_name: &str) -> Option<PermissionProfileToml> {
matches!(
profile_name,
BUILT_IN_READ_ONLY_PROFILE | BUILT_IN_WORKSPACE_PROFILE
)
.then_some(PermissionProfileToml {
description: None,
extends: None,
workspace_roots: None,
filesystem: None,
network: None,
})
fn extensible_builtin_parent_profile(profile_name: &str) -> Option<PermissionProfileToml> {
match profile_name {
BUILT_IN_READ_ONLY_PROFILE => Some(PermissionProfileToml {
description: None,
extends: None,
workspace_roots: None,
filesystem: Some(FilesystemPermissionsToml {
glob_scan_max_depth: None,
entries: BTreeMap::from([(
":root".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
)]),
}),
network: None,
}),
BUILT_IN_WORKSPACE_PROFILE => Some(PermissionProfileToml {
description: None,
extends: None,
workspace_roots: None,
filesystem: Some(FilesystemPermissionsToml {
glob_scan_max_depth: None,
entries: BTreeMap::from([
(
":root".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
),
(
":workspace_roots".to_string(),
FilesystemPermissionToml::Scoped(BTreeMap::from([
(".".to_string(), FileSystemAccessMode::Write),
(".git".to_string(), FileSystemAccessMode::Read),
(".agents".to_string(), FileSystemAccessMode::Read),
(".codex".to_string(), FileSystemAccessMode::Read),
])),
),
(
":slash_tmp".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Write),
),
(
":tmpdir".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Write),
),
]),
}),
network: None,
}),
_ => None,
}
}
pub(crate) fn network_proxy_config_for_profile_selection(
@@ -244,25 +279,10 @@ pub(crate) fn compile_permission_profile(
policy_cwd: &Path,
startup_warnings: &mut Vec<String>,
) -> io::Result<(FileSystemSandboxPolicy, NetworkSandboxPolicy)> {
let ResolvedPermissionProfileToml {
profile,
inherited_profile_names,
} = resolve_permission_profile(permissions, profile_name)?;
let base_permissions = inherited_profile_names.iter().find_map(|name| {
match name.as_str() {
BUILT_IN_READ_ONLY_PROFILE => Some(PermissionProfile::read_only()),
BUILT_IN_WORKSPACE_PROFILE => Some(PermissionProfile::workspace_write()),
_ => None,
}
.map(|profile| profile.to_runtime_permissions())
});
let (mut file_system_sandbox_policy, base_network_sandbox_policy) = base_permissions
.unwrap_or_else(|| {
(
FileSystemSandboxPolicy::restricted(Vec::new()),
NetworkSandboxPolicy::Restricted,
)
});
let ResolvedPermissionProfileToml { profile, .. } =
resolve_permission_profile(permissions, profile_name)?;
let mut file_system_sandbox_policy = FileSystemSandboxPolicy::restricted(Vec::new());
let base_network_sandbox_policy = NetworkSandboxPolicy::Restricted;
if let Some(filesystem) = profile.filesystem.as_ref() {
if filesystem.is_empty() && file_system_sandbox_policy.entries.is_empty() {
push_warning(
@@ -693,6 +713,7 @@ fn parse_special_path(path: &str) -> Option<FileSystemSpecialPath> {
":minimal" => Some(FileSystemSpecialPath::Minimal),
":workspace_roots" => Some(FileSystemSpecialPath::project_roots(/*subpath*/ None)),
":tmpdir" => Some(FileSystemSpecialPath::Tmpdir),
":slash_tmp" => Some(FileSystemSpecialPath::SlashTmp),
_ if path.starts_with(':') => {
Some(FileSystemSpecialPath::unknown(path, /*subpath*/ None))
}