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	use super::*;
99
100	#[test]
101	fn test_role_creation() {
102		let role = Role::new(
103			"test".to_string(),
104			vec!["permission1".to_string(), "permission2".to_string()],
105			"Test role".to_string(),
106		);
107
108		assert_eq!(role.name, "test");
109		assert_eq!(role.permission_count(), 2);
110	}
111
112	#[test]
113	fn test_has_permission() {
114		let role = Role::new(
115			"test".to_string(),
116			vec!["permission1".to_string(), "permission2".to_string()],
117			"Test role".to_string(),
118		);
119
120		assert!(role.has_permission("permission1"));
121		assert!(!role.has_permission("permission3"));
122	}
123
124	#[test]
125	fn test_add_permission() {
126		let mut role = Role::new("test".to_string(), vec!["permission1".to_string()], "Test role".to_string());
127
128		role.add_permission("permission2".to_string());
129		assert_eq!(role.permission_count(), 2);
130
131		// Adding duplicate should not increase count
132		role.add_permission("permission1".to_string());
133		assert_eq!(role.permission_count(), 2);
134	}
135
136	#[test]
137	fn test_remove_permission() {
138		let mut role = Role::new(
139			"test".to_string(),
140			vec!["permission1".to_string(), "permission2".to_string()],
141			"Test role".to_string(),
142		);
143
144		role.remove_permission("permission1");
145		assert_eq!(role.permission_count(), 1);
146		assert!(!role.has_permission("permission1"));
147
148		// Removing non-existent permission should not cause issues
149		role.remove_permission("permission3");
150		assert_eq!(role.permission_count(), 1);
151	}
152}