@@ -63,16 +63,57 @@ pub fn IsPathAllowedForAccess(ApplicationState:&ApplicationState, PathToCheck:&P
6363 return Ok ( ( ) ) ;
6464 }
6565
66+ // Use canonical paths on both sides so that prefix-matching survives
67+ // macOS's `/Volumes/<vol>/...` vs `/private/var/...` resolution and
68+ // any symlinked submodule roots. Cocoon's URI strip yields the user-
69+ // visible path (`/Volumes/CORSAIR/.../Land/Dependency/...`) while the
70+ // workspace folder URL stays as built from `from_directory_path` -
71+ // these can disagree on platforms where the resolved canonical path
72+ // differs from the URI-derived one (encoded mount-point indirection,
73+ // case-insensitive HFS+, etc.). Without this, a workspace with deep
74+ // submodule trees rejects every read that walks past the first level
75+ // even though the path is a literal descendant of the open folder.
76+ let CanonicalPathToCheck = PathToCheck
77+ . canonicalize ( )
78+ . unwrap_or_else ( |_| PathToCheck . to_path_buf ( ) ) ;
6679 let IsAllowed = FoldersGuard . iter ( ) . any ( |Folder | {
67- match Folder . URI . to_file_path ( ) {
68- Ok ( FolderPath ) => PathToCheck . starts_with ( FolderPath ) ,
69- Err ( _) => false ,
70- }
80+ let FolderPath = match Folder . URI . to_file_path ( ) {
81+ Ok ( P ) => P ,
82+ Err ( _) => return false ,
83+ } ;
84+ let CanonicalFolderPath = FolderPath
85+ . canonicalize ( )
86+ . unwrap_or_else ( |_| FolderPath . clone ( ) ) ;
87+ // Try both canonical-canonical AND raw-raw - either match wins.
88+ PathToCheck . starts_with ( & FolderPath )
89+ || PathToCheck . starts_with ( & CanonicalFolderPath )
90+ || CanonicalPathToCheck . starts_with ( & FolderPath )
91+ || CanonicalPathToCheck . starts_with ( & CanonicalFolderPath )
7192 } ) ;
7293
7394 if IsAllowed {
7495 Ok ( ( ) )
7596 } else {
97+ // Surface the comparison details so a workspace-mismatch bug
98+ // (URL-to-path conversion, canonicalisation drift) is debuggable
99+ // without rebuilding. Tag is `vfs` so it appears under the
100+ // default `short` trace set.
101+ let FolderPaths : Vec < String > = FoldersGuard
102+ . iter ( )
103+ . map ( |F | {
104+ F . URI
105+ . to_file_path ( )
106+ . map ( |P | P . display ( ) . to_string ( ) )
107+ . unwrap_or_else ( |_| format ! ( "<bad-uri:{}>" , F . URI ) )
108+ } )
109+ . collect ( ) ;
110+ dev_log ! (
111+ "vfs" ,
112+ "[PathSecurity] reject path={} canonical={} folders=[{}]" ,
113+ PathToCheck . display( ) ,
114+ CanonicalPathToCheck . display( ) ,
115+ FolderPaths . join( ", " )
116+ ) ;
76117 Err ( CommonError :: FileSystemPermissionDenied {
77118 Path : PathToCheck . to_path_buf ( ) ,
78119 Reason : "Path is outside of the registered workspace folders." . to_string ( ) ,
0 commit comments