permissions: support workspace roots in profiles

This commit is contained in:
Michael Bolin
2026-05-14 15:18:44 -07:00
parent 01d93fd9fc
commit 797dbb40f7
60 changed files with 1290 additions and 723 deletions
@@ -11,6 +11,7 @@ workspace = true
codex-core = { workspace = true }
codex-model-provider-info = { workspace = true }
codex-protocol = { workspace = true }
codex-utils-absolute-path = { workspace = true }
[dev-dependencies]
codex-utils-absolute-path = { workspace = true }
@@ -1,7 +1,7 @@
use codex_protocol::models::PermissionProfile;
use codex_protocol::protocol::NetworkAccess;
use codex_protocol::protocol::SandboxPolicy;
use std::path::Path;
use codex_utils_absolute_path::AbsolutePathBuf;
pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String {
match sandbox_policy {
@@ -51,8 +51,39 @@ pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String {
}
}
pub fn summarize_permission_profile(permission_profile: &PermissionProfile, cwd: &Path) -> String {
match permission_profile.to_legacy_sandbox_policy(cwd) {
pub fn summarize_permission_profile(
permission_profile: &PermissionProfile,
cwd: &AbsolutePathBuf,
workspace_roots: &[AbsolutePathBuf],
) -> String {
match permission_profile.to_legacy_sandbox_policy(cwd.as_path()) {
Ok(SandboxPolicy::WorkspaceWrite {
network_access,
exclude_tmpdir_env_var,
exclude_slash_tmp,
..
}) => {
let mut summary = "workspace-write".to_string();
let mut writable_entries = vec!["workdir".to_string()];
if !exclude_slash_tmp {
writable_entries.push("/tmp".to_string());
}
if !exclude_tmpdir_env_var {
writable_entries.push("$TMPDIR".to_string());
}
writable_entries.extend(
workspace_roots
.iter()
.filter(|root| *root != cwd)
.map(|root| root.to_string_lossy().to_string()),
);
summary.push_str(&format!(" [{}]", writable_entries.join(", ")));
if network_access {
summary.push_str(" (network access enabled)");
}
summary
}
Ok(policy) => summarize_sandbox_policy(&policy),
Err(_) => {
if permission_profile.network_sandbox_policy().is_enabled() {
@@ -67,6 +98,7 @@ pub fn summarize_permission_profile(permission_profile: &PermissionProfile, cwd:
#[cfg(test)]
mod tests {
use super::*;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
@@ -112,4 +144,39 @@ mod tests {
)
);
}
#[test]
fn permission_profile_summary_uses_runtime_workspace_roots_and_hides_internal_writes() {
let cwd =
AbsolutePathBuf::try_from(if cfg!(windows) { "C:\\repo" } else { "/repo" }).unwrap();
let extra_root = AbsolutePathBuf::try_from(if cfg!(windows) {
"C:\\repo-extra"
} else {
"/repo-extra"
})
.unwrap();
let hidden_root = AbsolutePathBuf::try_from(if cfg!(windows) {
"C:\\Users\\test\\.codex\\memories"
} else {
"/Users/test/.codex/memories"
})
.unwrap();
let profile = PermissionProfile::workspace_write_with(
std::slice::from_ref(&hidden_root),
NetworkSandboxPolicy::Restricted,
/*exclude_tmpdir_env_var*/ false,
/*exclude_slash_tmp*/ false,
);
let summary =
summarize_permission_profile(&profile, &cwd, &[cwd.clone(), extra_root.clone()]);
assert_eq!(
summary,
format!(
"workspace-write [workdir, /tmp, $TMPDIR, {}]",
extra_root.display()
)
);
}
}