Skip to content

Commit dff0c35

Browse files
rubydusaonbjerg
andauthored
fix: look through all matching permissions in is_path_allowed (#10679)
* fix: use `find_all_permissions` in `is_path_allowed` * chore: `rustfmt` --------- Co-authored-by: onbjerg <[email protected]>
1 parent 632c586 commit dff0c35

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

crates/config/src/fs_permissions.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl FsPermissions {
3737
/// Caution: This should be called with normalized paths if the `allowed_paths` are also
3838
/// normalized.
3939
pub fn is_path_allowed(&self, path: &Path, kind: FsAccessKind) -> bool {
40-
self.find_permission(path).map(|perm| perm.is_granted(kind)).unwrap_or_default()
40+
self.find_all_permissions(path).iter().any(|perm| perm.is_granted(kind))
4141
}
4242

4343
/// Returns the permission for the matching path.
@@ -66,6 +66,39 @@ impl FsPermissions {
6666
permission.map(|perm| perm.access)
6767
}
6868

69+
/// Returns all permissions for the matching path.
70+
///
71+
/// This finds the longest matching paths with resolved sym links, e.g. if we have the following
72+
/// permissions:
73+
///
74+
/// `./out` = `read`
75+
/// `./out/contracts` = `read`
76+
/// `./out/contracts` = `write`
77+
///
78+
/// And we check for `./out/contracts/MyContract.sol`, we will get both `read` and
79+
/// `write` permissions.
80+
pub fn find_all_permissions(&self, path: &Path) -> Vec<FsAccessPermission> {
81+
let mut matching_permissions = Vec::new();
82+
let mut max_path_len = 0;
83+
84+
// First pass: find all matching permissions and determine the maximum path length
85+
for perm in &self.permissions {
86+
let permission_path = dunce::canonicalize(&perm.path).unwrap_or(perm.path.clone());
87+
if path.starts_with(&permission_path) {
88+
let path_len = permission_path.components().count();
89+
if path_len > max_path_len {
90+
max_path_len = path_len;
91+
matching_permissions.clear();
92+
matching_permissions.push(perm.access);
93+
} else if path_len == max_path_len {
94+
matching_permissions.push(perm.access);
95+
}
96+
}
97+
}
98+
99+
matching_permissions
100+
}
101+
69102
/// Updates all `allowed_paths` and joins ([`Path::join`]) the `root` with all entries
70103
pub fn join_all(&mut self, root: &Path) {
71104
self.permissions.iter_mut().for_each(|perm| {
@@ -270,4 +303,19 @@ mod tests {
270303
let permission = permissions.find_permission(Path::new("./out/MyContract.sol")).unwrap();
271304
assert_eq!(FsAccessPermission::Write, permission);
272305
}
306+
307+
#[test]
308+
fn find_all_permissions() {
309+
let permissions = FsPermissions::new(vec![
310+
PathPermission::read("./out"),
311+
PathPermission::read("./out/contracts"),
312+
PathPermission::write("./out/contracts"),
313+
]);
314+
315+
let found_permissions =
316+
permissions.find_all_permissions(Path::new("./out/contracts/MyContract.sol"));
317+
assert_eq!(found_permissions.len(), 2);
318+
assert!(found_permissions.contains(&FsAccessPermission::Write));
319+
assert!(found_permissions.contains(&FsAccessPermission::Read));
320+
}
273321
}

0 commit comments

Comments
 (0)