Resolve the full permission chain for a role, following inheritance. Returns a list of role names from the given role up through its ancestors, capped at `MAX_ROLE_INHERITANCE_DEPTH` entries (self + ancestors). The catalog enforces no cycles and no chains deeper than `MAX_ROLE_INHERITANCE_DEPTH` at write time, so this walk is O(depth) with no HashSet needed. If the stored chain somehow violates t
(&self, role: &Role)
| 253 | /// invariant (e.g. data written before the cap was introduced), the walk |
| 254 | /// returns an error rather than truncating silently. |
| 255 | pub fn resolve_inheritance(&self, role: &Role) -> crate::Result<Vec<Role>> { |
| 256 | let mut chain = vec![role.clone()]; |
| 257 | |
| 258 | if let Role::Custom(name) = role { |
| 259 | let roles = self.roles.read().map_err(|e| crate::Error::Internal { |
| 260 | detail: format!("role store lock poisoned: {e}"), |
| 261 | })?; |
| 262 | |
| 263 | let mut current = name.as_str(); |
| 264 | |
| 265 | loop { |
| 266 | if chain.len() > MAX_ROLE_INHERITANCE_DEPTH { |
| 267 | return Err(crate::Error::RoleInheritanceDepthExceeded { |
| 268 | depth: chain.len(), |
| 269 | limit: MAX_ROLE_INHERITANCE_DEPTH, |
| 270 | }); |
| 271 | } |
| 272 | // Built-in roles have no further parents. |
| 273 | if is_builtin(current) { |
| 274 | break; |
| 275 | } |
| 276 | match roles.get(current) { |
| 277 | Some(custom) => match &custom.parent { |
| 278 | Some(parent_name) => { |
| 279 | // Role::from_str is infallible (Err = Infallible); |
| 280 | // matching on the uninhabited error proves it at |
| 281 | // compile time without an unwrap. |
| 282 | let parent_role: Role = match parent_name.parse() { |
| 283 | Ok(r) => r, |
| 284 | Err(e) => match e {}, |
| 285 | }; |
| 286 | chain.push(parent_role); |
| 287 | current = parent_name.as_str(); |
| 288 | } |
| 289 | None => break, |
| 290 | }, |
| 291 | None => break, |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | Ok(chain) |
| 297 | } |
| 298 | |
| 299 | /// Check that adopting `parent` as `role_name`'s inheritance parent would |
| 300 | /// not create a cycle or exceed [`MAX_ROLE_INHERITANCE_DEPTH`]. |