use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Clone)] pub struct RbacSystem { roles: HashMap, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Role { pub name: String, pub permissions: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Permission { // Server permissions ServerCreate, ServerDelete, ServerRead, ServerUpdate, ServerSsh, // Taskserv permissions TaskservCreate, TaskservDelete, TaskservRead, TaskservUpdate, // Cluster permissions ClusterCreate, ClusterDelete, ClusterRead, ClusterUpdate, // Workspace permissions WorkspaceCreate, WorkspaceDelete, WorkspaceRead, WorkspaceUpdate, WorkspaceActivate, // Workflow permissions WorkflowSubmit, WorkflowCancel, WorkflowRead, // Extension permissions ExtensionLoad, ExtensionRead, // Operation permissions OperationRead, OperationCancel, // System permissions SystemAdmin, SystemMetrics, SystemHealth, AuditRead, } impl RbacSystem { pub fn new() -> Self { let mut roles = HashMap::new(); // Admin role - full permissions roles.insert( "admin".to_string(), Role { name: "admin".to_string(), permissions: vec![Permission::SystemAdmin], }, ); // Operator role - infrastructure operations roles.insert( "operator".to_string(), Role { name: "operator".to_string(), permissions: vec![ Permission::ServerCreate, Permission::ServerDelete, Permission::ServerRead, Permission::ServerUpdate, Permission::TaskservCreate, Permission::TaskservDelete, Permission::TaskservRead, Permission::ClusterCreate, Permission::ClusterDelete, Permission::ClusterRead, Permission::WorkflowSubmit, Permission::WorkflowCancel, Permission::WorkflowRead, Permission::OperationRead, Permission::OperationCancel, ], }, ); // Developer role - read and limited create roles.insert( "developer".to_string(), Role { name: "developer".to_string(), permissions: vec![ Permission::ServerRead, Permission::ServerSsh, Permission::TaskservRead, Permission::ClusterRead, Permission::WorkspaceRead, Permission::WorkflowRead, Permission::OperationRead, Permission::ExtensionRead, ], }, ); // Viewer role - read-only roles.insert( "viewer".to_string(), Role { name: "viewer".to_string(), permissions: vec![ Permission::ServerRead, Permission::TaskservRead, Permission::ClusterRead, Permission::WorkspaceRead, Permission::WorkflowRead, Permission::OperationRead, Permission::SystemHealth, ], }, ); Self { roles } } pub fn check_permission(&self, user_roles: &[String], permission: Permission) -> bool { // Admin role has all permissions if user_roles.contains(&"admin".to_string()) { return true; } // Check if any user role has the required permission for role_name in user_roles { if let Some(role) = self.roles.get(role_name) { if role.permissions.contains(&permission) || role.permissions.contains(&Permission::SystemAdmin) { return true; } } } false } pub fn get_role(&self, role_name: &str) -> Option<&Role> { self.roles.get(role_name) } pub fn add_role(&mut self, role: Role) { self.roles.insert(role.name.clone(), role); } pub fn remove_role(&mut self, role_name: &str) -> Option { self.roles.remove(role_name) } pub fn list_roles(&self) -> Vec<&Role> { self.roles.values().collect() } } impl Default for RbacSystem { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_admin_has_all_permissions() { let rbac = RbacSystem::new(); assert!(rbac.check_permission(&["admin".to_string()], Permission::ServerCreate)); assert!(rbac.check_permission(&["admin".to_string()], Permission::WorkspaceDelete)); } #[test] fn test_operator_permissions() { let rbac = RbacSystem::new(); assert!(rbac.check_permission(&["operator".to_string()], Permission::ServerCreate)); assert!(rbac.check_permission(&["operator".to_string()], Permission::TaskservCreate)); assert!(!rbac.check_permission(&["operator".to_string()], Permission::AuditRead)); } #[test] fn test_viewer_read_only() { let rbac = RbacSystem::new(); assert!(rbac.check_permission(&["viewer".to_string()], Permission::ServerRead)); assert!(!rbac.check_permission(&["viewer".to_string()], Permission::ServerCreate)); assert!(!rbac.check_permission(&["viewer".to_string()], Permission::ServerDelete)); } #[test] fn test_multiple_roles() { let rbac = RbacSystem::new(); let roles = vec!["viewer".to_string(), "developer".to_string()]; assert!(rbac.check_permission(&roles, Permission::ServerRead)); assert!(rbac.check_permission(&roles, Permission::ServerSsh)); } }