Specs stay at repo root (cross-VM). Move deploy and code into logical projects with README per domain, updated manifest.yaml, and symlinks at legacy paths for VM122 backward compatibility.
273 lines
6.4 KiB
Python
273 lines
6.4 KiB
Python
"""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),
|
|
}
|