@@ -799,327 +799,5 @@ fn join_program_and_argv(program: &AbsolutePathBuf, argv: &[String]) -> Vec<Stri
799799}
800800
801801#[ cfg( test) ]
802- mod tests {
803- use super :: CoreShellActionProvider ;
804- #[ cfg( target_os = "macos" ) ]
805- use super :: CoreShellCommandExecutor ;
806- use super :: ParsedShellCommand ;
807- use super :: extract_shell_script;
808- use super :: join_program_and_argv;
809- use super :: map_exec_result;
810- #[ cfg( target_os = "macos" ) ]
811- use crate :: config:: Constrained ;
812- #[ cfg( target_os = "macos" ) ]
813- use crate :: config:: Permissions ;
814- #[ cfg( target_os = "macos" ) ]
815- use crate :: config:: types:: ShellEnvironmentPolicy ;
816- use crate :: exec:: SandboxType ;
817- #[ cfg( target_os = "macos" ) ]
818- use crate :: protocol:: AskForApproval ;
819- use crate :: protocol:: ReadOnlyAccess ;
820- use crate :: protocol:: SandboxPolicy ;
821- #[ cfg( target_os = "macos" ) ]
822- use crate :: sandboxing:: SandboxPermissions ;
823- #[ cfg( target_os = "macos" ) ]
824- use crate :: seatbelt:: MACOS_PATH_TO_SEATBELT_EXECUTABLE ;
825- #[ cfg( target_os = "macos" ) ]
826- use codex_protocol:: config_types:: WindowsSandboxLevel ;
827- use codex_protocol:: models:: FileSystemPermissions ;
828- use codex_protocol:: models:: MacOsPreferencesPermission ;
829- use codex_protocol:: models:: MacOsSeatbeltProfileExtensions ;
830- use codex_protocol:: models:: PermissionProfile ;
831- use codex_shell_escalation:: EscalationExecution ;
832- use codex_shell_escalation:: EscalationPermissions ;
833- use codex_shell_escalation:: ExecResult ;
834- use codex_shell_escalation:: Permissions as EscalatedPermissions ;
835- #[ cfg( target_os = "macos" ) ]
836- use codex_shell_escalation:: ShellCommandExecutor ;
837- use codex_utils_absolute_path:: AbsolutePathBuf ;
838- use pretty_assertions:: assert_eq;
839- #[ cfg( target_os = "macos" ) ]
840- use std:: collections:: HashMap ;
841- use std:: path:: PathBuf ;
842- use std:: time:: Duration ;
843-
844- #[ test]
845- fn extract_shell_script_preserves_login_flag ( ) {
846- assert_eq ! (
847- extract_shell_script( & [ "/bin/zsh" . into( ) , "-lc" . into( ) , "echo hi" . into( ) ] ) . unwrap( ) ,
848- ParsedShellCommand {
849- script: "echo hi" . to_string( ) ,
850- login: true ,
851- }
852- ) ;
853- assert_eq ! (
854- extract_shell_script( & [ "/bin/zsh" . into( ) , "-c" . into( ) , "echo hi" . into( ) ] ) . unwrap( ) ,
855- ParsedShellCommand {
856- script: "echo hi" . to_string( ) ,
857- login: false ,
858- }
859- ) ;
860- }
861-
862- #[ test]
863- fn extract_shell_script_supports_wrapped_command_prefixes ( ) {
864- assert_eq ! (
865- extract_shell_script( & [
866- "/usr/bin/env" . into( ) ,
867- "CODEX_EXECVE_WRAPPER=1" . into( ) ,
868- "/bin/zsh" . into( ) ,
869- "-lc" . into( ) ,
870- "echo hello" . into( )
871- ] )
872- . unwrap( ) ,
873- ParsedShellCommand {
874- script: "echo hello" . to_string( ) ,
875- login: true ,
876- }
877- ) ;
878-
879- assert_eq ! (
880- extract_shell_script( & [
881- "sandbox-exec" . into( ) ,
882- "-p" . into( ) ,
883- "sandbox_policy" . into( ) ,
884- "/bin/zsh" . into( ) ,
885- "-c" . into( ) ,
886- "pwd" . into( ) ,
887- ] )
888- . unwrap( ) ,
889- ParsedShellCommand {
890- script: "pwd" . to_string( ) ,
891- login: false ,
892- }
893- ) ;
894- }
895-
896- #[ test]
897- fn extract_shell_script_rejects_unsupported_shell_invocation ( ) {
898- let err = extract_shell_script ( & [
899- "sandbox-exec" . into ( ) ,
900- "-fc" . into ( ) ,
901- "echo not supported" . into ( ) ,
902- ] )
903- . unwrap_err ( ) ;
904- assert ! ( matches!( err, super :: ToolError :: Rejected ( _) ) ) ;
905- assert_eq ! (
906- match err {
907- super :: ToolError :: Rejected ( reason) => reason,
908- _ => "" . to_string( ) ,
909- } ,
910- "unexpected shell command format for zsh-fork execution"
911- ) ;
912- }
913-
914- #[ test]
915- fn join_program_and_argv_replaces_original_argv_zero ( ) {
916- assert_eq ! (
917- join_program_and_argv(
918- & AbsolutePathBuf :: from_absolute_path( "/tmp/tool" ) . unwrap( ) ,
919- & [ "./tool" . into( ) , "--flag" . into( ) , "value" . into( ) ] ,
920- ) ,
921- vec![ "/tmp/tool" , "--flag" , "value" ]
922- ) ;
923- assert_eq ! (
924- join_program_and_argv(
925- & AbsolutePathBuf :: from_absolute_path( "/tmp/tool" ) . unwrap( ) ,
926- & [ "./tool" . into( ) ]
927- ) ,
928- vec![ "/tmp/tool" ]
929- ) ;
930- }
931-
932- #[ test]
933- fn map_exec_result_preserves_stdout_and_stderr ( ) {
934- let out = map_exec_result (
935- SandboxType :: None ,
936- ExecResult {
937- exit_code : 0 ,
938- stdout : "out" . to_string ( ) ,
939- stderr : "err" . to_string ( ) ,
940- output : "outerr" . to_string ( ) ,
941- duration : Duration :: from_millis ( 1 ) ,
942- timed_out : false ,
943- } ,
944- )
945- . unwrap ( ) ;
946-
947- assert_eq ! ( out. stdout. text, "out" ) ;
948- assert_eq ! ( out. stderr. text, "err" ) ;
949- assert_eq ! ( out. aggregated_output. text, "outerr" ) ;
950- }
951-
952- #[ test]
953- fn shell_request_escalation_execution_is_explicit ( ) {
954- let requested_permissions = PermissionProfile {
955- file_system : Some ( FileSystemPermissions {
956- read : None ,
957- write : Some ( vec ! [ PathBuf :: from( "./output" ) ] ) ,
958- } ) ,
959- ..Default :: default ( )
960- } ;
961- let sandbox_policy = SandboxPolicy :: WorkspaceWrite {
962- writable_roots : vec ! [
963- AbsolutePathBuf :: from_absolute_path( "/tmp/original/output" ) . unwrap( ) ,
964- ] ,
965- read_only_access : ReadOnlyAccess :: FullAccess ,
966- network_access : false ,
967- exclude_tmpdir_env_var : false ,
968- exclude_slash_tmp : false ,
969- } ;
970- let macos_seatbelt_profile_extensions = MacOsSeatbeltProfileExtensions {
971- macos_preferences : MacOsPreferencesPermission :: ReadWrite ,
972- ..Default :: default ( )
973- } ;
974-
975- assert_eq ! (
976- CoreShellActionProvider :: shell_request_escalation_execution(
977- crate :: sandboxing:: SandboxPermissions :: UseDefault ,
978- & sandbox_policy,
979- None ,
980- Some ( & macos_seatbelt_profile_extensions) ,
981- ) ,
982- EscalationExecution :: TurnDefault ,
983- ) ;
984- assert_eq ! (
985- CoreShellActionProvider :: shell_request_escalation_execution(
986- crate :: sandboxing:: SandboxPermissions :: RequireEscalated ,
987- & sandbox_policy,
988- None ,
989- Some ( & macos_seatbelt_profile_extensions) ,
990- ) ,
991- EscalationExecution :: Unsandboxed ,
992- ) ;
993- assert_eq ! (
994- CoreShellActionProvider :: shell_request_escalation_execution(
995- crate :: sandboxing:: SandboxPermissions :: WithAdditionalPermissions ,
996- & sandbox_policy,
997- Some ( & requested_permissions) ,
998- Some ( & macos_seatbelt_profile_extensions) ,
999- ) ,
1000- EscalationExecution :: Permissions ( EscalationPermissions :: Permissions (
1001- EscalatedPermissions {
1002- sandbox_policy,
1003- macos_seatbelt_profile_extensions: Some ( macos_seatbelt_profile_extensions) ,
1004- } ,
1005- ) ) ,
1006- ) ;
1007- }
1008-
1009- #[ cfg( target_os = "macos" ) ]
1010- #[ tokio:: test]
1011- async fn prepare_escalated_exec_turn_default_preserves_macos_seatbelt_extensions ( ) {
1012- let cwd = AbsolutePathBuf :: from_absolute_path ( std:: env:: temp_dir ( ) ) . unwrap ( ) ;
1013- let executor = CoreShellCommandExecutor {
1014- command : vec ! [ "echo" . to_string( ) , "ok" . to_string( ) ] ,
1015- cwd : cwd. to_path_buf ( ) ,
1016- env : HashMap :: new ( ) ,
1017- network : None ,
1018- sandbox : SandboxType :: None ,
1019- sandbox_policy : SandboxPolicy :: new_read_only_policy ( ) ,
1020- windows_sandbox_level : WindowsSandboxLevel :: Disabled ,
1021- sandbox_permissions : SandboxPermissions :: UseDefault ,
1022- justification : None ,
1023- arg0 : None ,
1024- sandbox_policy_cwd : cwd. to_path_buf ( ) ,
1025- macos_seatbelt_profile_extensions : Some ( MacOsSeatbeltProfileExtensions {
1026- macos_preferences : MacOsPreferencesPermission :: ReadWrite ,
1027- ..Default :: default ( )
1028- } ) ,
1029- codex_linux_sandbox_exe : None ,
1030- use_linux_sandbox_bwrap : false ,
1031- } ;
1032-
1033- let prepared = executor
1034- . prepare_escalated_exec (
1035- & AbsolutePathBuf :: from_absolute_path ( "/bin/echo" ) . unwrap ( ) ,
1036- & [ "echo" . to_string ( ) , "ok" . to_string ( ) ] ,
1037- & cwd,
1038- HashMap :: new ( ) ,
1039- EscalationExecution :: TurnDefault ,
1040- )
1041- . await
1042- . unwrap ( ) ;
1043-
1044- assert_eq ! (
1045- prepared. command. first( ) . map( String :: as_str) ,
1046- Some ( MACOS_PATH_TO_SEATBELT_EXECUTABLE )
1047- ) ;
1048- assert_eq ! ( prepared. command. get( 1 ) . map( String :: as_str) , Some ( "-p" ) ) ;
1049- assert ! (
1050- prepared
1051- . command
1052- . get( 2 )
1053- . is_some_and( |policy| policy. contains( "(allow user-preference-write)" ) ) ,
1054- "expected seatbelt policy to include macOS extension profile: {:?}" ,
1055- prepared. command
1056- ) ;
1057- }
1058-
1059- #[ cfg( target_os = "macos" ) ]
1060- #[ tokio:: test]
1061- async fn prepare_escalated_exec_permissions_preserve_macos_seatbelt_extensions ( ) {
1062- let cwd = AbsolutePathBuf :: from_absolute_path ( std:: env:: temp_dir ( ) ) . unwrap ( ) ;
1063- let executor = CoreShellCommandExecutor {
1064- command : vec ! [ "echo" . to_string( ) , "ok" . to_string( ) ] ,
1065- cwd : cwd. to_path_buf ( ) ,
1066- env : HashMap :: new ( ) ,
1067- network : None ,
1068- sandbox : SandboxType :: None ,
1069- sandbox_policy : SandboxPolicy :: DangerFullAccess ,
1070- windows_sandbox_level : WindowsSandboxLevel :: Disabled ,
1071- sandbox_permissions : SandboxPermissions :: UseDefault ,
1072- justification : None ,
1073- arg0 : None ,
1074- sandbox_policy_cwd : cwd. to_path_buf ( ) ,
1075- macos_seatbelt_profile_extensions : None ,
1076- codex_linux_sandbox_exe : None ,
1077- use_linux_sandbox_bwrap : false ,
1078- } ;
1079-
1080- let permissions = Permissions {
1081- approval_policy : Constrained :: allow_any ( AskForApproval :: Never ) ,
1082- sandbox_policy : Constrained :: allow_any ( SandboxPolicy :: new_read_only_policy ( ) ) ,
1083- network : None ,
1084- allow_login_shell : true ,
1085- shell_environment_policy : ShellEnvironmentPolicy :: default ( ) ,
1086- windows_sandbox_mode : None ,
1087- macos_seatbelt_profile_extensions : Some ( MacOsSeatbeltProfileExtensions {
1088- macos_preferences : MacOsPreferencesPermission :: ReadWrite ,
1089- ..Default :: default ( )
1090- } ) ,
1091- } ;
1092-
1093- let prepared = executor
1094- . prepare_escalated_exec (
1095- & AbsolutePathBuf :: from_absolute_path ( "/bin/echo" ) . unwrap ( ) ,
1096- & [ "echo" . to_string ( ) , "ok" . to_string ( ) ] ,
1097- & cwd,
1098- HashMap :: new ( ) ,
1099- EscalationExecution :: Permissions ( EscalationPermissions :: Permissions (
1100- EscalatedPermissions {
1101- sandbox_policy : permissions. sandbox_policy . get ( ) . clone ( ) ,
1102- macos_seatbelt_profile_extensions : permissions
1103- . macos_seatbelt_profile_extensions
1104- . clone ( ) ,
1105- } ,
1106- ) ) ,
1107- )
1108- . await
1109- . unwrap ( ) ;
1110-
1111- assert_eq ! (
1112- prepared. command. first( ) . map( String :: as_str) ,
1113- Some ( MACOS_PATH_TO_SEATBELT_EXECUTABLE )
1114- ) ;
1115- assert_eq ! ( prepared. command. get( 1 ) . map( String :: as_str) , Some ( "-p" ) ) ;
1116- assert ! (
1117- prepared
1118- . command
1119- . get( 2 )
1120- . is_some_and( |policy| policy. contains( "(allow user-preference-write)" ) ) ,
1121- "expected seatbelt policy to include macOS extension profile: {:?}" ,
1122- prepared. command
1123- ) ;
1124- }
1125- }
802+ #[ path = "unix_escalation_tests.rs" ]
803+ mod tests;
0 commit comments