Skip to main content

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
84	use super::*;
85
86	#[test]
87	fn test_permission_creation() {
88		let permission =
89			Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
90
91		assert_eq!(permission.name, "file.read");
92
93		assert_eq!(permission.description, "Read file operations");
94
95		assert_eq!(permission.category, "file");
96	}
97
98	#[test]
99	fn test_is_in_category() {
100		let permission =
101			Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
102
103		assert!(permission.is_in_category("file"));
104
105		assert!(!permission.is_in_category("config"));
106	}
107
108	#[test]
109	fn test_resource() {
110		let permission =
111			Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
112
113		assert_eq!(permission.resource(), Some("file"));
114	}
115
116	#[test]
117	fn test_action() {
118		let permission =
119			Permission::new("file.read".to_string(), "Read file operations".to_string(), "file".to_string());
120
121		assert_eq!(permission.action(), Some("read"));
122	}
123
124	#[test]
125	fn test_invalid_permission_name() {
126		let permission = Permission::new("invalid".to_string(), "Invalid permission".to_string(), "test".to_string());
127
128		// Should return None for invalid format
129		assert_eq!(permission.resource(), Some("invalid"));
130
131		assert_eq!(permission.action(), None);
132	}
133}