| 181 | } |
| 182 | |
| 183 | fn resolve_recursive( |
| 184 | scopes: &HashMap<String, ScopeDefinition>, |
| 185 | name: &str, |
| 186 | out: &mut Vec<(String, String)>, |
| 187 | visited: &mut std::collections::HashSet<String>, |
| 188 | ) { |
| 189 | if !visited.insert(name.to_string()) { |
| 190 | return; // Cycle detected — skip. |
| 191 | } |
| 192 | if let Some(def) = scopes.get(name) { |
| 193 | out.extend(def.grants.iter().cloned()); |
| 194 | for inc in &def.includes { |
| 195 | Self::resolve_recursive(scopes, inc, out, visited); |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | /// Check if a scope grants a specific `(permission, collection)` pair. |
| 201 | pub fn scope_grants(&self, scope_name: &str, permission: &str, collection: &str) -> bool { |