Expose uncompiled permission profile selection (#39752)

## What changed

- Add `resolve_permission_profile_selection` to select the effective profile using configured defaults, managed requirements, and allowlists.
- Return the merged configured and managed profile catalog without compiling platform-specific paths, leaving path interpretation to the executor.

## Testing

- Verify that a managed default overrides a configured default while preserving Windows-style paths.
- Verify that an allowlisted but undefined profile is rejected.

GitOrigin-RevId: 0172193d48f0346522f931d3b806054895d199c0
This commit is contained in:
Sean Huang
2026-08-20 17:25:14 +00:00
committed by copyberry
parent a26d50852a
commit 85a1b0e33d
3 changed files with 138 additions and 0 deletions
+3
View File
@@ -159,6 +159,7 @@ mod managed_features;
mod network_proxy_spec;
mod otel;
mod permission_profile_catalog;
mod permission_profile_selection;
mod permissions;
mod requirements;
mod resolved_permission_profile;
@@ -182,6 +183,8 @@ pub use permission_profile_catalog::permission_profile_catalog;
use permission_profile_catalog::permission_profile_catalog_from_permissions;
use permission_profile_catalog::permission_profile_is_allowed;
use permission_profile_catalog::validate_permission_profile_for_deny_read;
pub use permission_profile_selection::ResolvedPermissionProfileSelection;
pub use permission_profile_selection::resolve_permission_profile_selection;
pub(crate) use permissions::is_builtin_permission_profile_name;
pub(crate) use resolved_permission_profile::PermissionProfileState;
@@ -0,0 +1,39 @@
use codex_config::ConfigRequirementsToml;
use codex_config::permissions_toml::PermissionsToml;
/// A selected permission profile and its uncompiled configured and managed catalog.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResolvedPermissionProfileSelection<'a> {
/// The effective profile selected by configuration and managed requirements.
pub profile_id: Option<&'a str>,
/// Configured and managed named profiles, without platform-specific compilation.
pub profiles: Option<PermissionsToml>,
}
/// Resolves the effective permission profile without interpreting profile paths.
///
/// Managed profiles and allowlists are applied using Core's normal selection rules,
/// while the merged profile catalog remains uncompiled for the executor to interpret.
pub fn resolve_permission_profile_selection<'a>(
configured_profiles: Option<&PermissionsToml>,
configured_default_profile_id: Option<&'a str>,
requirements: &'a ConfigRequirementsToml,
) -> std::io::Result<ResolvedPermissionProfileSelection<'a>> {
let selection = super::resolve_effective_permission_selection(
configured_profiles,
/*default_permissions_override*/ None,
/*persisted_profile_id*/ None,
configured_default_profile_id,
requirements,
&mut Vec::new(),
)?;
Ok(ResolvedPermissionProfileSelection {
profile_id: selection.selected_profile_id,
profiles: selection.profiles,
})
}
#[cfg(test)]
#[path = "permission_profile_selection_tests.rs"]
mod tests;
@@ -0,0 +1,96 @@
use crate::config::ResolvedPermissionProfileSelection;
use crate::config::resolve_permission_profile_selection;
use codex_config::ConfigRequirementsToml;
use codex_config::permissions_toml::PermissionsToml;
use pretty_assertions::assert_eq;
use std::collections::BTreeMap;
#[test]
fn resolves_managed_profile_without_compiling_executor_paths() -> anyhow::Result<()> {
let configured_profiles = toml::from_str::<PermissionsToml>(
r#"
[configured-windows]
extends = ":workspace"
[configured-windows.workspace_roots]
'C:\Users\agent\workspace' = true
[configured-windows.filesystem]
'C:\Users\agent\workspace' = "write"
"#,
)?;
let requirements = toml::from_str::<ConfigRequirementsToml>(
r#"
default_permissions = "managed-windows"
[allowed_permission_profiles]
configured-windows = false
managed-windows = true
[permissions.managed-windows.workspace_roots]
'D:\Managed\workspace' = true
[permissions.managed-windows.filesystem]
'D:\Managed\workspace' = "read"
"#,
)?;
let expected_profiles = PermissionsToml {
entries: BTreeMap::from([
(
"configured-windows".to_string(),
configured_profiles.entries["configured-windows"].clone(),
),
(
"managed-windows".to_string(),
requirements
.permissions
.as_ref()
.expect("managed profiles should deserialize")
.profiles["managed-windows"]
.clone(),
),
]),
};
let resolved = resolve_permission_profile_selection(
Some(&configured_profiles),
Some("configured-windows"),
&requirements,
)?;
assert_eq!(
resolved,
ResolvedPermissionProfileSelection {
profile_id: Some("managed-windows"),
profiles: Some(expected_profiles),
}
);
Ok(())
}
#[test]
fn rejects_undefined_allowlisted_permission_profile() -> anyhow::Result<()> {
let requirements = toml::from_str::<ConfigRequirementsToml>(
r#"
default_permissions = "missing-profile"
[allowed_permission_profiles]
missing-profile = true
"#,
)?;
let error = resolve_permission_profile_selection(
/*configured_profiles*/ None,
/*configured_default_profile_id*/ None,
&requirements,
)
.expect_err("undefined allowlisted profiles should be rejected");
assert_eq!(
error.to_string(),
"requirements.toml allowed_permission_profiles refers to undefined profile `missing-profile`"
);
Ok(())
}