Merge 4f646e0aca into sapling-pr-archive-bolinfest

This commit is contained in:
Michael Bolin
2026-04-30 03:04:45 -07:00
committed by GitHub

View File

@@ -23,7 +23,6 @@ use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::GranularApprovalConfig;
use codex_protocol::protocol::SandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
use std::fs;
@@ -126,10 +125,6 @@ fn external_file_system_sandbox_policy() -> FileSystemSandboxPolicy {
FileSystemSandboxPolicy::external_sandbox()
}
fn permission_profile_from_sandbox_policy(sandbox_policy: &SandboxPolicy) -> PermissionProfile {
PermissionProfile::from_legacy_sandbox_policy(sandbox_policy)
}
async fn test_config() -> (TempDir, Config) {
let home = TempDir::new().expect("create temp dir");
let config = ConfigBuilder::without_managed_config_for_tests()
@@ -644,7 +639,7 @@ async fn evaluates_bash_lc_inner_commands() {
"rm -rf /some/important/folder".to_string(),
],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -726,7 +721,7 @@ async fn evaluates_heredoc_script_against_prefix_rules() {
policy_src: Some(r#"prefix_rule(pattern=["python3"], decision="allow")"#.to_string()),
command,
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -750,7 +745,7 @@ async fn omits_auto_amendment_for_heredoc_fallback_prompts() {
"python3 <<'PY'\nprint('hello')\nPY".to_string(),
],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -774,7 +769,7 @@ async fn drops_requested_amendment_for_heredoc_fallback_prompts_when_it_wont_mat
"python3 <<'PY'\nprint('hello')\nPY".to_string(),
],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: Some(vec![
@@ -811,7 +806,7 @@ prefix_rule(
"/some/important/folder".to_string(),
],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -830,7 +825,7 @@ async fn exec_approval_requirement_prefers_execpolicy_match() {
policy_src: Some(r#"prefix_rule(pattern=["rm"], decision="prompt")"#.to_string()),
command: vec!["rm".to_string()],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -858,7 +853,7 @@ prefix_rule(pattern=["git"], decision="allow")
policy_src: Some(policy_src),
command: vec![git_path, "status".to_string()],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -892,7 +887,7 @@ prefix_rule(pattern=["git"], decision="prompt")
policy_src: Some(policy_src),
command: vec![disallowed_git_path.clone(), "status".to_string()],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -919,7 +914,7 @@ async fn requested_prefix_rule_can_approve_absolute_path_commands() {
"cargo-insta".to_string(),
],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: Some(vec!["cargo".to_string(), "install".to_string()]),
@@ -942,7 +937,7 @@ async fn exec_approval_requirement_respects_approval_policy() {
policy_src: Some(r#"prefix_rule(pattern=["rm"], decision="prompt")"#.to_string()),
command: vec!["rm".to_string()],
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -968,7 +963,7 @@ fn unmatched_granular_policy_still_prompts_for_restricted_sandbox_escalation() {
request_permissions: true,
mcp_elicitations: true,
}),
&permission_profile_from_sandbox_policy(&SandboxPolicy::new_read_only_policy()),
&PermissionProfile::read_only(),
&read_only_file_system_sandbox_policy(),
Path::new("/tmp"),
&command,
@@ -1067,7 +1062,7 @@ async fn exec_approval_requirement_prompts_for_inline_additional_permissions_und
"touch requested-dir/requested-but-unused.txt".to_string(),
],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::WithAdditionalPermissions,
prefix_rule: None,
@@ -1097,7 +1092,7 @@ async fn exec_approval_requirement_rejects_unmatched_sandbox_escalation_when_gra
request_permissions: true,
mcp_elicitations: true,
}),
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::RequireEscalated,
prefix_rule: None,
@@ -1133,9 +1128,7 @@ async fn mixed_rule_and_sandbox_prompt_prioritizes_rule_for_rejection_decision()
request_permissions: true,
mcp_elicitations: true,
}),
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::RequireEscalated,
@@ -1173,9 +1166,7 @@ async fn mixed_rule_and_sandbox_prompt_rejects_when_granular_rules_are_disabled(
request_permissions: true,
mcp_elicitations: true,
}),
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::RequireEscalated,
@@ -1200,9 +1191,7 @@ async fn exec_approval_requirement_falls_back_to_heuristics() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &command,
approval_policy: AskForApproval::UnlessTrusted,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::UseDefault,
@@ -1228,9 +1217,7 @@ async fn empty_bash_lc_script_falls_back_to_original_command() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &command,
approval_policy: AskForApproval::UnlessTrusted,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::UseDefault,
@@ -1260,9 +1247,7 @@ async fn whitespace_bash_lc_script_falls_back_to_original_command() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &command,
approval_policy: AskForApproval::UnlessTrusted,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::UseDefault,
@@ -1292,9 +1277,7 @@ async fn request_rule_uses_prefix_rule() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &command,
approval_policy: AskForApproval::OnRequest,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: SandboxPermissions::RequireEscalated,
@@ -1443,7 +1426,7 @@ async fn proposed_execpolicy_amendment_is_present_for_single_command_without_pol
policy_src: None,
command: command.clone(),
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1463,7 +1446,7 @@ async fn proposed_execpolicy_amendment_is_omitted_when_policy_prompts() {
policy_src: Some(r#"prefix_rule(pattern=["rm"], decision="prompt")"#.to_string()),
command: vec!["rm".to_string()],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1487,7 +1470,7 @@ async fn proposed_execpolicy_amendment_is_present_for_multi_command_scripts() {
"cargo build && echo ok".to_string(),
],
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1517,7 +1500,7 @@ async fn proposed_execpolicy_amendment_uses_first_no_match_in_multi_command_scri
policy_src: Some(policy_src.to_string()),
command,
approval_policy: AskForApproval::UnlessTrusted,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1541,7 +1524,7 @@ async fn proposed_execpolicy_amendment_is_present_when_heuristics_allow() {
policy_src: None,
command: command.clone(),
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1561,7 +1544,7 @@ async fn proposed_execpolicy_amendment_is_suppressed_when_policy_matches_allow()
policy_src: Some(r#"prefix_rule(pattern=["echo"], decision="allow")"#.to_string()),
command: vec!["echo".to_string(), "safe".to_string()],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1592,7 +1575,7 @@ prefix_rule(pattern=["cat"], decision="allow")
policy_src: Some(policy_src.to_string()),
command: command.clone(),
approval_policy,
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
permission_profile: PermissionProfile::workspace_write(),
file_system_sandbox_policy: workspace_write_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1624,7 +1607,7 @@ prefix_rule(pattern=["bash"], decision="allow")
.to_string(),
],
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: read_only_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1790,7 +1773,7 @@ async fn dangerous_rm_rf_requires_approval_in_danger_full_access() {
policy_src: None,
command: command.clone(),
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::DangerFullAccess,
permission_profile: PermissionProfile::Disabled,
file_system_sandbox_policy: unrestricted_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
prefix_rule: None,
@@ -1831,7 +1814,7 @@ async fn verify_approval_requirement_for_unsafe_powershell_command() {
])));
let (pwsh_approval_reason, expected_req) = if cfg!(windows) {
(
r#"On Windows, SandboxPolicy::ReadOnly should be assumed to mean
r#"On Windows, a read-only permission profile should be assumed to mean
that no sandbox is present, so anything that is not "provably
safe" should require approval."#,
ExecApprovalRequirement::NeedsApproval {
@@ -1854,9 +1837,7 @@ async fn verify_approval_requirement_for_unsafe_powershell_command() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &sneaky_command,
approval_policy: AskForApproval::OnRequest,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: permissions,
@@ -1881,9 +1862,7 @@ async fn verify_approval_requirement_for_unsafe_powershell_command() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &dangerous_command,
approval_policy: AskForApproval::OnRequest,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: permissions,
@@ -1904,9 +1883,7 @@ async fn verify_approval_requirement_for_unsafe_powershell_command() {
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &dangerous_command,
approval_policy: AskForApproval::Never,
permission_profile: permission_profile_from_sandbox_policy(
&SandboxPolicy::new_read_only_policy(),
),
permission_profile: PermissionProfile::read_only(),
file_system_sandbox_policy: &read_only_file_system_sandbox_policy(),
sandbox_cwd: Path::new("/tmp"),
sandbox_permissions: permissions,
@@ -1926,8 +1903,8 @@ async fn dangerous_command_allowed_when_sandbox_is_explicitly_disabled() {
policy_src: None,
command,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::ExternalSandbox {
network_access: Default::default(),
permission_profile: PermissionProfile::External {
network: NetworkSandboxPolicy::Restricted,
},
file_system_sandbox_policy: external_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
@@ -1951,8 +1928,8 @@ async fn dangerous_command_forbidden_in_external_sandbox_when_policy_matches() {
policy_src: Some("prefix_rule(pattern=['rm'], decision='prompt')".to_string()),
command,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::ExternalSandbox {
network_access: Default::default(),
permission_profile: PermissionProfile::External {
network: NetworkSandboxPolicy::Restricted,
},
file_system_sandbox_policy: external_file_system_sandbox_policy(),
sandbox_permissions: SandboxPermissions::UseDefault,
@@ -1970,7 +1947,7 @@ struct ExecApprovalRequirementScenario {
policy_src: Option<String>,
command: Vec<String>,
approval_policy: AskForApproval,
sandbox_policy: SandboxPolicy,
permission_profile: PermissionProfile,
file_system_sandbox_policy: FileSystemSandboxPolicy,
sandbox_permissions: SandboxPermissions,
prefix_rule: Option<Vec<String>>,
@@ -1984,7 +1961,7 @@ async fn assert_exec_approval_requirement_for_command(
policy_src,
command,
approval_policy,
sandbox_policy,
permission_profile,
file_system_sandbox_policy,
sandbox_permissions,
prefix_rule,
@@ -2001,7 +1978,6 @@ async fn assert_exec_approval_requirement_for_command(
None => Arc::new(Policy::empty()),
};
let permission_profile = permission_profile_from_sandbox_policy(&sandbox_policy);
let requirement = ExecPolicyManager::new(policy)
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
command: &command,