218 lines
6.0 KiB
Rust
Raw Permalink Normal View History

2025-10-07 10:59:52 +01:00
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct RbacSystem {
roles: HashMap<String, Role>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Role {
pub name: String,
pub permissions: Vec<Permission>,
}
#[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<Role> {
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));
}
}