Skip to main content

Mountain/IPC/Security/
Role.rs

1//! # Role Definition (IPC Security)
2//!
3//! ## RESPONSIBILITIES
4//! This module defines the Role structure used for role-based access control
5//! (RBAC) in the IPC layer.
6//!
7//! ## ARCHITECTURAL ROLE
8//! This module provides the role definition that groups permissions for
9//! assignment to users.
10//!
11//! ## KEY COMPONENTS
12//!
13//! - **Role**: Role definition with name, permissions, and description
14//!
15//! ## ERROR HANDLING
16//! N/A - This is a data definition module.
17//!
18//! ## LOGGING
19//! N/A - Role creation is logged by PermissionManager.
20//!
21//! ## PERFORMANCE CONSIDERATIONS
22//! - Role definitions are stored in HashMap for O(1) lookup
23//! - Permissions are stored as `Vec<String>` for iteration
24//!
25//! ## TODO
26//! - Add role inheritance support
27//! - Implement role activation/deactivation
28//! - Add role metadata (creation time, last modified)
29//! - Support role aliases
30
31use serde::{Deserialize, Serialize};
32
33/// Role definition for RBAC
34///
35/// Roles are collections of permissions that can be assigned to users.
36/// They provide a convenient way to manage access control by grouping
37/// related permissions together.
38///
39/// ## Role Hierarchy
40///
41/// ```text
42/// admin (full access)
43///     |
44///     ├── developer (read/write files, read config)
45///     └── user (read-only access)
46/// ```
47///
48/// ## Example Usage
49///
50/// ```rust,ignore
51/// let role = Role {
52///     name: "editor".to_string(),
53///     permissions: vec![
54///         "file.read".to_string(),
55///         "file.write".to_string(),
56///         "storage.read".to_string(),
57///     ],
58///     description: "Editor role with file access".to_string(),
59/// };
60/// ```
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct Role {
63	/// Unique role identifier
64	pub name:String,
65
66	/// List of permissions granted by this role
67	pub permissions:Vec<String>,
68
69	/// Human-readable description of the role
70	pub description:String,
71}
72
73impl Role {
74	/// Create a new role
75	pub fn new(name:String, permissions:Vec<String>, description:String) -> Self {
76		Self { name, permissions, description }
77	}
78
79	/// Check if role has a specific permission
80	pub fn has_permission(&self, permission:&str) -> bool { self.permissions.iter().any(|p| p == permission) }
81
82	/// Add a permission to the role
83	pub fn add_permission(&mut self, permission:String) {
84		if !self.has_permission(&permission) {
85			self.permissions.push(permission);
86		}
87	}
88
89	/// Remove a permission from the role
90	pub fn remove_permission(&mut self, permission:&str) { self.permissions.retain(|p| p != permission); }
91
92	/// Get the count of permissions
93	pub fn permission_count(&self) -> usize { self.permissions.len() }
94}
95
96#[cfg(test)]
97mod tests {
98
99	use super::*;
100
101	#[test]
102	fn test_role_creation() {
103		let role = Role::new(
104			"test".to_string(),
105			vec!["permission1".to_string(), "permission2".to_string()],
106			"Test role".to_string(),
107		);
108
109		assert_eq!(role.name, "test");
110
111		assert_eq!(role.permission_count(), 2);
112	}
113
114	#[test]
115	fn test_has_permission() {
116		let role = Role::new(
117			"test".to_string(),
118			vec!["permission1".to_string(), "permission2".to_string()],
119			"Test role".to_string(),
120		);
121
122		assert!(role.has_permission("permission1"));
123
124		assert!(!role.has_permission("permission3"));
125	}
126
127	#[test]
128	fn test_add_permission() {
129		let mut role = Role::new("test".to_string(), vec!["permission1".to_string()], "Test role".to_string());
130
131		role.add_permission("permission2".to_string());
132
133		assert_eq!(role.permission_count(), 2);
134
135		// Adding duplicate should not increase count
136		role.add_permission("permission1".to_string());
137
138		assert_eq!(role.permission_count(), 2);
139	}
140
141	#[test]
142	fn test_remove_permission() {
143		let mut role = Role::new(
144			"test".to_string(),
145			vec!["permission1".to_string(), "permission2".to_string()],
146			"Test role".to_string(),
147		);
148
149		role.remove_permission("permission1");
150
151		assert_eq!(role.permission_count(), 1);
152
153		assert!(!role.has_permission("permission1"));
154
155		// Removing non-existent permission should not cause issues
156		role.remove_permission("permission3");
157
158		assert_eq!(role.permission_count(), 1);
159	}
160}