From 3d4b883ffbe6b57093d594b7a636295cac49af6e Mon Sep 17 00:00:00 2001 From: rubydusa Date: Sat, 31 May 2025 16:16:08 +0300 Subject: [PATCH 1/2] fix: use `find_all_permissions` in `is_path_allowed` --- crates/config/src/fs_permissions.rs | 49 ++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/crates/config/src/fs_permissions.rs b/crates/config/src/fs_permissions.rs index 1d2c35ff33bf9..c68401e0419d4 100644 --- a/crates/config/src/fs_permissions.rs +++ b/crates/config/src/fs_permissions.rs @@ -37,7 +37,7 @@ impl FsPermissions { /// Caution: This should be called with normalized paths if the `allowed_paths` are also /// normalized. pub fn is_path_allowed(&self, path: &Path, kind: FsAccessKind) -> bool { - self.find_permission(path).map(|perm| perm.is_granted(kind)).unwrap_or_default() + self.find_all_permissions(path).iter().any(|perm| perm.is_granted(kind)) } /// Returns the permission for the matching path. @@ -66,6 +66,39 @@ impl FsPermissions { permission.map(|perm| perm.access) } + /// Returns all permissions for the matching path. + /// + /// This finds the longest matching paths with resolved sym links, e.g. if we have the following + /// permissions: + /// + /// `./out` = `read` + /// `./out/contracts` = `read` + /// `./out/contracts` = `write` + /// + /// And we check for `./out/contracts/MyContract.sol`, we will get both `read` and + /// `write` permissions. + pub fn find_all_permissions(&self, path: &Path) -> Vec { + let mut matching_permissions = Vec::new(); + let mut max_path_len = 0; + + // First pass: find all matching permissions and determine the maximum path length + for perm in &self.permissions { + let permission_path = dunce::canonicalize(&perm.path).unwrap_or(perm.path.clone()); + if path.starts_with(&permission_path) { + let path_len = permission_path.components().count(); + if path_len > max_path_len { + max_path_len = path_len; + matching_permissions.clear(); + matching_permissions.push(perm.access); + } else if path_len == max_path_len { + matching_permissions.push(perm.access); + } + } + } + + matching_permissions + } + /// Updates all `allowed_paths` and joins ([`Path::join`]) the `root` with all entries pub fn join_all(&mut self, root: &Path) { self.permissions.iter_mut().for_each(|perm| { @@ -270,4 +303,18 @@ mod tests { let permission = permissions.find_permission(Path::new("./out/MyContract.sol")).unwrap(); assert_eq!(FsAccessPermission::Write, permission); } + + #[test] + fn find_all_permissions() { + let permissions = FsPermissions::new(vec![ + PathPermission::read("./out"), + PathPermission::read("./out/contracts"), + PathPermission::write("./out/contracts"), + ]); + + let found_permissions = permissions.find_all_permissions(Path::new("./out/contracts/MyContract.sol")); + assert_eq!(found_permissions.len(), 2); + assert!(found_permissions.contains(&FsAccessPermission::Write)); + assert!(found_permissions.contains(&FsAccessPermission::Read)); + } } From 96055e2ba8240df12c846d5cd018d7194a475c15 Mon Sep 17 00:00:00 2001 From: rubydusa Date: Sat, 31 May 2025 19:22:20 +0300 Subject: [PATCH 2/2] chore: `rustfmt` --- crates/config/src/fs_permissions.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/config/src/fs_permissions.rs b/crates/config/src/fs_permissions.rs index c68401e0419d4..bc185569d54c3 100644 --- a/crates/config/src/fs_permissions.rs +++ b/crates/config/src/fs_permissions.rs @@ -75,7 +75,7 @@ impl FsPermissions { /// `./out/contracts` = `read` /// `./out/contracts` = `write` /// - /// And we check for `./out/contracts/MyContract.sol`, we will get both `read` and + /// And we check for `./out/contracts/MyContract.sol`, we will get both `read` and /// `write` permissions. pub fn find_all_permissions(&self, path: &Path) -> Vec { let mut matching_permissions = Vec::new(); @@ -312,7 +312,8 @@ mod tests { PathPermission::write("./out/contracts"), ]); - let found_permissions = permissions.find_all_permissions(Path::new("./out/contracts/MyContract.sol")); + let found_permissions = + permissions.find_all_permissions(Path::new("./out/contracts/MyContract.sol")); assert_eq!(found_permissions.len(), 2); assert!(found_permissions.contains(&FsAccessPermission::Write)); assert!(found_permissions.contains(&FsAccessPermission::Read));