Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Bolin
0fc2a7b068 tests: submit websocket turns with permission profiles 2026-04-30 03:08:22 -07:00
Michael Bolin
4f646e0aca tests: use permission profiles in exec policy checks 2026-04-30 03:04:35 -07:00
3 changed files with 50 additions and 107 deletions

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,

View File

@@ -630,15 +630,6 @@ impl TestCodex {
.await
}
pub async fn submit_turn_with_policy(
&self,
prompt: &str,
sandbox_policy: SandboxPolicy,
) -> Result<()> {
self.submit_turn_with_policies(prompt, AskForApproval::Never, sandbox_policy)
.await
}
pub async fn submit_turn_with_service_tier(
&self,
prompt: &str,
@@ -654,26 +645,6 @@ impl TestCodex {
.await
}
pub async fn submit_turn_with_policies(
&self,
prompt: &str,
approval_policy: AskForApproval,
sandbox_policy: SandboxPolicy,
) -> Result<()> {
let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd(
&sandbox_policy,
self.config.cwd.as_path(),
);
self.submit_turn_with_context(
prompt,
approval_policy,
permission_profile,
/*service_tier*/ None,
/*environments*/ None,
)
.await
}
pub async fn submit_turn_with_approval_and_permission_profile(
&self,
prompt: &str,
@@ -896,16 +867,6 @@ impl TestCodexHarness {
Box::pin(self.test.submit_turn(prompt)).await
}
pub async fn submit_with_policy(
&self,
prompt: &str,
sandbox_policy: SandboxPolicy,
) -> Result<()> {
self.test
.submit_turn_with_policy(prompt, sandbox_policy)
.await
}
pub async fn submit_with_permission_profile(
&self,
prompt: &str,

View File

@@ -38,8 +38,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.permission_profile(),
)
.await?;
let connection = server.single_connection();
assert_eq!(connection.len(), 2);
@@ -82,7 +85,7 @@ 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.legacy_sandbox_policy())
test.submit_turn_with_permission_profile("hello", test.config.permissions.permission_profile())
.await?;
assert_eq!(server.handshakes().len(), 1);
@@ -129,7 +132,7 @@ 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())
test.submit_turn_with_permission_profile("hello", test.config.permissions.permission_profile())
.await?;
assert_eq!(server.handshakes().len(), 1);
@@ -182,8 +185,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.permission_profile(),
)
.await?;
let connection = server.single_connection();
assert_eq!(connection.len(), 3);