@@ -377,6 +377,42 @@ fn intersect_permission_profiles_materializes_cwd_grant_for_reuse() {
377377 ) ;
378378}
379379
380+ #[ test]
381+ fn intersect_permission_profiles_deduplicates_materialized_grants ( ) {
382+ let temp_dir = TempDir :: new ( ) . expect ( "create temp dir" ) ;
383+ let cwd =
384+ AbsolutePathBuf :: from_absolute_path ( temp_dir. path ( ) . join ( "cwd" ) ) . expect ( "absolute cwd" ) ;
385+ let permissions = PermissionProfile {
386+ file_system : Some ( FileSystemPermissions {
387+ entries : vec ! [
388+ FileSystemSandboxEntry {
389+ path: FileSystemPath :: Special {
390+ value: FileSystemSpecialPath :: CurrentWorkingDirectory ,
391+ } ,
392+ access: FileSystemAccessMode :: Write ,
393+ } ,
394+ FileSystemSandboxEntry {
395+ path: FileSystemPath :: Path { path: cwd. clone( ) } ,
396+ access: FileSystemAccessMode :: Write ,
397+ } ,
398+ ] ,
399+ glob_scan_max_depth : None ,
400+ } ) ,
401+ ..Default :: default ( )
402+ } ;
403+
404+ assert_eq ! (
405+ intersect_permission_profiles( permissions. clone( ) , permissions, cwd. as_path( ) ) ,
406+ PermissionProfile {
407+ file_system: Some ( FileSystemPermissions :: from_read_write_roots(
408+ /*read*/ None ,
409+ Some ( vec![ cwd] ) ,
410+ ) ) ,
411+ ..Default :: default ( )
412+ }
413+ ) ;
414+ }
415+
380416#[ test]
381417fn intersect_permission_profiles_materializes_cwd_deny_entries ( ) {
382418 let temp_dir = TempDir :: new ( ) . expect ( "create temp dir" ) ;
@@ -509,6 +545,75 @@ fn intersect_permission_profiles_rejects_concrete_grants_matched_by_requested_de
509545 ) ;
510546}
511547
548+ #[ test]
549+ fn intersect_permission_profiles_materializes_relative_deny_globs_for_reuse ( ) {
550+ let temp_dir = TempDir :: new ( ) . expect ( "create temp dir" ) ;
551+ let request_cwd = AbsolutePathBuf :: from_absolute_path ( temp_dir. path ( ) . join ( "request-cwd" ) )
552+ . expect ( "absolute request cwd" ) ;
553+ let later_cwd = AbsolutePathBuf :: from_absolute_path ( temp_dir. path ( ) . join ( "later-cwd" ) )
554+ . expect ( "absolute later cwd" ) ;
555+ let cwd_write = FileSystemSandboxEntry {
556+ path : FileSystemPath :: Special {
557+ value : FileSystemSpecialPath :: CurrentWorkingDirectory ,
558+ } ,
559+ access : FileSystemAccessMode :: Write ,
560+ } ;
561+ let deny_env_files = FileSystemSandboxEntry {
562+ path : FileSystemPath :: GlobPattern {
563+ pattern : "**/*.env" . to_string ( ) ,
564+ } ,
565+ access : FileSystemAccessMode :: None ,
566+ } ;
567+ let permissions = PermissionProfile {
568+ file_system : Some ( FileSystemPermissions {
569+ entries : vec ! [ cwd_write, deny_env_files] ,
570+ glob_scan_max_depth : std:: num:: NonZeroUsize :: new ( 2 ) ,
571+ } ) ,
572+ ..Default :: default ( )
573+ } ;
574+
575+ let intersected =
576+ intersect_permission_profiles ( permissions. clone ( ) , permissions, request_cwd. as_path ( ) ) ;
577+
578+ assert_eq ! (
579+ intersected,
580+ PermissionProfile {
581+ file_system: Some ( FileSystemPermissions {
582+ entries: vec![
583+ FileSystemSandboxEntry {
584+ path: FileSystemPath :: Path {
585+ path: request_cwd. clone( ) ,
586+ } ,
587+ access: FileSystemAccessMode :: Write ,
588+ } ,
589+ FileSystemSandboxEntry {
590+ path: FileSystemPath :: GlobPattern {
591+ pattern: request_cwd. join( "**/*.env" ) . to_string_lossy( ) . into_owned( ) ,
592+ } ,
593+ access: FileSystemAccessMode :: None ,
594+ } ,
595+ ] ,
596+ glob_scan_max_depth: std:: num:: NonZeroUsize :: new( 2 ) ,
597+ } ) ,
598+ ..Default :: default ( )
599+ }
600+ ) ;
601+ assert_eq ! (
602+ intersect_permission_profiles(
603+ PermissionProfile {
604+ file_system: Some ( FileSystemPermissions :: from_read_write_roots(
605+ /*read*/ None ,
606+ Some ( vec![ later_cwd. join( "token.env" ) ] ) ,
607+ ) ) ,
608+ ..Default :: default ( )
609+ } ,
610+ intersected,
611+ later_cwd. as_path( ) ,
612+ ) ,
613+ PermissionProfile :: default ( )
614+ ) ;
615+ }
616+
512617#[ test]
513618fn intersect_permission_profiles_drops_broader_cwd_grant_for_requested_child_path ( ) {
514619 let temp_dir = TempDir :: new ( ) . expect ( "create temp dir" ) ;
@@ -567,7 +672,7 @@ fn intersect_permission_profiles_uses_granted_bounded_glob_scan_depth() {
567672 } ;
568673 let granted = PermissionProfile {
569674 file_system : Some ( FileSystemPermissions {
570- entries : vec ! [ root_write. clone( ) , deny_env_files. clone ( ) ] ,
675+ entries : vec ! [ root_write. clone( ) , deny_env_files] ,
571676 glob_scan_max_depth : std:: num:: NonZeroUsize :: new ( 4 ) ,
572677 } ) ,
573678 ..Default :: default ( )
@@ -577,7 +682,20 @@ fn intersect_permission_profiles_uses_granted_bounded_glob_scan_depth() {
577682 intersect_permission_profiles( requested, granted, cwd. as_path( ) ) ,
578683 PermissionProfile {
579684 file_system: Some ( FileSystemPermissions {
580- entries: vec![ root_write, deny_env_files] ,
685+ entries: vec![
686+ root_write,
687+ FileSystemSandboxEntry {
688+ path: FileSystemPath :: GlobPattern {
689+ pattern: AbsolutePathBuf :: resolve_path_against_base(
690+ "**/*.env" ,
691+ cwd. as_path( )
692+ )
693+ . to_string_lossy( )
694+ . into_owned( ) ,
695+ } ,
696+ access: FileSystemAccessMode :: None ,
697+ } ,
698+ ] ,
581699 glob_scan_max_depth: std:: num:: NonZeroUsize :: new( 4 ) ,
582700 } ) ,
583701 ..Default :: default ( )
@@ -609,7 +727,7 @@ fn intersect_permission_profiles_uses_granted_unbounded_glob_scan_depth() {
609727 } ;
610728 let granted = PermissionProfile {
611729 file_system : Some ( FileSystemPermissions {
612- entries : vec ! [ root_write. clone( ) , deny_env_files. clone ( ) ] ,
730+ entries : vec ! [ root_write. clone( ) , deny_env_files] ,
613731 glob_scan_max_depth : None ,
614732 } ) ,
615733 ..Default :: default ( )
@@ -619,7 +737,20 @@ fn intersect_permission_profiles_uses_granted_unbounded_glob_scan_depth() {
619737 intersect_permission_profiles( requested, granted, cwd. as_path( ) ) ,
620738 PermissionProfile {
621739 file_system: Some ( FileSystemPermissions {
622- entries: vec![ root_write, deny_env_files] ,
740+ entries: vec![
741+ root_write,
742+ FileSystemSandboxEntry {
743+ path: FileSystemPath :: GlobPattern {
744+ pattern: AbsolutePathBuf :: resolve_path_against_base(
745+ "**/*.env" ,
746+ cwd. as_path( )
747+ )
748+ . to_string_lossy( )
749+ . into_owned( ) ,
750+ } ,
751+ access: FileSystemAccessMode :: None ,
752+ } ,
753+ ] ,
623754 glob_scan_max_depth: None ,
624755 } ) ,
625756 ..Default :: default ( )
0 commit comments