Mountain/IPC/Security/Permission.rs
1//! # Permission Definition (IPC Security)
2//!
3//! ## RESPONSIBILITIES
4//! This module defines the Permission structure used for role-based access
5//! control (RBAC) in the IPC layer.
6//!
7//! ## ARCHITECTURAL ROLE
8//! This module provides the permission definition that represents individual
9//! access rights that can be granted to roles.
10//!
11//! ## KEY COMPONENTS
12//!
13//! - **Permission**: Permission definition with name, description, and category
14//!
15//! ## ERROR HANDLING
16//! N/A - This is a data definition module.
17//!
18//! ## LOGGING
19//! N/A - Permission creation is logged by PermissionManager.
20//!
21//! ## PERFORMANCE CONSIDERATIONS
22//! - Permission definitions are stored in HashMap for O(1) lookup
23//! - Minimal memory footprint for efficient storage
24//!
25//! ## TODO
26//! - Add permission metadata (creation time, last used)
27//! - Implement permission aliases
28//! - Support permission hierarchies (e.g., "file.*" includes all file
29//! permissions)
30
31use serde::{Deserialize, Serialize};
32
33/// Permission definition for RBAC
34///
35/// Permissions represent individual access rights that can be granted to roles.
36/// They follow a naming convention of "resource.action" (e.g., "file.read",
37/// "config.update") for clear organization.
38///
39/// ## Permission Categories
40///
41/// - **file**: File system operations (read, write, delete)
42/// - **config**: Configuration management (read, update)
43/// - **storage**: Storage operations (read, write)
44/// - **system**: System-level operations (external access)
45///
46/// ## Example Usage
47///
48/// ```rust,ignore
49/// let permission = Permission {
50/// name: "file.write".to_string(),
51/// description: "Write file operations".to_string(),
52/// category: "file".to_string(),
53/// };
54/// ```
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct Permission {
57 /// Unique permission identifier (e.g., "file.read", "config.update")
58 pub name:String,
59
60 /// Human-readable description of what this permission allows
61 pub description:String,
62
63 /// Category for groupings (e.g., "file", "config", "storage")
64 pub category:String,
65}
66
67impl Permission {
68 /// Create a new permission
69 pub fn new(name:String, description:String, category:String) -> Self { Self { name, description, category } }
70
71 /// Check if this permission belongs to a specific category
72 pub fn is_in_category(&self, category:&str) -> bool { self.category == category }
73
74 /// Get the resource part of the permission name (before the dot)
75 pub fn resource(&self) -> Option<&str> { self.name.split('.').next() }
76
77 /// Get the action part of the permission name (after the dot)
78 pub fn action(&self) -> Option<&str> { self.name.split('.').nth(1) }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_permission_creation() {
87 let permission =
88 Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
89
90 assert_eq!(permission.name, "file.read");
91 assert_eq!(permission.description, "Read file operations");
92 assert_eq!(permission.category, "file");
93 }
94
95 #[test]
96 fn test_is_in_category() {
97 let permission =
98 Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
99
100 assert!(permission.is_in_category("file"));
101 assert!(!permission.is_in_category("config"));
102 }
103
104 #[test]
105 fn test_resource() {
106 let permission =
107 Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
108
109 assert_eq!(permission.resource(), Some("file"));
110 }
111
112 #[test]
113 fn test_action() {
114 let permission =
115 Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
116
117 assert_eq!(permission.action(), Some("read"));
118 }
119
120 #[test]
121 fn test_invalid_permission_name() {
122 let permission = Permission::new("invalid".to_string(), "Invalid permission".to_string(), "test".to_string());
123
124 // Should return None for invalid format
125 assert_eq!(permission.resource(), Some("invalid"));
126 assert_eq!(permission.action(), None);
127 }
128}