"""RBAC helpers for Ligbox Ops Desk — Spec 003 + 027.""" from __future__ import annotations # Ops (Spec 003) OPS_ROLES = frozenset({"super_admin", "ops_lead", "technician", "noc"}) # Comercial (Spec 027) SALES_ROLES = frozenset({"sales_admin", "sales_support"}) # Negócio / plataforma (Spec 027) BUSINESS_ROLES = frozenset( { "finance", "marketing", "seo", "developer", "devops", "security_analyst", "content_editor", "agentic_operator", } ) # Sistema (não humanos) SYSTEM_ROLES = frozenset({"api_service", "agent_system"}) ALL_ROLES = OPS_ROLES | SALES_ROLES | BUSINESS_ROLES | SYSTEM_ROLES # Funções humanas (login Desk) HUMAN_ROLES = OPS_ROLES | SALES_ROLES | BUSINESS_ROLES # Atribuíveis no cadastro Spec 004 (exceto super_admin) ASSIGNABLE_ROLES = HUMAN_ROLES - {"super_admin"} # Compatibilidade com código existente ROLES = HUMAN_ROLES ROLE_LABELS: dict[str, str] = { "super_admin": "Super Admin", "ops_lead": "Chefe Ops", "technician": "Suporte", "noc": "NOC", "sales_admin": "Sales Admin", "sales_support": "Sales Support", "finance": "Financeiro", "marketing": "Marketing", "seo": "SEO", "developer": "Developer", "devops": "DevOps", "security_analyst": "Segurança / SOC", "content_editor": "Conteúdo / CMS", "agentic_operator": "Operador Agentes IA", "api_service": "API Service", "agent_system": "Agent System", } def is_valid_role(role: str) -> bool: return role in ALL_ROLES def is_assignable_role(role: str) -> bool: return role in ASSIGNABLE_ROLES def can_read_tickets(role: str) -> bool: return role in HUMAN_ROLES def can_patch_ticket(role: str, ticket: dict, username: str) -> bool: if role in ("super_admin", "ops_lead"): return True if role == "technician": assignee = ticket.get("assigned_to") return assignee is None or assignee == username return False def can_assign_ticket(role: str, assignee: str | None, username: str) -> bool: if role in ("super_admin", "ops_lead"): return True if role == "technician": return assignee in (None, username) return False def can_run_audit(role: str) -> bool: return role in ("super_admin", "ops_lead") def can_read_audit_overview(role: str) -> bool: return role in ( "super_admin", "ops_lead", "noc", "developer", "devops", "security_analyst", "agentic_operator", ) def can_read_audit_scorecard(role: str) -> bool: return role in ( "super_admin", "ops_lead", "noc", "developer", "security_analyst", "agentic_operator", ) def can_read_cloudflare_dns(role: str) -> bool: return role in ( "super_admin", "ops_lead", "technician", "noc", "seo", "devops", "developer", ) def can_read_funnel(role: str) -> bool: return role in ( "super_admin", "ops_lead", "technician", "noc", "sales_admin", "sales_support", "finance", "marketing", "seo", "developer", "devops", "agentic_operator", ) def can_read_session_timeline(role: str) -> bool: return role in ( "super_admin", "ops_lead", "technician", "sales_admin", "sales_support", "finance", "marketing", "seo", "developer", "devops", "agentic_operator", ) def can_list_webhook_events(role: str, source: str | None = None) -> bool: if role == "noc": return source in (None, "wazuh", "vm112-security") if role == "security_analyst": return source in (None, "wazuh", "vm112-security", "vm112") if role == "finance": return source in (None, "billing", "vm112") if role == "developer": return source in (None, "vm112", "wazuh") return role in HUMAN_ROLES def can_read_crm_leads(role: str) -> bool: return role in ( "super_admin", "ops_lead", "technician", "sales_admin", "sales_support", "marketing", "seo", ) def can_read_assist(role: str) -> bool: return role in ("super_admin", "ops_lead", "technician", "sales_admin", "sales_support") def can_assist_takeover(role: str) -> bool: return role in ("super_admin", "ops_lead", "technician") def can_assist_handoff(role: str, username: str) -> bool: return role in ("super_admin", "ops_lead", "technician") def can_manage_users(role: str) -> bool: return role == "super_admin" def can_manage_vm112_domains(role: str) -> bool: """Admin Desk — domínios orquestrados VM112 (Spec 017).""" return role in ("super_admin", "ops_lead", "devops") def should_mask_sensitive(role: str) -> bool: return role in ("noc", "sales_support") def can_read_migration(role: str) -> bool: return role in ("super_admin", "ops_lead", "technician", "noc", "devops") def can_manage_migration(role: str) -> bool: return role in ("super_admin", "ops_lead", "technician") def can_read_billing(role: str) -> bool: return role in ( "super_admin", "ops_lead", "noc", "finance", "sales_admin", "sales_support", ) def can_validate_billing(role: str) -> bool: """Transicionar billing_state — Spec 023 / FR-027-005 / FR-027-009.""" return role in ("super_admin", "ops_lead", "finance", "sales_admin") def can_manage_billing(role: str) -> bool: return can_validate_billing(role) def can_create_foss_order(role: str) -> bool: return role in ( "super_admin", "ops_lead", "finance", "sales_admin", "sales_support", ) def can_access_foss_admin(role: str) -> bool: return role in ("super_admin", "finance", "sales_admin") def can_access_openadmin(role: str) -> bool: return role in ("super_admin", "devops", "sales_admin") def can_openpanel_autologin(role: str) -> bool: return role in ( "super_admin", "sales_admin", "sales_support", "marketing", "seo", "content_editor", "technician", ) def roles_meta() -> dict: """Metadados para UI — labels e funções atribuíveis no cadastro.""" return { "labels": ROLE_LABELS, "assignable": sorted(ASSIGNABLE_ROLES), "human": sorted(HUMAN_ROLES), }