@@ -26,6 +26,7 @@ use codex_protocol::permissions::FileSystemSandboxEntry;
2626use codex_protocol:: permissions:: FileSystemSandboxPolicy ;
2727use codex_protocol:: permissions:: FileSystemSpecialPath ;
2828use codex_protocol:: permissions:: NetworkSandboxPolicy ;
29+ use codex_protocol:: permissions:: PRESERVED_PATH_NAMES ;
2930use codex_protocol:: protocol:: SandboxPolicy ;
3031use codex_utils_absolute_path:: AbsolutePathBuf ;
3132use pretty_assertions:: assert_eq;
@@ -59,6 +60,26 @@ fn seatbelt_policy_arg(args: &[String]) -> &str {
5960 . expect ( "seatbelt args should include policy text" )
6061}
6162
63+ fn seatbelt_preserved_path_name_requirements ( root : & Path ) -> String {
64+ let mut root = root. to_string_lossy ( ) . to_string ( ) ;
65+ while root. len ( ) > 1 && root. ends_with ( '/' ) {
66+ root. pop ( ) ;
67+ }
68+ let root = regex_lite:: escape ( & root) ;
69+ PRESERVED_PATH_NAMES
70+ . iter ( )
71+ . map ( |name| {
72+ let name = regex_lite:: escape ( name) ;
73+ if root == "/" {
74+ format ! ( r#"(require-not (regex #"^/(.*/)?{name}(/.*)?$"))"# )
75+ } else {
76+ format ! ( r#"(require-not (regex #"^{root}/(.*/)?{name}(/.*)?$"))"# )
77+ }
78+ } )
79+ . collect :: < Vec < _ > > ( )
80+ . join ( " " )
81+ }
82+
6283struct TestConfigReloader ;
6384
6485#[ async_trait:: async_trait]
@@ -843,8 +864,7 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() {
843864 ) ;
844865 assert ! (
845866 policy_text. contains( "WRITABLE_ROOT_1_EXCLUDED_0" )
846- && policy_text. contains( "WRITABLE_ROOT_1_EXCLUDED_1" )
847- && policy_text. contains( "WRITABLE_ROOT_1_EXCLUDED_2" ) ,
867+ && policy_text. contains( "WRITABLE_ROOT_1_EXCLUDED_1" ) ,
848868 "expected explicit writable root preserved path carveouts in policy:\n {policy_text}" ,
849869 ) ;
850870 assert ! (
@@ -1079,11 +1099,11 @@ fn create_seatbelt_args_block_first_time_dot_codex_creation_with_exact_and_desce
10791099
10801100 let policy_text = seatbelt_policy_arg ( & args) ;
10811101 assert ! (
1082- policy_text. contains( "(require-not (literal (param \" WRITABLE_ROOT_0_EXCLUDED_1 \" )))" ) ,
1102+ policy_text. contains( "(require-not (literal (param \" WRITABLE_ROOT_0_EXCLUDED_2 \" )))" ) ,
10831103 "expected exact .codex carveout in policy:\n {policy_text}"
10841104 ) ;
10851105 assert ! (
1086- policy_text. contains( "(require-not (subpath (param \" WRITABLE_ROOT_0_EXCLUDED_1 \" )))" ) ,
1106+ policy_text. contains( "(require-not (subpath (param \" WRITABLE_ROOT_0_EXCLUDED_2 \" )))" ) ,
10871107 "expected descendant .codex carveout in policy:\n {policy_text}"
10881108 ) ;
10891109}
@@ -1239,11 +1259,17 @@ fn create_seatbelt_args_for_cwd_as_git_repo() {
12391259 let slash_tmp = PathBuf :: from ( "/tmp" )
12401260 . canonicalize ( )
12411261 . expect ( "canonicalize /tmp" ) ;
1242- let tempdir_policy_entry = if tmpdir_env_var. is_some ( ) {
1243- r#" (require-all (subpath (param "WRITABLE_ROOT_2")) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_2"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_3"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_3"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_4"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_4"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_5"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_5"))) )"#
1262+ let tempdir_policy_entry = if let Some ( p) = & tmpdir_env_var {
1263+ let preserved_requirements = seatbelt_preserved_path_name_requirements ( Path :: new ( p) ) ;
1264+ format ! (
1265+ r#" (require-all (subpath (param "WRITABLE_ROOT_2")) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_2"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_3"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_3"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_4"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_4"))) (require-not (literal (param "WRITABLE_ROOT_2_EXCLUDED_5"))) (require-not (subpath (param "WRITABLE_ROOT_2_EXCLUDED_5"))) {preserved_requirements} )"#
1266+ )
12441267 } else {
1245- ""
1268+ String :: new ( )
12461269 } ;
1270+ let root_0_preserved_requirements =
1271+ seatbelt_preserved_path_name_requirements ( & vulnerable_root_canonical) ;
1272+ let root_1_preserved_requirements = seatbelt_preserved_path_name_requirements ( & slash_tmp) ;
12471273
12481274 // Build the expected policy text using a raw string for readability.
12491275 // Note that the policy includes:
@@ -1256,7 +1282,7 @@ fn create_seatbelt_args_for_cwd_as_git_repo() {
12561282; allow read-only file operations
12571283(allow file-read*)
12581284(allow file-write*
1259- (require-all (subpath (param "WRITABLE_ROOT_0")) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_2"))) ) (require-all (subpath (param "WRITABLE_ROOT_1")) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_2"))) ){tempdir_policy_entry}
1285+ (require-all (subpath (param "WRITABLE_ROOT_0")) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_0_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_0_EXCLUDED_2"))) {root_0_preserved_requirements} ) (require-all (subpath (param "WRITABLE_ROOT_1")) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_0"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_0"))) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_1"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_1"))) (require-not (literal (param "WRITABLE_ROOT_1_EXCLUDED_2"))) (require-not (subpath (param "WRITABLE_ROOT_1_EXCLUDED_2"))) {root_1_preserved_requirements} ){tempdir_policy_entry}
12601286)
12611287
12621288"# ,
0 commit comments