role_system/
role.rs

1//! Role definitions and management.
2
3use crate::{
4    error::{Error, Result},
5    permission::{Permission, PermissionSet},
6};
7use std::{
8    collections::HashMap,
9    time::{Duration, Instant},
10};
11use uuid::Uuid;
12
13/// A role hierarchy system for managing role inheritance.
14#[derive(Debug, Clone)]
15#[cfg_attr(feature = "persistence", derive(serde::Serialize, serde::Deserialize))]
16pub struct RoleHierarchy {
17    /// Map of child role ID to parent role ID
18    parent_map: HashMap<String, String>,
19    /// Map of parent role ID to set of child role IDs
20    children_map: HashMap<String, Vec<String>>,
21    /// All roles in the hierarchy
22    roles: HashMap<String, Role>,
23}
24
25impl RoleHierarchy {
26    /// Create a new empty role hierarchy.
27    pub fn new() -> Self {
28        Self {
29            parent_map: HashMap::new(),
30            children_map: HashMap::new(),
31            roles: HashMap::new(),
32        }
33    }
34
35    /// Add a role to the hierarchy.
36    pub fn add_role(&mut self, role: Role) -> Result<()> {
37        let role_id = role.id().to_string();
38        self.roles.insert(role_id, role);
39        Ok(())
40    }
41
42    /// Set a parent-child relationship between roles.
43    pub fn set_parent(&mut self, child_id: &str, parent_id: &str) -> Result<()> {
44        // Verify both roles exist
45        if !self.roles.contains_key(child_id) {
46            return Err(Error::RoleNotFound(child_id.to_string()));
47        }
48        if !self.roles.contains_key(parent_id) {
49            return Err(Error::RoleNotFound(parent_id.to_string()));
50        }
51
52        // Check for circular dependencies
53        if self.would_create_cycle(child_id, parent_id) {
54            return Err(Error::CircularDependency(format!(
55                "{} -> {}",
56                child_id, parent_id
57            )));
58        }
59
60        // Remove any existing parent relationship for this child
61        if let Some(old_parent) = self.parent_map.remove(child_id)
62            && let Some(siblings) = self.children_map.get_mut(&old_parent)
63        {
64            siblings.retain(|id| id != child_id);
65        }
66
67        // Set the new parent relationship
68        self.parent_map
69            .insert(child_id.to_string(), parent_id.to_string());
70        self.children_map
71            .entry(parent_id.to_string())
72            .or_default()
73            .push(child_id.to_string());
74
75        Ok(())
76    }
77
78    /// Get the parent role of a given role.
79    pub fn get_parent(&self, role_id: &str) -> Option<&Role> {
80        self.parent_map
81            .get(role_id)
82            .and_then(|parent_id| self.roles.get(parent_id))
83    }
84
85    /// Get all child roles of a given role.
86    pub fn get_children(&self, role_id: &str) -> Vec<&Role> {
87        self.children_map
88            .get(role_id)
89            .map(|child_ids| {
90                child_ids
91                    .iter()
92                    .filter_map(|id| self.roles.get(id))
93                    .collect()
94            })
95            .unwrap_or_default()
96    }
97
98    /// Get all ancestor roles (parents, grandparents, etc.) of a given role.
99    pub fn get_ancestors(&self, role_id: &str) -> Vec<&Role> {
100        let mut ancestors = Vec::new();
101        let mut current = role_id;
102
103        while let Some(parent_id) = self.parent_map.get(current) {
104            if let Some(parent_role) = self.roles.get(parent_id) {
105                ancestors.push(parent_role);
106                current = parent_id;
107            } else {
108                break;
109            }
110        }
111
112        ancestors
113    }
114
115    /// Get all permissions for a role, including inherited permissions.
116    pub fn get_effective_permissions(&self, role_id: &str) -> Result<PermissionSet> {
117        let role = self
118            .roles
119            .get(role_id)
120            .ok_or_else(|| Error::RoleNotFound(role_id.to_string()))?;
121
122        let mut permissions = role.permissions().clone();
123
124        // Add inherited permissions from ancestors
125        for ancestor in self.get_ancestors(role_id) {
126            for permission in ancestor.permissions().permissions() {
127                permissions.add(permission.clone());
128            }
129        }
130
131        Ok(permissions)
132    }
133
134    /// Check if a role has a specific permission, including inherited permissions.
135    pub fn has_permission(
136        &self,
137        role_id: &str,
138        action: &str,
139        resource: &str,
140        context: &HashMap<String, String>,
141    ) -> Result<bool> {
142        let effective_permissions = self.get_effective_permissions(role_id)?;
143        Ok(effective_permissions.grants(action, resource, context))
144    }
145
146    /// Get a role by ID.
147    pub fn get_role(&self, role_id: &str) -> Option<&Role> {
148        self.roles.get(role_id)
149    }
150
151    /// Get all roles in the hierarchy.
152    pub fn get_all_roles(&self) -> Vec<&Role> {
153        self.roles.values().collect()
154    }
155
156    /// Remove a role from the hierarchy.
157    pub fn remove_role(&mut self, role_id: &str) -> Result<()> {
158        // Remove the role itself
159        if self.roles.remove(role_id).is_none() {
160            return Err(Error::RoleNotFound(role_id.to_string()));
161        }
162
163        // Remove from parent mapping
164        if let Some(parent_id) = self.parent_map.remove(role_id)
165            && let Some(siblings) = self.children_map.get_mut(&parent_id)
166        {
167            siblings.retain(|id| id != role_id);
168        }
169
170        // Remove from children mapping and reparent children
171        if let Some(child_ids) = self.children_map.remove(role_id) {
172            for child_id in child_ids {
173                self.parent_map.remove(&child_id);
174            }
175        }
176
177        Ok(())
178    }
179
180    /// Check if setting a parent would create a circular dependency.
181    fn would_create_cycle(&self, child_id: &str, proposed_parent_id: &str) -> bool {
182        // If the proposed parent is the child itself, it's a cycle
183        if child_id == proposed_parent_id {
184            return true;
185        }
186
187        // Check if the proposed parent is already a descendant of the child
188        let mut current = proposed_parent_id;
189        while let Some(parent_id) = self.parent_map.get(current) {
190            if parent_id == child_id {
191                return true;
192            }
193            current = parent_id;
194        }
195
196        false
197    }
198}
199
200impl Default for RoleHierarchy {
201    fn default() -> Self {
202        Self::new()
203    }
204}
205
206/// A role represents a collection of permissions that can be assigned to subjects.
207#[derive(Debug, Clone)]
208#[cfg_attr(feature = "persistence", derive(serde::Serialize, serde::Deserialize))]
209pub struct Role {
210    /// Unique identifier for the role.
211    id: String,
212    /// Human-readable name of the role.
213    name: String,
214    /// Optional description of the role.
215    description: Option<String>,
216    /// Permissions granted by this role.
217    permissions: PermissionSet,
218    /// Metadata associated with the role.
219    metadata: HashMap<String, String>,
220    /// Whether this role is active.
221    active: bool,
222}
223
224impl Role {
225    /// Create a new role with the given name.
226    pub fn new(name: impl Into<String>) -> Self {
227        let name = name.into();
228        Self {
229            id: Uuid::new_v4().to_string(),
230            name,
231            description: None,
232            permissions: PermissionSet::new(),
233            metadata: HashMap::new(),
234            active: true,
235        }
236    }
237
238    /// Create a new role with a specific ID.
239    pub fn with_id(id: impl Into<String>, name: impl Into<String>) -> Self {
240        let mut role = Self::new(name);
241        role.id = id.into();
242        role
243    }
244
245    /// Get the role's unique identifier.
246    pub fn id(&self) -> &str {
247        &self.id
248    }
249
250    /// Get the role's name.
251    pub fn name(&self) -> &str {
252        &self.name
253    }
254
255    /// Set the role's description.
256    pub fn with_description(mut self, description: impl Into<String>) -> Self {
257        self.description = Some(description.into());
258        self
259    }
260
261    /// Get the role's description.
262    pub fn description(&self) -> Option<&str> {
263        self.description.as_deref()
264    }
265
266    /// Add a permission to this role.
267    pub fn add_permission(mut self, permission: Permission) -> Self {
268        self.permissions.add(permission);
269        self
270    }
271
272    /// Add multiple permissions to this role.
273    pub fn add_permissions(mut self, permissions: impl IntoIterator<Item = Permission>) -> Self {
274        for permission in permissions {
275            self.permissions.add(permission);
276        }
277        self
278    }
279
280    /// Remove a permission from this role.
281    pub fn remove_permission(&mut self, permission: &Permission) {
282        self.permissions.remove(permission);
283    }
284
285    /// Check if this role has a specific permission.
286    pub fn has_permission_exact(&self, permission: &Permission) -> bool {
287        self.permissions.contains(permission)
288    }
289
290    /// Check if this role grants permission for an action on a resource type.
291    pub fn has_permission(
292        &self,
293        action: &str,
294        resource_type: &str,
295        context: &HashMap<String, String>,
296    ) -> bool {
297        if !self.active {
298            return false;
299        }
300        self.permissions.grants(action, resource_type, context)
301    }
302
303    /// Get all permissions granted by this role.
304    pub fn permissions(&self) -> &PermissionSet {
305        &self.permissions
306    }
307
308    /// Set metadata for this role.
309    pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
310        self.metadata.insert(key.into(), value.into());
311        self
312    }
313
314    /// Get metadata value for a key.
315    pub fn metadata(&self, key: &str) -> Option<&str> {
316        self.metadata.get(key).map(|s| s.as_str())
317    }
318
319    /// Get all metadata.
320    pub fn all_metadata(&self) -> &HashMap<String, String> {
321        &self.metadata
322    }
323
324    /// Set whether this role is active.
325    pub fn set_active(&mut self, active: bool) {
326        self.active = active;
327    }
328
329    /// Check if this role is active.
330    pub fn is_active(&self) -> bool {
331        self.active
332    }
333
334    /// Deactivate this role.
335    pub fn deactivate(mut self) -> Self {
336        self.active = false;
337        self
338    }
339
340    /// Merge permissions from another role into this one.
341    pub fn merge_permissions(&mut self, other: &Role) {
342        for permission in other.permissions() {
343            self.permissions.add(permission.clone());
344        }
345    }
346
347    // Optional hierarchy access methods (require hierarchy config to be enabled)
348
349    /// Get the parent role ID if this role has a parent in the hierarchy.
350    ///
351    /// This method provides access to the direct parent relationship, enabling
352    /// use cases like API responses, admin interfaces, and JWT token generation.
353    ///
354    /// Returns `None` if:
355    /// - This role has no parent (it's a root role)
356    /// - Hierarchy access is disabled in configuration
357    ///
358    /// # Example
359    /// ```rust
360    /// use role_system::Role;
361    ///
362    /// let role = Role::new("junior_dev");
363    /// if let Some(parent_id) = role.parent_role_id() {
364    ///     println!("Parent role: {}", parent_id);
365    /// }
366    /// ```
367    ///
368    /// # Note
369    /// This method returns `None` by default to maintain backward compatibility.
370    /// The actual parent relationship is managed by the `RoleHierarchy` system.
371    /// To use this feature, the role must be created through a system that
372    /// tracks hierarchy relationships and enables hierarchy access.
373    pub fn parent_role_id(&self) -> Option<&str> {
374        // By default, roles don't track their parents directly
375        // This is managed by RoleHierarchy and AsyncRoleSystem
376        // Individual Role instances return None for backward compatibility
377        None
378    }
379
380    /// Get the child role IDs if this role has children in the hierarchy.
381    ///
382    /// This method provides access to direct child relationships, useful for
383    /// building admin interfaces, API responses, and permission visualization.
384    ///
385    /// Returns empty vector if:
386    /// - This role has no children
387    /// - Hierarchy access is disabled in configuration
388    ///
389    /// # Example
390    /// ```rust
391    /// use role_system::Role;
392    ///
393    /// let role = Role::new("team_lead");
394    /// let children = role.child_role_ids();
395    /// for child_id in children {
396    ///     println!("Child role: {}", child_id);
397    /// }
398    /// ```
399    ///
400    /// # Note
401    /// This method returns an empty vector by default to maintain backward compatibility.
402    /// The actual child relationships are managed by the `RoleHierarchy` system.
403    /// To use this feature, the role must be created through a system that
404    /// tracks hierarchy relationships and enables hierarchy access.
405    pub fn child_role_ids(&self) -> Vec<&str> {
406        // By default, roles don't track their children directly
407        // This is managed by RoleHierarchy and AsyncRoleSystem
408        // Individual Role instances return empty vector for backward compatibility
409        Vec::new()
410    }
411
412    /// Check if this role is a root role (has no parent).
413    ///
414    /// A root role is one that sits at the top of a hierarchy branch
415    /// and doesn't inherit from any other role.
416    ///
417    /// # Example
418    /// ```rust
419    /// use role_system::Role;
420    ///
421    /// let admin_role = Role::new("admin");
422    /// if admin_role.is_root_role() {
423    ///     println!("This is a top-level role");
424    /// }
425    /// ```
426    ///
427    /// # Note
428    /// Returns `true` by default since individual Role instances don't
429    /// track hierarchy relationships. Use `RoleHierarchy` or `AsyncRoleSystem`
430    /// for actual hierarchy-aware operations.
431    pub fn is_root_role(&self) -> bool {
432        self.parent_role_id().is_none()
433    }
434
435    /// Check if this role is a leaf role (has no children).
436    ///
437    /// A leaf role is one that doesn't have any roles inheriting from it.
438    ///
439    /// # Example
440    /// ```rust
441    /// use role_system::Role;
442    ///
443    /// let intern_role = Role::new("intern");
444    /// if intern_role.is_leaf_role() {
445    ///     println!("This role has no children");
446    /// }
447    /// ```
448    ///
449    /// # Note
450    /// Returns `true` by default since individual Role instances don't
451    /// track hierarchy relationships. Use `RoleHierarchy` or `AsyncRoleSystem`
452    /// for actual hierarchy-aware operations.
453    pub fn is_leaf_role(&self) -> bool {
454        self.child_role_ids().is_empty()
455    }
456
457    /// Get the depth of this role in the hierarchy.
458    ///
459    /// Root roles have depth 0, their children have depth 1, etc.
460    /// This is useful for visualization and API responses.
461    ///
462    /// # Example
463    /// ```rust
464    /// use role_system::Role;
465    ///
466    /// let role = Role::new("senior_dev");
467    /// let depth = role.hierarchy_depth();
468    /// println!("Role depth: {}", depth);
469    /// ```
470    ///
471    /// # Note
472    /// Returns `0` by default since individual Role instances don't
473    /// track hierarchy relationships. Use `RoleHierarchy` or `AsyncRoleSystem`
474    /// for actual hierarchy-aware depth calculation.
475    pub fn hierarchy_depth(&self) -> usize {
476        0
477    }
478
479    /// Get metadata about this role's position in the hierarchy.
480    ///
481    /// Returns a HashMap containing hierarchy-related metadata such as:
482    /// - "parent_count": Number of ancestors
483    /// - "child_count": Number of direct children
484    /// - "descendant_count": Total number of descendants
485    /// - "depth": Depth in hierarchy
486    ///
487    /// # Example
488    /// ```rust
489    /// use role_system::Role;
490    ///
491    /// let role = Role::new("manager");
492    /// let hierarchy_meta = role.hierarchy_metadata();
493    /// if let Some(depth) = hierarchy_meta.get("depth") {
494    ///     println!("Hierarchy depth: {}", depth);
495    /// }
496    /// ```
497    ///
498    /// # Note
499    /// Returns minimal metadata by default. Use `RoleHierarchy` or `AsyncRoleSystem`
500    /// for complete hierarchy metadata.
501    pub fn hierarchy_metadata(&self) -> HashMap<String, String> {
502        let mut metadata = HashMap::new();
503        metadata.insert("depth".to_string(), "0".to_string());
504        metadata.insert("parent_count".to_string(), "0".to_string());
505        metadata.insert("child_count".to_string(), "0".to_string());
506        metadata.insert("descendant_count".to_string(), "0".to_string());
507        metadata.insert("is_root".to_string(), "true".to_string());
508        metadata.insert("is_leaf".to_string(), "true".to_string());
509        metadata
510    }
511}
512
513/// A temporary role elevation for a subject.
514#[derive(Debug, Clone)]
515#[cfg_attr(feature = "persistence", derive(serde::Serialize, serde::Deserialize))]
516pub struct RoleElevation {
517    /// The role being elevated to.
518    role_name: String,
519    /// When the elevation was created.
520    #[cfg_attr(feature = "persistence", serde(with = "instant_serde"))]
521    created_at: Instant,
522    /// How long the elevation lasts (None for permanent).
523    duration: Option<Duration>,
524    /// Reason for the elevation.
525    reason: Option<String>,
526}
527
528impl RoleElevation {
529    /// Create a new role elevation.
530    pub fn new(role_name: String, duration: Option<Duration>) -> Self {
531        Self {
532            role_name,
533            created_at: Instant::now(),
534            duration,
535            reason: None,
536        }
537    }
538
539    /// Create a role elevation with a reason.
540    pub fn with_reason(role_name: String, duration: Option<Duration>, reason: String) -> Self {
541        Self {
542            role_name,
543            created_at: Instant::now(),
544            duration,
545            reason: Some(reason),
546        }
547    }
548
549    /// Get the role name being elevated to.
550    pub fn role_name(&self) -> &str {
551        &self.role_name
552    }
553
554    /// Get when the elevation was created.
555    pub fn created_at(&self) -> Instant {
556        self.created_at
557    }
558
559    /// Get the duration of the elevation.
560    pub fn duration(&self) -> Option<Duration> {
561        self.duration
562    }
563
564    /// Get the reason for the elevation.
565    pub fn reason(&self) -> Option<&str> {
566        self.reason.as_deref()
567    }
568
569    /// Check if the elevation has expired.
570    pub fn is_expired(&self, now: Instant) -> bool {
571        if let Some(duration) = self.duration {
572            now.duration_since(self.created_at) > duration
573        } else {
574            false // Permanent elevation
575        }
576    }
577
578    /// Get the time remaining for this elevation.
579    pub fn time_remaining(&self, now: Instant) -> Option<Duration> {
580        if let Some(duration) = self.duration {
581            let elapsed = now.duration_since(self.created_at);
582            if elapsed < duration {
583                Some(duration - elapsed)
584            } else {
585                Some(Duration::ZERO)
586            }
587        } else {
588            None // Permanent elevation
589        }
590    }
591}
592
593/// Builder for creating roles with a fluent API.
594#[derive(Debug, Default)]
595pub struct RoleBuilder {
596    name: Option<String>,
597    description: Option<String>,
598    permissions: Vec<Permission>,
599    metadata: HashMap<String, String>,
600    active: bool,
601}
602
603impl RoleBuilder {
604    /// Create a new role builder.
605    pub fn new() -> Self {
606        Self {
607            active: true,
608            ..Default::default()
609        }
610    }
611
612    /// Set the role name.
613    pub fn name(mut self, name: impl Into<String>) -> Self {
614        self.name = Some(name.into());
615        self
616    }
617
618    /// Set the role description.
619    pub fn description(mut self, description: impl Into<String>) -> Self {
620        self.description = Some(description.into());
621        self
622    }
623
624    /// Add a permission to the role.
625    pub fn permission(mut self, permission: Permission) -> Self {
626        self.permissions.push(permission);
627        self
628    }
629
630    /// Add multiple permissions to the role.
631    pub fn permissions(mut self, permissions: impl IntoIterator<Item = Permission>) -> Self {
632        self.permissions.extend(permissions);
633        self
634    }
635
636    /// Add permissions with fluent allow syntax.
637    ///
638    /// # Example
639    /// ```rust
640    /// use role_system::role::RoleBuilder;
641    /// let role = RoleBuilder::new()
642    ///     .name("admin")
643    ///     .allow("users", ["create", "read", "update", "delete"])
644    ///     .allow("roles", ["read", "assign"])
645    ///     .build().unwrap();
646    /// ```
647    pub fn allow<I, S>(mut self, resource: impl Into<String>, actions: I) -> Self
648    where
649        I: IntoIterator<Item = S>,
650        S: Into<String>,
651    {
652        let resource = resource.into();
653        for action in actions {
654            self.permissions
655                .push(Permission::new(action.into(), resource.clone()));
656        }
657        self
658    }
659
660    /// Add permissions with deny semantics (creates negative conditions).
661    ///
662    /// # Example
663    /// ```rust
664    /// use role_system::role::RoleBuilder;
665    /// let role = RoleBuilder::new()
666    ///     .name("restricted_admin")
667    ///     .allow("users", ["read", "update"])
668    ///     .deny("system", ["shutdown"])
669    ///     .build().unwrap();
670    /// ```
671    pub fn deny<I, S>(mut self, resource: impl Into<String>, actions: I) -> Self
672    where
673        I: IntoIterator<Item = S>,
674        S: Into<String>,
675    {
676        let resource = resource.into();
677        for action in actions {
678            // Create a permission with a condition that always returns false
679            let deny_permission =
680                Permission::with_condition(action.into(), resource.clone(), |_| false);
681            self.permissions.push(deny_permission);
682        }
683        self
684    }
685
686    /// Add permissions with conditional access.
687    ///
688    /// # Example
689    /// ```rust
690    /// use role_system::role::RoleBuilder;
691    /// let role = RoleBuilder::new()
692    ///     .name("user")
693    ///     .allow_when("profile", ["update"], |ctx|
694    ///         ctx.get("user_id") == ctx.get("target_id"))
695    ///     .build().unwrap();
696    /// ```
697    pub fn allow_when<I, S, F>(
698        mut self,
699        resource: impl Into<String>,
700        actions: I,
701        condition: F,
702    ) -> Self
703    where
704        I: IntoIterator<Item = S>,
705        S: Into<String>,
706        F: Fn(&std::collections::HashMap<String, String>) -> bool + Send + Sync + 'static + Clone,
707    {
708        let resource = resource.into();
709        for action in actions {
710            let conditional_permission =
711                Permission::with_condition(action.into(), resource.clone(), condition.clone());
712            self.permissions.push(conditional_permission);
713        }
714        self
715    }
716
717    /// Add metadata to the role.
718    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
719        self.metadata.insert(key.into(), value.into());
720        self
721    }
722
723    /// Set whether the role is active.
724    pub fn active(mut self, active: bool) -> Self {
725        self.active = active;
726        self
727    }
728
729    /// Build the role.
730    pub fn build(self) -> Result<Role> {
731        let name = self
732            .name
733            .ok_or_else(|| Error::InvalidConfiguration("Role name is required".to_string()))?;
734
735        let mut role = Role::new(name);
736
737        if let Some(description) = self.description {
738            role = role.with_description(description);
739        }
740
741        for permission in self.permissions {
742            role = role.add_permission(permission);
743        }
744
745        for (key, value) in self.metadata {
746            role = role.with_metadata(key, value);
747        }
748
749        role.set_active(self.active);
750
751        Ok(role)
752    }
753}
754
755// Helper module for serializing Instant with serde
756#[cfg(feature = "persistence")]
757mod instant_serde {
758    use serde::{Deserialize, Deserializer, Serialize, Serializer};
759    use std::time::{Instant, SystemTime, UNIX_EPOCH};
760
761    pub fn serialize<S>(_instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
762    where
763        S: Serializer,
764    {
765        // Convert Instant to a duration since a reference point
766        // Note: This is a simplified approach and may not work across process restarts
767        let duration_since_epoch = SystemTime::now()
768            .duration_since(UNIX_EPOCH)
769            .unwrap()
770            .as_nanos();
771        duration_since_epoch.serialize(serializer)
772    }
773
774    pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
775    where
776        D: Deserializer<'de>,
777    {
778        let _nanos = u128::deserialize(deserializer)?;
779        // This is a simplified approach - in a real implementation you'd want
780        // to store a reference point and calculate relative to that
781        Ok(Instant::now())
782    }
783}
784
785#[cfg(test)]
786mod tests {
787    use super::*;
788    use crate::permission::Permission;
789
790    #[test]
791    fn test_role_creation() {
792        let role = Role::new("admin")
793            .with_description("Administrator role")
794            .add_permission(Permission::new("read", "documents"))
795            .add_permission(Permission::new("write", "documents"));
796
797        assert_eq!(role.name(), "admin");
798        assert_eq!(role.description(), Some("Administrator role"));
799        assert_eq!(role.permissions().len(), 2);
800        assert!(role.is_active());
801    }
802
803    #[test]
804    fn test_role_permissions() {
805        let role = Role::new("reader").add_permission(Permission::new("read", "documents"));
806
807        let context = HashMap::new();
808        assert!(role.has_permission("read", "documents", &context));
809        assert!(!role.has_permission("write", "documents", &context));
810    }
811
812    #[test]
813    fn test_role_builder() {
814        let role = RoleBuilder::new()
815            .name("test-role")
816            .description("A test role")
817            .permission(Permission::new("read", "documents"))
818            .metadata("department", "IT")
819            .active(true)
820            .build()
821            .unwrap();
822
823        assert_eq!(role.name(), "test-role");
824        assert_eq!(role.description(), Some("A test role"));
825        assert_eq!(role.metadata("department"), Some("IT"));
826        assert!(role.is_active());
827    }
828
829    #[test]
830    fn test_role_elevation() {
831        let elevation = RoleElevation::new("admin".to_string(), Some(Duration::from_secs(3600)));
832
833        assert_eq!(elevation.role_name(), "admin");
834        assert_eq!(elevation.duration(), Some(Duration::from_secs(3600)));
835        assert!(!elevation.is_expired(Instant::now()));
836    }
837
838    #[test]
839    fn test_inactive_role_permissions() {
840        let mut role = Role::new("inactive").add_permission(Permission::new("read", "documents"));
841
842        role.set_active(false);
843
844        let context = HashMap::new();
845        assert!(!role.has_permission("read", "documents", &context));
846    }
847}