mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
permissions: store only constrained permission profiles (#19735)
This commit is contained in:
committed by
GitHub
Unverified
parent
8033b6a449
commit
0ccd659b4b
@@ -574,7 +574,7 @@ writable_roots = ["./sandbox-root"]
|
||||
false
|
||||
);
|
||||
|
||||
match &*config.permissions.sandbox_policy {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { network_access, .. } => {
|
||||
assert_eq!(*network_access, true);
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ writable_roots = ["~/code"]
|
||||
.await?;
|
||||
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(home.join("code"))?;
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
|
||||
@@ -806,7 +806,7 @@ async fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::
|
||||
]),
|
||||
);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![memories_root],
|
||||
network_access: false,
|
||||
@@ -840,7 +840,7 @@ async fn permission_profile_override_populates_runtime_permissions() -> std::io:
|
||||
|
||||
assert_eq!(config.permissions.permission_profile(), permission_profile);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::DangerFullAccess
|
||||
);
|
||||
Ok(())
|
||||
@@ -869,7 +869,7 @@ async fn permission_profile_override_preserves_managed_unrestricted_filesystem()
|
||||
|
||||
assert_eq!(config.permissions.permission_profile(), permission_profile);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Restricted,
|
||||
}
|
||||
@@ -898,7 +898,7 @@ async fn managed_unrestricted_permission_profile_still_enables_network_requireme
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
"the legacy projection is intentionally lossy for managed unrestricted profiles"
|
||||
);
|
||||
@@ -974,7 +974,7 @@ async fn permission_profile_override_applies_runtime_roots_to_legacy_projection(
|
||||
.can_write_path_with_cwd(memories_root.as_path(), cwd.path())
|
||||
);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![memories_root],
|
||||
network_access: false,
|
||||
@@ -1209,7 +1209,7 @@ async fn permissions_profiles_allow_direct_write_roots_outside_workspace_root()
|
||||
.can_write_path_with_cwd(external_write_path.as_path(), cwd.path())
|
||||
);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![external_write_path, memories_root],
|
||||
network_access: false,
|
||||
@@ -1317,7 +1317,7 @@ async fn permissions_profiles_allow_unknown_special_paths() -> std::io::Result<(
|
||||
}]),
|
||||
);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
}
|
||||
@@ -1382,7 +1382,7 @@ async fn permissions_profiles_allow_missing_filesystem_with_warning() -> std::io
|
||||
FileSystemSandboxPolicy::restricted(Vec::new())
|
||||
);
|
||||
assert_eq!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
}
|
||||
@@ -1509,13 +1509,7 @@ 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
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.get()
|
||||
.has_full_network_access()
|
||||
);
|
||||
assert!(config.legacy_sandbox_policy().has_full_network_access());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1799,7 +1793,7 @@ exclude_slash_tmp = true
|
||||
)
|
||||
.await?;
|
||||
|
||||
let sandbox_policy = config.permissions.sandbox_policy.get();
|
||||
let sandbox_policy = &config.legacy_sandbox_policy();
|
||||
assert_eq!(
|
||||
config.permissions.file_system_sandbox_policy(),
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd.path()),
|
||||
@@ -1982,12 +1976,12 @@ async fn add_dir_override_extends_workspace_writable_roots() -> std::io::Result<
|
||||
|
||||
let expected_backend = backend.abs();
|
||||
if cfg!(target_os = "windows") {
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
other => panic!("expected read-only policy on Windows, got {other:?}"),
|
||||
}
|
||||
} else {
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
@@ -2045,7 +2039,7 @@ async fn workspace_write_always_includes_memories_root_once() -> std::io::Result
|
||||
.await?;
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
other => panic!("expected read-only policy on Windows, got {other:?}"),
|
||||
}
|
||||
@@ -2056,7 +2050,7 @@ async fn workspace_write_always_includes_memories_root_once() -> std::io::Result
|
||||
memories_root.display()
|
||||
);
|
||||
let expected_memories_root = memories_root.abs();
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
match &config.legacy_sandbox_policy() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert_eq!(
|
||||
writable_roots
|
||||
@@ -2375,7 +2369,7 @@ async fn profile_sandbox_mode_overrides_base() -> std::io::Result<()> {
|
||||
.await?;
|
||||
|
||||
assert!(matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
&SandboxPolicy::DangerFullAccess
|
||||
));
|
||||
|
||||
@@ -2409,12 +2403,12 @@ async fn cli_override_takes_precedence_over_profile_sandbox_mode() -> std::io::R
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
assert!(matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::ReadOnly { .. }
|
||||
));
|
||||
} else {
|
||||
assert!(matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::WorkspaceWrite { .. }
|
||||
));
|
||||
}
|
||||
@@ -5448,7 +5442,6 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::Never),
|
||||
permission_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
sandbox_policy: Constrained::allow_any(SandboxPolicy::new_read_only_policy()),
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
shell_environment_policy: ShellEnvironmentPolicy::default(),
|
||||
@@ -5642,7 +5635,6 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::UnlessTrusted),
|
||||
permission_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
sandbox_policy: Constrained::allow_any(SandboxPolicy::new_read_only_policy()),
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
shell_environment_policy: ShellEnvironmentPolicy::default(),
|
||||
@@ -5790,7 +5782,6 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::OnFailure),
|
||||
permission_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
sandbox_policy: Constrained::allow_any(SandboxPolicy::new_read_only_policy()),
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
shell_environment_policy: ShellEnvironmentPolicy::default(),
|
||||
@@ -5923,7 +5914,6 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::OnFailure),
|
||||
permission_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
sandbox_policy: Constrained::allow_any(SandboxPolicy::new_read_only_policy()),
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
shell_environment_policy: ShellEnvironmentPolicy::default(),
|
||||
@@ -6660,7 +6650,7 @@ async fn test_untrusted_project_gets_unless_trusted_approval_policy() -> anyhow:
|
||||
if cfg!(target_os = "windows") {
|
||||
assert!(
|
||||
matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::ReadOnly { .. }
|
||||
),
|
||||
"Expected ReadOnly on Windows"
|
||||
@@ -6668,7 +6658,7 @@ async fn test_untrusted_project_gets_unless_trusted_approval_policy() -> anyhow:
|
||||
} else {
|
||||
assert!(
|
||||
matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::WorkspaceWrite { .. }
|
||||
),
|
||||
"Expected WorkspaceWrite sandbox for untrusted project"
|
||||
@@ -6694,7 +6684,7 @@ async fn requirements_disallowing_default_sandbox_falls_back_to_required_default
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(
|
||||
*config.permissions.sandbox_policy.get(),
|
||||
config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::new_read_only_policy()
|
||||
);
|
||||
Ok(())
|
||||
@@ -6735,7 +6725,7 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(
|
||||
*config.permissions.sandbox_policy.get(),
|
||||
config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::new_read_only_policy()
|
||||
);
|
||||
Ok(())
|
||||
@@ -6764,10 +6754,7 @@ async fn permission_profile_override_falls_back_when_disallowed_by_requirements(
|
||||
.await?;
|
||||
|
||||
let expected_sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
assert_eq!(
|
||||
*config.permissions.sandbox_policy.get(),
|
||||
expected_sandbox_policy
|
||||
);
|
||||
assert_eq!(config.legacy_sandbox_policy(), expected_sandbox_policy);
|
||||
assert_eq!(
|
||||
config.permissions.permission_profile(),
|
||||
PermissionProfile::read_only()
|
||||
@@ -6821,7 +6808,7 @@ async fn permission_profile_override_preserves_split_write_roots() -> std::io::R
|
||||
.can_write_path_with_cwd(outside_root.as_path(), config.cwd.as_path())
|
||||
);
|
||||
assert!(matches!(
|
||||
config.permissions.sandbox_policy.get(),
|
||||
&config.legacy_sandbox_policy(),
|
||||
SandboxPolicy::WorkspaceWrite { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
|
||||
@@ -195,11 +195,6 @@ pub struct Permissions {
|
||||
/// Canonical effective runtime permissions after config requirements and
|
||||
/// runtime readable-root additions have been applied.
|
||||
pub permission_profile: Constrained<PermissionProfile>,
|
||||
/// Effective sandbox policy used for shell/unified exec.
|
||||
///
|
||||
/// Legacy projection retained while runtime call sites migrate to
|
||||
/// `permission_profile`.
|
||||
pub sandbox_policy: Constrained<SandboxPolicy>,
|
||||
/// Effective network configuration applied to all spawned processes.
|
||||
pub network: Option<NetworkProxySpec>,
|
||||
/// Whether the model may request a login shell for shell-based tools.
|
||||
@@ -250,13 +245,12 @@ impl Permissions {
|
||||
}
|
||||
|
||||
/// Check whether a legacy sandbox policy can be applied to this permission
|
||||
/// set under both legacy and canonical profile constraints.
|
||||
/// set after projecting it into the canonical permission profile.
|
||||
pub fn can_set_legacy_sandbox_policy(
|
||||
&self,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
cwd: &Path,
|
||||
) -> ConstraintResult<()> {
|
||||
self.sandbox_policy.can_set(sandbox_policy)?;
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(sandbox_policy);
|
||||
@@ -285,31 +279,18 @@ impl Permissions {
|
||||
network_sandbox_policy,
|
||||
);
|
||||
|
||||
self.sandbox_policy.set(sandbox_policy)?;
|
||||
self.permission_profile.set(permission_profile)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Replace permissions from the canonical profile and update compatibility
|
||||
/// projections for legacy consumers.
|
||||
/// Replace permissions from the canonical profile.
|
||||
pub fn set_permission_profile(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
cwd: &Path,
|
||||
) -> ConstraintResult<()> {
|
||||
let (file_system_sandbox_policy, network_sandbox_policy) =
|
||||
permission_profile.to_runtime_permissions();
|
||||
let sandbox_policy = compatibility_sandbox_policy_for_permission_profile(
|
||||
&permission_profile,
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
cwd,
|
||||
);
|
||||
self.permission_profile.can_set(&permission_profile)?;
|
||||
self.sandbox_policy.can_set(&sandbox_policy)?;
|
||||
|
||||
self.permission_profile.set(permission_profile)?;
|
||||
self.sandbox_policy.set(sandbox_policy)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -915,6 +896,18 @@ impl ConfigBuilder {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn legacy_sandbox_policy(&self) -> SandboxPolicy {
|
||||
self.permissions.legacy_sandbox_policy(self.cwd.as_path())
|
||||
}
|
||||
|
||||
pub fn set_legacy_sandbox_policy(
|
||||
&mut self,
|
||||
sandbox_policy: SandboxPolicy,
|
||||
) -> ConstraintResult<()> {
|
||||
self.permissions
|
||||
.set_legacy_sandbox_policy(sandbox_policy, self.cwd.as_path())
|
||||
}
|
||||
|
||||
pub fn to_models_manager_config(&self) -> ModelsManagerConfig {
|
||||
ModelsManagerConfig {
|
||||
model_context_window: self.model_context_window,
|
||||
@@ -2484,7 +2477,6 @@ impl Config {
|
||||
permissions: Permissions {
|
||||
approval_policy: constrained_approval_policy.value,
|
||||
permission_profile: constrained_permission_profile,
|
||||
sandbox_policy: constrained_sandbox_policy.value,
|
||||
network,
|
||||
allow_login_shell,
|
||||
shell_environment_policy,
|
||||
|
||||
@@ -848,7 +848,6 @@ pub(crate) fn build_guardian_review_session_config(
|
||||
guardian_config.permissions.permission_profile = Constrained::allow_only(
|
||||
PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
);
|
||||
guardian_config.permissions.sandbox_policy = Constrained::allow_only(sandbox_policy.clone());
|
||||
guardian_config
|
||||
.permissions
|
||||
.set_legacy_sandbox_policy(sandbox_policy, guardian_config.cwd.as_path())
|
||||
|
||||
@@ -1984,8 +1984,10 @@ async fn guardian_review_session_config_preserves_parent_network_proxy() {
|
||||
Constrained::allow_only(AskForApproval::Never)
|
||||
);
|
||||
assert_eq!(
|
||||
guardian_config.permissions.sandbox_policy,
|
||||
Constrained::allow_only(SandboxPolicy::new_read_only_policy())
|
||||
guardian_config.permissions.permission_profile,
|
||||
Constrained::allow_only(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -489,7 +489,7 @@ mod phase2 {
|
||||
);
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile(permission_profile, config.cwd.as_path())
|
||||
.set_permission_profile(permission_profile)
|
||||
.expect("permissions are configurable");
|
||||
configure(&mut config);
|
||||
let config = Arc::new(config);
|
||||
@@ -935,8 +935,9 @@ mod phase2 {
|
||||
.await
|
||||
.expect("enqueue global consolidation");
|
||||
let mut constrained_config = harness.config.as_ref().clone();
|
||||
constrained_config.permissions.sandbox_policy =
|
||||
Constrained::allow_only(SandboxPolicy::DangerFullAccess);
|
||||
constrained_config.permissions.permission_profile = Constrained::allow_only(
|
||||
PermissionProfile::from_legacy_sandbox_policy(&SandboxPolicy::DangerFullAccess),
|
||||
);
|
||||
|
||||
phase2::run(&harness.session, Arc::new(constrained_config)).await;
|
||||
|
||||
|
||||
@@ -1515,7 +1515,9 @@ async fn session_configured_reports_permission_profile_for_external_sandbox() ->
|
||||
};
|
||||
let expected_sandbox_policy = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.sandbox_policy = codex_config::Constrained::allow_any(sandbox_policy);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy)
|
||||
.expect("set sandbox policy");
|
||||
config.permissions.permission_profile =
|
||||
codex_config::Constrained::allow_any(PermissionProfile::from_runtime_permissions(
|
||||
&FileSystemSandboxPolicy::external_sandbox(),
|
||||
@@ -4187,7 +4189,7 @@ async fn user_turn_updates_approvals_reviewer() {
|
||||
cwd: config.cwd.to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: Some(codex_config::types::ApprovalsReviewer::AutoReview),
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
effort: config.model_reasoning_effort,
|
||||
|
||||
@@ -383,8 +383,6 @@ impl Session {
|
||||
per_turn_config.approvals_reviewer = session_configuration.approvals_reviewer;
|
||||
per_turn_config.permissions.permission_profile =
|
||||
session_configuration.permission_profile.clone();
|
||||
let sandbox_policy = session_configuration.sandbox_policy();
|
||||
per_turn_config.permissions.sandbox_policy = Constrained::allow_only(sandbox_policy);
|
||||
let permission_profile = session_configuration.permission_profile();
|
||||
let resolved_web_search_mode =
|
||||
resolve_web_search_mode_for_turn(&per_turn_config.web_search_mode, &permission_profile);
|
||||
|
||||
@@ -269,7 +269,7 @@ pub(crate) fn apply_spawn_agent_runtime_overrides(
|
||||
config.cwd = turn.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile(turn.permission_profile(), turn.cwd.as_path())
|
||||
.set_permission_profile(turn.permission_profile())
|
||||
.map_err(|err| {
|
||||
FunctionCallError::RespondToModel(format!("permission_profile is invalid: {err}"))
|
||||
})?;
|
||||
|
||||
@@ -2086,7 +2086,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let expected_sandbox = turn.config.permissions.sandbox_policy.get().clone();
|
||||
let expected_sandbox = turn.config.legacy_sandbox_policy();
|
||||
let mut expected_file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&expected_sandbox, &turn.cwd);
|
||||
expected_file_system_sandbox_policy
|
||||
@@ -3585,8 +3585,9 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr
|
||||
#[tokio::test]
|
||||
async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
fn pick_allowed_sandbox_policy(
|
||||
constraint: &crate::config::Constrained<SandboxPolicy>,
|
||||
constraint: &crate::config::Constrained<PermissionProfile>,
|
||||
base: SandboxPolicy,
|
||||
cwd: &std::path::Path,
|
||||
) -> SandboxPolicy {
|
||||
let candidates = [
|
||||
SandboxPolicy::new_read_only_policy(),
|
||||
@@ -3595,7 +3596,21 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
];
|
||||
candidates
|
||||
.into_iter()
|
||||
.find(|candidate| *candidate != base && constraint.can_set(candidate).is_ok())
|
||||
.find(|candidate| {
|
||||
if *candidate == base {
|
||||
return false;
|
||||
}
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(candidate, cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(candidate);
|
||||
let permission_profile =
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(candidate),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
);
|
||||
constraint.can_set(&permission_profile).is_ok()
|
||||
})
|
||||
.unwrap_or(base)
|
||||
}
|
||||
|
||||
@@ -3613,8 +3628,9 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
turn.cwd = temp_dir.abs();
|
||||
turn.codex_linux_sandbox_exe = Some(PathBuf::from("/bin/echo"));
|
||||
let sandbox_policy = pick_allowed_sandbox_policy(
|
||||
&turn.config.permissions.sandbox_policy,
|
||||
turn.config.permissions.sandbox_policy.get().clone(),
|
||||
&turn.config.permissions.permission_profile,
|
||||
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);
|
||||
@@ -3648,7 +3664,7 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
.expect("approval policy set");
|
||||
expected
|
||||
.permissions
|
||||
.set_permission_profile(permission_profile, turn.cwd.as_path())
|
||||
.set_permission_profile(permission_profile)
|
||||
.expect("permission profile set");
|
||||
assert_eq!(config, expected);
|
||||
}
|
||||
@@ -3699,8 +3715,7 @@ async fn build_agent_resume_config_clears_base_instructions() {
|
||||
.expect("approval policy set");
|
||||
expected
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.set(turn.sandbox_policy())
|
||||
.expect("sandbox policy set");
|
||||
.set_permission_profile(turn.permission_profile())
|
||||
.expect("permission profile set");
|
||||
assert_eq!(config, expected);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ impl ZshForkRuntime {
|
||||
config.main_execve_wrapper_exe = Some(self.main_execve_wrapper_exe.clone());
|
||||
config.permissions.allow_login_shell = false;
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy)
|
||||
.expect("set sandbox policy");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,8 @@ 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.permissions.sandbox_policy.get().clone(),
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn_with_policy("run the echo command", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
|
||||
let connection = server.single_connection();
|
||||
assert_eq!(connection.len(), 2);
|
||||
@@ -85,11 +82,8 @@ async fn websocket_first_turn_uses_startup_prewarm_and_create() -> Result<()> {
|
||||
|
||||
let mut builder = test_codex();
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
test.submit_turn_with_policy(
|
||||
"hello",
|
||||
test.config.permissions.sandbox_policy.get().clone(),
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn_with_policy("hello", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
|
||||
assert_eq!(server.handshakes().len(), 1);
|
||||
let connection = server.single_connection();
|
||||
@@ -135,11 +129,8 @@ 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.permissions.sandbox_policy.get().clone(),
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn_with_policy("hello", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
|
||||
assert_eq!(server.handshakes().len(), 1);
|
||||
let connection = server.single_connection();
|
||||
@@ -191,11 +182,8 @@ 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.permissions.sandbox_policy.get().clone(),
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn_with_policy("run the echo command", test.config.legacy_sandbox_policy())
|
||||
.await?;
|
||||
|
||||
let connection = server.single_connection();
|
||||
assert_eq!(connection.len(), 3);
|
||||
|
||||
@@ -1727,7 +1727,9 @@ async fn run_scenario(scenario: &ScenarioSpec) -> Result<()> {
|
||||
|
||||
let mut builder = test_codex().with_model(model).with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy.clone());
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy.clone())
|
||||
.expect("set sandbox policy");
|
||||
for feature in features {
|
||||
config
|
||||
.features
|
||||
@@ -1854,7 +1856,9 @@ async fn approving_apply_patch_for_session_skips_future_prompts_for_same_file()
|
||||
.with_model("gpt-5.4")
|
||||
.with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config.approvals_reviewer = ApprovalsReviewer::User;
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
@@ -1962,7 +1966,9 @@ async fn approving_execpolicy_amendment_persists_policy_and_skips_future_prompts
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
let allow_prefix_path = test.cwd.path().join("allow-prefix.txt");
|
||||
@@ -2133,7 +2139,9 @@ async fn spawned_subagent_execpolicy_amendment_propagates_to_parent_session() ->
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Collab)
|
||||
@@ -2394,7 +2402,9 @@ async fn invalid_requested_prefix_rule_falls_back_for_compound_command() -> Resu
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
@@ -2445,7 +2455,9 @@ async fn approving_fallback_rule_for_compound_command_works() -> Result<()> {
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
@@ -2580,7 +2592,9 @@ allow_local_binding = true
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_home(home).with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
let layers = config
|
||||
.config_layer_stack
|
||||
.get_layers(
|
||||
@@ -3030,7 +3044,9 @@ async fn compound_command_with_one_safe_command_still_requires_approval() -> Res
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
|
||||
@@ -1745,7 +1745,7 @@ async fn user_turn_collaboration_mode_overrides_model_and_effort() -> anyhow::Re
|
||||
cwd: config.cwd.to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: session_configured.model.clone(),
|
||||
effort: Some(ReasoningEffort::Low),
|
||||
@@ -1867,7 +1867,7 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
|
||||
cwd: config.cwd.to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: session_configured.model,
|
||||
effort: None,
|
||||
|
||||
@@ -64,8 +64,9 @@ async fn codex_delegate_forwards_exec_approval_and_proceeds_on_approval() {
|
||||
// routes ExecApprovalRequest via the parent.
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
config.permissions.sandbox_policy =
|
||||
Constrained::allow_any(SandboxPolicy::new_read_only_policy());
|
||||
config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_read_only_policy())
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await.expect("build test codex");
|
||||
|
||||
@@ -147,8 +148,9 @@ async fn codex_delegate_forwards_patch_approval_and_proceeds_on_decision() {
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
// Use a restricted sandbox so patch approval is required
|
||||
config.permissions.sandbox_policy =
|
||||
Constrained::allow_any(SandboxPolicy::new_read_only_policy());
|
||||
config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_read_only_policy())
|
||||
.expect("set sandbox policy");
|
||||
config.include_apply_patch_tool = true;
|
||||
});
|
||||
let test = builder.build(&server).await.expect("build test codex");
|
||||
|
||||
@@ -185,7 +185,7 @@ async fn collaboration_instructions_added_on_user_turn() -> Result<()> {
|
||||
cwd: test.config.cwd.to_path_buf(),
|
||||
approval_policy: test.config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: test.config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: test.config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: test.session_configured.model.clone(),
|
||||
effort: None,
|
||||
@@ -307,7 +307,7 @@ async fn user_turn_overrides_collaboration_instructions_after_override() -> Resu
|
||||
cwd: test.config.cwd.to_path_buf(),
|
||||
approval_policy: test.config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: test.config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: test.config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: test.session_configured.model.clone(),
|
||||
effort: None,
|
||||
|
||||
@@ -1583,7 +1583,9 @@ allow_local_binding = true
|
||||
.enable(Feature::CodexHooks)
|
||||
.expect("test config should allow feature update");
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
let layers = config
|
||||
.config_layer_stack
|
||||
.get_layers(
|
||||
|
||||
@@ -1110,8 +1110,9 @@ async fn handle_container_exec_autoapprove_from_config_records_tool_decision() {
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_config(|config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
config.permissions.sandbox_policy =
|
||||
Constrained::allow_any(SandboxPolicy::DangerFullAccess);
|
||||
config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess)
|
||||
.expect("set sandbox policy");
|
||||
})
|
||||
.build(&server)
|
||||
.await
|
||||
|
||||
@@ -825,7 +825,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.permissions.sandbox_policy.get();
|
||||
let default_sandbox_policy = &config.legacy_sandbox_policy();
|
||||
let default_model = session_configured.model;
|
||||
let default_effort = config.model_reasoning_effort;
|
||||
let default_summary = config.model_reasoning_summary;
|
||||
@@ -955,7 +955,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.permissions.sandbox_policy.get();
|
||||
let default_sandbox_policy = &config.legacy_sandbox_policy();
|
||||
let default_model = session_configured.model;
|
||||
let default_effort = config.model_reasoning_effort;
|
||||
let default_summary = config.model_reasoning_summary;
|
||||
|
||||
@@ -162,7 +162,7 @@ async fn remote_models_config_context_window_override_clamps_to_max_context_wind
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
@@ -240,7 +240,7 @@ async fn remote_models_config_override_above_max_uses_max_context_window() -> Re
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
@@ -317,7 +317,7 @@ async fn remote_models_use_context_window_when_config_override_is_absent() -> Re
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
@@ -407,7 +407,7 @@ async fn remote_models_long_model_slug_is_sent_with_high_reasoning() -> Result<(
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
@@ -468,7 +468,7 @@ async fn namespaced_model_slug_uses_catalog_metadata_without_fallback_warning()
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
|
||||
@@ -324,7 +324,9 @@ async fn with_additional_permissions_requires_approval_under_on_request() -> Res
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -419,7 +421,9 @@ async fn request_permissions_tool_is_auto_denied_when_granular_request_permissio
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::RequestPermissionsTool)
|
||||
@@ -502,7 +506,9 @@ async fn relative_additional_permissions_resolve_against_tool_workdir() -> Resul
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -603,7 +609,9 @@ async fn read_only_with_additional_permissions_does_not_widen_to_unrequested_cwd
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -703,7 +711,9 @@ async fn read_only_with_additional_permissions_does_not_widen_to_unrequested_tmp
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -802,7 +812,9 @@ async fn workspace_write_with_additional_permissions_can_write_outside_cwd() ->
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -906,7 +918,9 @@ async fn with_additional_permissions_denied_approval_blocks_execution() -> Resul
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1011,7 +1025,9 @@ async fn request_permissions_grants_apply_to_later_exec_command_calls() -> Resul
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1135,7 +1151,9 @@ async fn request_permissions_preapprove_explicit_exec_permissions_outside_on_req
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1253,7 +1271,9 @@ async fn request_permissions_grants_apply_to_later_shell_command_calls() -> Resu
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1365,7 +1385,9 @@ async fn request_permissions_grants_apply_to_later_shell_command_calls_without_i
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::RequestPermissionsTool)
|
||||
@@ -1477,7 +1499,9 @@ async fn partial_request_permissions_grants_do_not_preapprove_new_permissions()
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1641,7 +1665,9 @@ async fn request_permissions_grants_do_not_carry_across_turns() -> Result<()> {
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -1754,7 +1780,9 @@ async fn request_permissions_session_grants_carry_across_turns() -> Result<()> {
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
|
||||
@@ -204,7 +204,9 @@ async fn approved_folder_write_request_permissions_unblocks_later_exec_without_s
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
@@ -334,7 +336,9 @@ async fn apply_patch_after_request_permissions(strict_auto_review: bool) -> Resu
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
|
||||
@@ -32,7 +32,7 @@ fn resume_history(
|
||||
current_date: None,
|
||||
timezone: None,
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
sandbox_policy: config.legacy_sandbox_policy(),
|
||||
permission_profile: None,
|
||||
network: None,
|
||||
file_system_sandbox_policy: None,
|
||||
|
||||
@@ -552,7 +552,9 @@ async fn shell_enforces_glob_deny_read_policy() -> Result<()> {
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_config(move |config| {
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(read_only_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(read_only_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
let mut file_system_sandbox_policy = FileSystemSandboxPolicy::default();
|
||||
file_system_sandbox_policy
|
||||
.entries
|
||||
@@ -789,9 +791,7 @@ async fn shell_timeout_handles_background_grandchild_stdout() -> Result<()> {
|
||||
let server = start_mock_server().await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
config
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.set(SandboxPolicy::DangerFullAccess)
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
@@ -885,9 +885,7 @@ async fn shell_spawn_failure_truncates_exec_error() -> Result<()> {
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let mut builder = test_codex().with_config(|cfg| {
|
||||
cfg.permissions
|
||||
.sandbox_policy
|
||||
.set(SandboxPolicy::DangerFullAccess)
|
||||
cfg.set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess)
|
||||
.expect("set sandbox policy");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
@@ -2545,7 +2545,9 @@ async fn unified_exec_enforces_glob_deny_read_policy() -> Result<()> {
|
||||
.features
|
||||
.enable(Feature::UnifiedExec)
|
||||
.expect("test config should allow feature update");
|
||||
config.permissions.sandbox_policy = Constrained::allow_any(read_only_policy_for_config);
|
||||
config
|
||||
.set_legacy_sandbox_policy(read_only_policy_for_config)
|
||||
.expect("set sandbox policy");
|
||||
let mut file_system_sandbox_policy = FileSystemSandboxPolicy::default();
|
||||
file_system_sandbox_policy
|
||||
.entries
|
||||
|
||||
@@ -1634,11 +1634,7 @@ async fn update_feature_flags_enabling_guardian_selects_auto_review() -> Result<
|
||||
auto_review.approval_policy
|
||||
);
|
||||
assert_eq!(
|
||||
app.chat_widget
|
||||
.config_ref()
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.get(),
|
||||
&app.chat_widget.config_ref().legacy_sandbox_policy(),
|
||||
&auto_review.sandbox_policy
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -1714,9 +1710,7 @@ async fn update_feature_flags_disabling_guardian_clears_review_policy_and_restor
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)?;
|
||||
app.config
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.set(SandboxPolicy::new_workspace_write_policy())?;
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())?;
|
||||
app.chat_widget
|
||||
.set_approval_policy(AskForApproval::OnRequest);
|
||||
app.chat_widget
|
||||
@@ -1815,11 +1809,7 @@ async fn update_feature_flags_enabling_guardian_overrides_explicit_manual_review
|
||||
auto_review.approval_policy
|
||||
);
|
||||
assert_eq!(
|
||||
app.chat_widget
|
||||
.config_ref()
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.get(),
|
||||
&app.chat_widget.config_ref().legacy_sandbox_policy(),
|
||||
&auto_review.sandbox_policy
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -2933,7 +2923,7 @@ async fn side_fork_config_is_ephemeral_and_appends_developer_guardrails() {
|
||||
let mut app = make_test_app().await;
|
||||
app.config.developer_instructions = Some("Existing developer policy.".to_string());
|
||||
let original_approval_policy = app.config.permissions.approval_policy.value();
|
||||
let original_sandbox_policy = app.config.permissions.sandbox_policy.get().clone();
|
||||
let original_sandbox_policy = app.config.legacy_sandbox_policy();
|
||||
|
||||
let fork_config = app.side_fork_config();
|
||||
|
||||
@@ -2942,10 +2932,7 @@ async fn side_fork_config_is_ephemeral_and_appends_developer_guardrails() {
|
||||
fork_config.permissions.approval_policy.value(),
|
||||
original_approval_policy
|
||||
);
|
||||
assert_eq!(
|
||||
fork_config.permissions.sandbox_policy.get(),
|
||||
&original_sandbox_policy
|
||||
);
|
||||
assert_eq!(fork_config.legacy_sandbox_policy(), original_sandbox_policy);
|
||||
let developer_instructions = fork_config
|
||||
.developer_instructions
|
||||
.as_deref()
|
||||
|
||||
@@ -192,9 +192,8 @@ mod tests {
|
||||
.set_sandbox_policy(expected_sandbox_policy.clone())
|
||||
.expect("set widget sandbox policy");
|
||||
app.config
|
||||
.permissions
|
||||
.set_legacy_sandbox_policy(expected_sandbox_policy.clone(), app.config.cwd.as_path())
|
||||
.expect("set app sandbox policy");
|
||||
.set_legacy_sandbox_policy(expected_sandbox_policy.clone())
|
||||
.expect("set sandbox policy");
|
||||
|
||||
app.sync_active_thread_permission_settings_to_cached_session()
|
||||
.await;
|
||||
|
||||
@@ -141,8 +141,12 @@ use codex_protocol::items::AgentMessageContent;
|
||||
use codex_protocol::items::AgentMessageItem;
|
||||
use codex_protocol::items::UserMessageItem;
|
||||
use codex_protocol::models::MessagePhase;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::SandboxEnforcement;
|
||||
use codex_protocol::models::local_image_label_text;
|
||||
use codex_protocol::parse_command::ParsedCommand;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::plan_tool::PlanItemArg as UpdatePlanItemArg;
|
||||
use codex_protocol::plan_tool::StepStatus as UpdatePlanItemStatus;
|
||||
#[cfg(test)]
|
||||
@@ -2376,7 +2380,7 @@ impl ChatWidget {
|
||||
Some(permission_profile) => self
|
||||
.config
|
||||
.permissions
|
||||
.set_permission_profile(permission_profile, event.cwd.as_path()),
|
||||
.set_permission_profile(permission_profile),
|
||||
None => self
|
||||
.config
|
||||
.permissions
|
||||
@@ -2384,11 +2388,16 @@ impl ChatWidget {
|
||||
};
|
||||
if let Err(err) = permission_sync {
|
||||
tracing::warn!(%err, "failed to sync permissions from SessionConfigured");
|
||||
self.config.permissions.sandbox_policy =
|
||||
Constrained::allow_only(event.sandbox_policy.clone());
|
||||
let permission_profile = event.permission_profile.clone().unwrap_or_else(|| {
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&event.sandbox_policy,
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&event.sandbox_policy,
|
||||
event.cwd.as_path(),
|
||||
);
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&event.sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::from(&event.sandbox_policy),
|
||||
)
|
||||
});
|
||||
self.config.permissions.permission_profile =
|
||||
|
||||
@@ -252,9 +252,7 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
.set(AskForApproval::OnRequest)
|
||||
.expect("set approval policy");
|
||||
chat.config
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.set(SandboxPolicy::new_workspace_write_policy())
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())
|
||||
.expect("set sandbox policy");
|
||||
chat.config.cwd = test_path_buf("/home/user/main").abs();
|
||||
|
||||
@@ -312,7 +310,7 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
AskForApproval::Never
|
||||
);
|
||||
assert_eq!(
|
||||
chat.config_ref().permissions.sandbox_policy.get(),
|
||||
&chat.config_ref().legacy_sandbox_policy(),
|
||||
&expected_sandbox
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -374,7 +372,7 @@ async fn session_configured_external_sandbox_keeps_external_runtime_policy() {
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
chat.config_ref().permissions.sandbox_policy.get(),
|
||||
&chat.config_ref().legacy_sandbox_policy(),
|
||||
&expected_sandbox
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn set_legacy_sandbox_policy(chat: &mut ChatWidget, sandbox_policy: SandboxPolicy) {
|
||||
chat.config
|
||||
.permissions
|
||||
.set_legacy_sandbox_policy(sandbox_policy, chat.config.cwd.as_path())
|
||||
.expect("set sandbox policy");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn approvals_selection_popup_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
@@ -354,7 +347,9 @@ async fn permissions_selection_history_snapshot_full_access_to_default() {
|
||||
.approval_policy
|
||||
.set(AskForApproval::Never)
|
||||
.expect("set approval policy");
|
||||
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::DangerFullAccess);
|
||||
chat.config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::DangerFullAccess)
|
||||
.expect("set sandbox policy");
|
||||
|
||||
chat.open_permissions_popup();
|
||||
let popup = render_bottom_popup(&chat, /*width*/ 120);
|
||||
@@ -393,7 +388,9 @@ async fn permissions_selection_emits_history_cell_when_current_is_selected() {
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
.expect("set approval policy");
|
||||
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
|
||||
chat.config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())
|
||||
.expect("set sandbox policy");
|
||||
|
||||
chat.open_permissions_popup();
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
@@ -448,7 +445,9 @@ async fn permissions_selection_hides_auto_review_when_feature_disabled_even_if_a
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
.expect("set approval policy");
|
||||
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
|
||||
chat.config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())
|
||||
.expect("set sandbox policy");
|
||||
|
||||
chat.open_permissions_popup();
|
||||
let popup = render_bottom_popup(&chat, /*width*/ 120);
|
||||
@@ -573,7 +572,9 @@ async fn permissions_selection_can_disable_auto_review() {
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
.expect("set approval policy");
|
||||
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
|
||||
chat.config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())
|
||||
.expect("set sandbox policy");
|
||||
|
||||
chat.open_permissions_popup();
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Up));
|
||||
@@ -610,7 +611,9 @@ async fn permissions_selection_sends_approvals_reviewer_in_override_turn_context
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
.expect("set approval policy");
|
||||
set_legacy_sandbox_policy(&mut chat, SandboxPolicy::new_workspace_write_policy());
|
||||
chat.config
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::new_workspace_write_policy())
|
||||
.expect("set sandbox policy");
|
||||
chat.set_approvals_reviewer(ApprovalsReviewer::User);
|
||||
|
||||
chat.open_permissions_popup();
|
||||
|
||||
@@ -99,16 +99,12 @@ async fn status_snapshot_includes_reasoning_details() {
|
||||
config.model_reasoning_summary = Some(ReasoningSummary::Detailed);
|
||||
config.cwd = test_path_buf("/workspace/tests").abs();
|
||||
config
|
||||
.permissions
|
||||
.set_legacy_sandbox_policy(
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
},
|
||||
config.cwd.as_path(),
|
||||
)
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
})
|
||||
.expect("set sandbox policy");
|
||||
|
||||
let account_display = test_status_account_display();
|
||||
@@ -185,16 +181,12 @@ async fn status_permissions_non_default_workspace_write_is_custom() {
|
||||
.expect("set approval policy");
|
||||
config.cwd = test_path_buf("/workspace/tests").abs();
|
||||
config
|
||||
.permissions
|
||||
.set_legacy_sandbox_policy(
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
},
|
||||
config.cwd.as_path(),
|
||||
)
|
||||
.set_legacy_sandbox_policy(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
})
|
||||
.expect("set sandbox policy");
|
||||
|
||||
let account_display = test_status_account_display();
|
||||
|
||||
Reference in New Issue
Block a user