mirror of
https://github.com/openai/codex.git
synced 2026-11-15 21:50:46 +00:00
Remove legacy sandbox-policy accessors from configuration (#61395)
## What changed - Remove `Config::legacy_sandbox_policy` and `Permissions::legacy_sandbox_policy`. - Update core and TUI tests to use permission profiles and filesystem/network policies directly, with explicit conversion where legacy wire formats are required. - Report the active sandbox label in app-server resume override mismatch diagnostics. GitOrigin-RevId: cbc5417944e23404523e69dc5516d66d6bfafefe
This commit is contained in:
@@ -1191,7 +1191,6 @@ flag = false
|
||||
async fn managed_preferences_expand_home_directory_in_workspace_write_roots() -> anyhow::Result<()>
|
||||
{
|
||||
use base64::Engine;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
|
||||
let Some(home) = dirs::home_dir() else {
|
||||
return Ok(());
|
||||
@@ -1230,23 +1229,15 @@ writable_roots = ["~/code"]
|
||||
.await?;
|
||||
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(home.join("code"))?;
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access: true,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: false,
|
||||
} => {
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
.iter()
|
||||
.filter(|root| **root == expected_root)
|
||||
.count(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
other => panic!("expected workspace-write policy, got {other:?}"),
|
||||
}
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
&codex_protocol::models::PermissionProfile::workspace_write_with(
|
||||
&[expected_root],
|
||||
codex_protocol::permissions::NetworkSandboxPolicy::Enabled,
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ false,
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(config.permissions.active_permission_profile(), None);
|
||||
Ok(())
|
||||
|
||||
@@ -101,7 +101,6 @@ use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::MultiAgentVersion;
|
||||
use codex_protocol::protocol::NetworkAccess;
|
||||
use codex_protocol::protocol::RealtimeVoice;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol_test_support::ContentItemTestExt;
|
||||
@@ -2718,7 +2717,7 @@ async fn permissions_profiles_network_disabled_by_default_does_not_start_proxy()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::io::Result<()> {
|
||||
async fn default_permissions_profile_populates_runtime_permissions() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cwd = TempDir::new()?;
|
||||
std::fs::create_dir_all(cwd.path().join("docs"))?;
|
||||
@@ -2793,15 +2792,6 @@ async fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::
|
||||
},
|
||||
]),
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
);
|
||||
assert!(
|
||||
!config
|
||||
.permissions
|
||||
@@ -2904,10 +2894,6 @@ async fn permission_profile_override_populates_runtime_permissions() -> std::io:
|
||||
permission_profile
|
||||
);
|
||||
assert_eq!(config.permissions.active_permission_profile(), None);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::DangerFullAccess
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3008,9 +2994,11 @@ extends = ":workspace"
|
||||
extends: Some(BUILT_IN_PERMISSION_PROFILE_WORKSPACE.to_string()),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::new_workspace_write_policy()
|
||||
assert!(
|
||||
config
|
||||
.permissions
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(cwd.path(), cwd.path())
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -3215,12 +3203,6 @@ async fn permission_profile_override_preserves_managed_unrestricted_filesystem()
|
||||
config.permissions.effective_permission_profile(),
|
||||
permission_profile
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Restricted,
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3238,16 +3220,16 @@ async fn managed_unrestricted_permission_profile_still_enables_network_requireme
|
||||
ConfigToml::default(),
|
||||
ConfigOverrides {
|
||||
cwd: Some(cwd.path().to_path_buf()),
|
||||
permission_profile: Some(permission_profile),
|
||||
permission_profile: Some(permission_profile.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
"the legacy projection is intentionally lossy for managed unrestricted profiles"
|
||||
config.permissions.effective_permission_profile(),
|
||||
permission_profile
|
||||
);
|
||||
|
||||
let layers = config
|
||||
@@ -3276,8 +3258,7 @@ async fn managed_unrestricted_permission_profile_still_enables_network_requireme
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn permission_profile_override_keeps_memories_root_out_of_legacy_projection()
|
||||
-> std::io::Result<()> {
|
||||
async fn permission_profile_override_keeps_memories_root_read_only() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cwd = TempDir::new()?;
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
@@ -3318,15 +3299,6 @@ async fn permission_profile_override_keeps_memories_root_out_of_legacy_projectio
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(memories_root.as_path(), cwd.path())
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4072,20 +4044,24 @@ async fn implicit_builtin_workspace_profile_preserves_sandbox_workspace_write_se
|
||||
"implicit :workspace cannot be faithfully re-selected when it includes \
|
||||
legacy sandbox_workspace_write settings"
|
||||
);
|
||||
match config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => {
|
||||
assert!(writable_roots.contains(&extra_root));
|
||||
assert!(network_access);
|
||||
assert!(exclude_tmpdir_env_var);
|
||||
assert!(!exclude_slash_tmp);
|
||||
}
|
||||
sandbox_policy => panic!("expected workspace-write projection, got {sandbox_policy:?}"),
|
||||
}
|
||||
assert_eq!(
|
||||
policy
|
||||
.entries
|
||||
.into_iter()
|
||||
.filter(|entry| matches!(
|
||||
&entry.path,
|
||||
FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Tmpdir | FileSystemSpecialPath::SlashTmp
|
||||
}
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![FileSystemSandboxEntry::new(
|
||||
FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::SlashTmp
|
||||
},
|
||||
FileSystemAccessMode::Write,
|
||||
)]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4341,15 +4317,6 @@ async fn permissions_profiles_allow_direct_write_roots_outside_workspace_root()
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(external_write_path.as_path(), cwd.path())
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![external_write_path],
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4457,12 +4424,6 @@ async fn permissions_profiles_allow_unknown_special_paths() -> std::io::Result<(
|
||||
missing_path_behavior: None,
|
||||
}]),
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
}
|
||||
);
|
||||
assert!(
|
||||
config.startup_warnings.iter().any(|warning| warning.contains(
|
||||
"Configured filesystem path `:future_special_path` is not recognized by this version of Codex and will be ignored."
|
||||
@@ -4529,12 +4490,6 @@ async fn permissions_profiles_allow_missing_filesystem_with_warning() -> std::io
|
||||
config.permissions.file_system_sandbox_policy(),
|
||||
FileSystemSandboxPolicy::restricted(Vec::new())
|
||||
);
|
||||
assert_eq!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
}
|
||||
);
|
||||
assert!(
|
||||
config.startup_warnings.iter().any(|warning| warning.contains(
|
||||
"Permissions profile `dev` does not define any recognized filesystem entries for this version of Codex."
|
||||
@@ -4666,7 +4621,6 @@ async fn permissions_profiles_allow_network_enablement() -> std::io::Result<()>
|
||||
config.permissions.network_sandbox_policy().is_enabled(),
|
||||
"expected network sandbox policy to be enabled",
|
||||
);
|
||||
assert!(config.legacy_sandbox_policy().has_full_network_access());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5241,7 +5195,10 @@ exclude_slash_tmp = true
|
||||
)
|
||||
.await?;
|
||||
|
||||
let sandbox_policy = config.legacy_sandbox_policy();
|
||||
let sandbox_policy = config
|
||||
.permissions
|
||||
.effective_permission_profile()
|
||||
.to_legacy_sandbox_policy(cwd.path())?;
|
||||
let file_system_policy = config.permissions.file_system_sandbox_policy();
|
||||
let network_policy = config.permissions.network_sandbox_policy();
|
||||
|
||||
@@ -6406,25 +6363,27 @@ async fn add_dir_override_extends_workspace_writable_roots() -> std::io::Result<
|
||||
|
||||
let expected_backend = backend.abs();
|
||||
if cfg!(target_os = "windows") {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
other => panic!("expected read-only policy on Windows, got {other:?}"),
|
||||
}
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
&PermissionProfile::read_only()
|
||||
);
|
||||
} else {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
.iter()
|
||||
.filter(|root| **root == expected_backend)
|
||||
.count(),
|
||||
1,
|
||||
"expected single writable root entry for {}",
|
||||
expected_backend.display()
|
||||
);
|
||||
}
|
||||
other => panic!("expected workspace-write policy, got {other:?}"),
|
||||
}
|
||||
assert!(
|
||||
config
|
||||
.permissions
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(expected_backend.as_path(), config.cwd.as_path())
|
||||
);
|
||||
let writable_roots = config.permissions.user_visible_workspace_roots();
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
.iter()
|
||||
.filter(|root| **root == expected_backend)
|
||||
.count(),
|
||||
1,
|
||||
"expected single writable root entry for {}",
|
||||
expected_backend.display()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -6546,10 +6505,10 @@ async fn workspace_write_includes_configured_writable_root_once_without_memories
|
||||
.await?;
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
other => panic!("expected read-only policy on Windows, got {other:?}"),
|
||||
}
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
&PermissionProfile::read_only()
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
!memories_root.exists(),
|
||||
@@ -6557,21 +6516,23 @@ async fn workspace_write_includes_configured_writable_root_once_without_memories
|
||||
memories_root.display()
|
||||
);
|
||||
let expected_memories_root = memories_root.abs();
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert!(!writable_roots.contains(&expected_memories_root));
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
.iter()
|
||||
.filter(|root| **root == writable_root)
|
||||
.count(),
|
||||
1,
|
||||
"expected single writable root entry for {}",
|
||||
writable_root.display()
|
||||
);
|
||||
}
|
||||
other => panic!("expected workspace-write policy, got {other:?}"),
|
||||
}
|
||||
assert!(
|
||||
config
|
||||
.permissions
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(writable_root.as_path(), config.cwd.as_path())
|
||||
);
|
||||
let writable_roots = config.permissions.user_visible_workspace_roots();
|
||||
assert!(!writable_roots.contains(&expected_memories_root));
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
.iter()
|
||||
.filter(|root| **root == writable_root)
|
||||
.count(),
|
||||
1,
|
||||
"expected single writable root entry for {}",
|
||||
writable_root.display()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -6621,17 +6582,13 @@ async fn memory_tool_makes_memories_root_readable_without_creating_or_widening_w
|
||||
);
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
other => panic!("expected read-only policy on Windows, got {other:?}"),
|
||||
}
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
&PermissionProfile::read_only()
|
||||
);
|
||||
} else {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert!(!writable_roots.contains(&memories_root_abs));
|
||||
}
|
||||
other => panic!("expected workspace-write policy, got {other:?}"),
|
||||
}
|
||||
let writable_roots = config.permissions.user_visible_workspace_roots();
|
||||
assert!(!writable_roots.contains(&memories_root_abs));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -11601,24 +11558,14 @@ async fn test_untrusted_project_gets_unless_trusted_approval_policy() -> anyhow:
|
||||
"Expected UnlessTrusted approval policy for untrusted project"
|
||||
);
|
||||
|
||||
// Verify that untrusted projects still get WorkspaceWrite sandbox (or ReadOnly on Windows)
|
||||
if cfg!(target_os = "windows") {
|
||||
assert!(
|
||||
matches!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::ReadOnly { .. }
|
||||
),
|
||||
"Expected ReadOnly on Windows"
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
matches!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::WorkspaceWrite { .. }
|
||||
),
|
||||
"Expected WorkspaceWrite sandbox for untrusted project"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
&if cfg!(target_os = "windows") {
|
||||
PermissionProfile::read_only()
|
||||
} else {
|
||||
PermissionProfile::workspace_write()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -11670,8 +11617,8 @@ async fn requirements_disallowing_default_sandbox_falls_back_to_required_default
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(
|
||||
config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::new_read_only_policy()
|
||||
config.permissions.effective_permission_profile(),
|
||||
PermissionProfile::read_only()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -11696,8 +11643,8 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(
|
||||
config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::new_read_only_policy()
|
||||
config.permissions.effective_permission_profile(),
|
||||
PermissionProfile::read_only()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -11974,8 +11921,6 @@ async fn permission_profile_override_falls_back_when_disallowed_by_requirements(
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
let expected_sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
assert_eq!(config.legacy_sandbox_policy(), expected_sandbox_policy);
|
||||
assert_eq!(
|
||||
config.permissions.effective_permission_profile(),
|
||||
PermissionProfile::read_only()
|
||||
@@ -12110,10 +12055,6 @@ async fn permission_profile_override_preserves_split_write_roots() -> std::io::R
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_local_path_with_cwd(outside_root.as_path(), config.cwd.as_path())
|
||||
);
|
||||
assert!(matches!(
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::WorkspaceWrite { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
config.permissions.network_sandbox_policy(),
|
||||
NetworkSandboxPolicy::Restricted
|
||||
|
||||
@@ -204,7 +204,6 @@ pub use codex_config::ConstraintError;
|
||||
pub use codex_config::ConstraintResult;
|
||||
pub use codex_config::LoaderOverrides;
|
||||
pub use codex_network_proxy::NetworkProxyAuditMetadata;
|
||||
use codex_sandboxing::compatibility_sandbox_policy_for_permission_profile;
|
||||
pub use codex_sandboxing::system_bwrap_warning;
|
||||
pub use managed_features::ManagedFeatures;
|
||||
pub(crate) use metrics::emit_session_start_metrics;
|
||||
@@ -497,12 +496,6 @@ impl Permissions {
|
||||
self.permission_profile().network_sandbox_policy()
|
||||
}
|
||||
|
||||
/// Legacy compatibility projection derived from the canonical profile.
|
||||
pub fn legacy_sandbox_policy(&self, cwd: &Path) -> SandboxPolicy {
|
||||
let permission_profile = self.effective_permission_profile();
|
||||
compatibility_sandbox_policy_for_permission_profile(&permission_profile, cwd)
|
||||
}
|
||||
|
||||
/// Check whether a legacy sandbox policy can be applied to this permission
|
||||
/// set after projecting it into the canonical permission profile.
|
||||
pub fn can_set_legacy_sandbox_policy(
|
||||
@@ -1794,10 +1787,6 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn legacy_sandbox_policy(&self) -> SandboxPolicy {
|
||||
self.permissions.legacy_sandbox_policy(self.cwd.as_path())
|
||||
}
|
||||
|
||||
/// Combine runtime and profile roots without interpreting them on the current host.
|
||||
pub fn effective_workspace_roots(&self) -> Vec<PathUri> {
|
||||
let mut workspace_roots = self
|
||||
@@ -3914,11 +3903,6 @@ impl Config {
|
||||
)
|
||||
} else {
|
||||
let configured_network_proxy_config = NetworkProxyConfig::default();
|
||||
// No named `[permissions]` profile is active, but permissions
|
||||
// should still flow through the canonical profile representation.
|
||||
// Derive the old `sandbox_mode` defaults as a profile first, then
|
||||
// keep a legacy-compatible projection only for the remaining code
|
||||
// paths that still speak `SandboxPolicy`.
|
||||
let mut permission_profile = if let Some(PermissionConfig::Legacy { mode, workspace_write }) = permission_config {
|
||||
translate_legacy_permissions(
|
||||
mode,
|
||||
|
||||
@@ -185,7 +185,7 @@ async fn accepted_input_applies_thread_settings() {
|
||||
environments: Some(local_selections(config.cwd.clone()).into_requests()),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
approvals_reviewer: Some(codex_config::types::ApprovalsReviewer::AutoReview),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(config.permissions.effective_permission_profile()),
|
||||
summary: config.model_reasoning_summary,
|
||||
personality: config.personality,
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
|
||||
@@ -57,7 +57,6 @@ use codex_protocol::models::FunctionCallOutputBody;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::models::SandboxEnforcement;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::protocol::AgentStatus;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -65,12 +64,9 @@ use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::FileSystemAccessMode;
|
||||
use codex_protocol::protocol::FileSystemPath;
|
||||
use codex_protocol::protocol::FileSystemSandboxEntry;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
use codex_protocol::protocol::ItemCompletedEvent;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
@@ -2289,10 +2285,9 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
Arc::clone(&environment_manager),
|
||||
);
|
||||
set_agent_control(&mut session, manager.agent_control());
|
||||
let expected_sandbox = turn.config.legacy_sandbox_policy();
|
||||
#[allow(deprecated)]
|
||||
let mut expected_file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&expected_sandbox, &turn.cwd);
|
||||
let expected_profile = turn.config.permissions.effective_permission_profile();
|
||||
let (mut expected_file_system_sandbox_policy, expected_network_sandbox_policy) =
|
||||
expected_profile.to_runtime_permissions();
|
||||
expected_file_system_sandbox_policy
|
||||
.entries
|
||||
.push(FileSystemSandboxEntry {
|
||||
@@ -2308,9 +2303,8 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
},
|
||||
missing_path_behavior: None,
|
||||
});
|
||||
let expected_network_sandbox_policy = NetworkSandboxPolicy::from(&expected_sandbox);
|
||||
let expected_permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&expected_sandbox),
|
||||
expected_profile.enforcement(),
|
||||
&expected_file_system_sandbox_policy,
|
||||
expected_network_sandbox_policy,
|
||||
);
|
||||
@@ -2390,7 +2384,6 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
.expect("spawned agent thread should exist")
|
||||
.config_snapshot()
|
||||
.await;
|
||||
assert_eq!(snapshot.sandbox_policy(), expected_sandbox);
|
||||
assert_eq!(snapshot.approval_policy, AskForApproval::OnRequest);
|
||||
assert_eq!(snapshot.approvals_reviewer, ApprovalsReviewer::AutoReview);
|
||||
assert_eq!(snapshot.permission_profile, expected_permission_profile);
|
||||
@@ -4555,29 +4548,6 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr
|
||||
async fn build_agent_spawn_config_uses_captured_step_settings_and_turn_context_values(
|
||||
parent_enabled: bool,
|
||||
) {
|
||||
fn pick_allowed_sandbox_policy(
|
||||
permissions: &crate::config::Permissions,
|
||||
base: SandboxPolicy,
|
||||
cwd: &std::path::Path,
|
||||
) -> SandboxPolicy {
|
||||
let candidates = [
|
||||
SandboxPolicy::new_read_only_policy(),
|
||||
SandboxPolicy::new_workspace_write_policy(),
|
||||
SandboxPolicy::DangerFullAccess,
|
||||
];
|
||||
candidates
|
||||
.into_iter()
|
||||
.find(|candidate| {
|
||||
if *candidate == base {
|
||||
return false;
|
||||
}
|
||||
permissions
|
||||
.can_set_legacy_sandbox_policy(candidate, cwd)
|
||||
.is_ok()
|
||||
})
|
||||
.unwrap_or(base)
|
||||
}
|
||||
|
||||
let (_session, mut turn) = make_session_and_context().await;
|
||||
update_turn_settings_for_test(&mut turn, |settings| {
|
||||
update_selected_settings_for_test(settings, |selected| {
|
||||
@@ -4609,19 +4579,23 @@ async fn build_agent_spawn_config_uses_captured_step_settings_and_turn_context_v
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
let turn_cwd = turn.cwd.clone();
|
||||
let sandbox_policy = pick_allowed_sandbox_policy(
|
||||
&turn.config.permissions,
|
||||
turn.config.legacy_sandbox_policy(),
|
||||
turn_cwd.as_path(),
|
||||
);
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &turn_cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
);
|
||||
let base_profile = turn.config.permissions.effective_permission_profile();
|
||||
let permission_profile = [
|
||||
PermissionProfile::read_only(),
|
||||
PermissionProfile::workspace_write()
|
||||
.materialize_project_roots_with_workspace_roots(&[turn_cwd]),
|
||||
PermissionProfile::Disabled,
|
||||
]
|
||||
.into_iter()
|
||||
.find(|candidate| {
|
||||
*candidate != base_profile
|
||||
&& turn
|
||||
.config
|
||||
.permissions
|
||||
.can_set_permission_profile(candidate)
|
||||
.is_ok()
|
||||
})
|
||||
.unwrap_or(base_profile);
|
||||
turn.initial_environments.environments.clear();
|
||||
Arc::make_mut(&mut turn.config)
|
||||
.permissions
|
||||
|
||||
@@ -781,8 +781,11 @@ async fn websocket_test_codex_shell_chain() -> Result<()> {
|
||||
let mut builder = test_codex().with_windows_cmd_shell();
|
||||
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
test.submit_turn_with_policy("run the echo command", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
test.submit_turn_with_permission_profile(
|
||||
"run the echo command",
|
||||
test.config.permissions.effective_permission_profile(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let connection = server.single_connection();
|
||||
assert_eq!(connection.len(), 2);
|
||||
@@ -847,8 +850,11 @@ async fn websocket_first_turn_uses_startup_prewarm_and_create(
|
||||
});
|
||||
}
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
test.submit_turn_with_policy("hello", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
test.submit_turn_with_permission_profile(
|
||||
"hello",
|
||||
test.config.permissions.effective_permission_profile(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(server.handshakes().len(), 1);
|
||||
let connection = server.single_connection();
|
||||
@@ -942,8 +948,11 @@ async fn websocket_first_turn_handles_handshake_delay_with_startup_prewarm() ->
|
||||
|
||||
let mut builder = test_codex();
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
test.submit_turn_with_policy("hello", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
test.submit_turn_with_permission_profile(
|
||||
"hello",
|
||||
test.config.permissions.effective_permission_profile(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(server.handshakes().len(), 1);
|
||||
let connection = server.single_connection();
|
||||
@@ -999,8 +1008,11 @@ async fn websocket_v2_test_codex_shell_chain() -> Result<()> {
|
||||
});
|
||||
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
test.submit_turn_with_policy("run the echo command", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
test.submit_turn_with_permission_profile(
|
||||
"run the echo command",
|
||||
test.config.permissions.effective_permission_profile(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let connection = server.single_connection();
|
||||
assert_eq!(connection.len(), 3);
|
||||
|
||||
@@ -2843,7 +2843,7 @@ async fn user_turn_collaboration_mode_overrides_model_and_effort() -> anyhow::Re
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(config.cwd.clone())),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(config.permissions.effective_permission_profile()),
|
||||
summary: Some(
|
||||
config
|
||||
.model_reasoning_summary
|
||||
@@ -3101,7 +3101,7 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(config.cwd.clone())),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(config.permissions.effective_permission_profile()),
|
||||
summary: Some(ReasoningSummary::Concise),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
|
||||
@@ -546,7 +546,7 @@ async fn collaboration_instructions_added_on_user_turn() -> Result<()> {
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(test.config.permissions.effective_permission_profile()),
|
||||
summary: Some(
|
||||
test.config
|
||||
.model_reasoning_summary
|
||||
@@ -593,7 +593,7 @@ async fn collaboration_instructions_omitted_when_disabled() -> Result<()> {
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(test.config.permissions.effective_permission_profile()),
|
||||
summary: Some(
|
||||
test.config
|
||||
.model_reasoning_summary
|
||||
@@ -651,7 +651,7 @@ async fn user_turn_overrides_collaboration_instructions_after_override() -> Resu
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
permission_profile: Some(test.config.permissions.effective_permission_profile()),
|
||||
summary: Some(
|
||||
test.config
|
||||
.model_reasoning_summary
|
||||
|
||||
@@ -260,7 +260,7 @@ approvals_reviewer = "user"
|
||||
"model": session.model, "modelProvider": session.model_provider_id, "cwd": session.cwd,
|
||||
"approvalPolicy": app::AskForApproval::from(session.approval_policy),
|
||||
"approvalsReviewer": app::ApprovalsReviewer::from(session.approvals_reviewer),
|
||||
"sandbox": app::SandboxPolicy::from(test.config.legacy_sandbox_policy()),
|
||||
"sandbox": app::SandboxPolicy::from(test.config.permissions.effective_permission_profile().to_legacy_sandbox_policy(test.config.cwd.as_path())?),
|
||||
}))?;
|
||||
client.track_response(
|
||||
/*connection_id*/ 1,
|
||||
|
||||
@@ -916,7 +916,7 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
|
||||
let default_cwd = config.cwd.clone();
|
||||
let default_approval_policy = config.permissions.approval_policy.value();
|
||||
let default_sandbox_policy = &config.legacy_sandbox_policy();
|
||||
let default_permission_profile = config.permissions.effective_permission_profile();
|
||||
let default_model = session_configured.model;
|
||||
let default_effort = config.model_reasoning_effort.clone();
|
||||
let default_summary = config.model_reasoning_summary;
|
||||
@@ -930,7 +930,7 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
permission_profile: Some(default_permission_profile.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
@@ -955,7 +955,7 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
permission_profile: Some(default_permission_profile.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
@@ -1053,7 +1053,7 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
|
||||
let default_cwd = config.cwd.clone();
|
||||
let default_approval_policy = config.permissions.approval_policy.value();
|
||||
let default_sandbox_policy = &config.legacy_sandbox_policy();
|
||||
let default_permission_profile = config.permissions.effective_permission_profile();
|
||||
let default_model = session_configured.model;
|
||||
let default_effort = config.model_reasoning_effort.clone();
|
||||
let default_summary = config.model_reasoning_summary;
|
||||
@@ -1067,7 +1067,7 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(local_requests(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
permission_profile: Some(default_permission_profile.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
|
||||
@@ -5,9 +5,9 @@ use anyhow::Result;
|
||||
use codex_config::LoaderOverrides;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_core::config::ConfigOverrides;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_utils_cargo_bin::cargo_bin;
|
||||
use core_test_support::responses;
|
||||
use core_test_support::skip_if_remote;
|
||||
@@ -107,13 +107,11 @@ async fn forged_worktree_project_config_cannot_start_host_mcp() -> Result<()> {
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
loaded.permissions.legacy_sandbox_policy(&checkout),
|
||||
loaded.permissions.effective_permission_profile(),
|
||||
if registered {
|
||||
SandboxPolicy::DangerFullAccess
|
||||
PermissionProfile::Disabled
|
||||
} else {
|
||||
SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
}
|
||||
PermissionProfile::read_only()
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user