277 lines
10 KiB
Python
277 lines
10 KiB
Python
"""Catálogo mestre de funções Ligbox — padrão Odoo res.groups aplicado à plataforma DevOps.
|
||
|
||
Uma função Desk (`desk_role`) é a **fonte de verdade**; cada serviço/VM recebe um
|
||
mapeamento explícito (grupo nativo, módulo, permissão API). Spec 027.
|
||
|
||
Analogia Odoo:
|
||
res.users.role → desk_users.role (VM122)
|
||
res.groups → PLATFORM_ROLE_CATALOG[*].bindings[*]
|
||
ir.model.access → permissions.py helpers + route guards
|
||
record rules → should_mask_sensitive, ticket assignee, …
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
from typing import Any
|
||
|
||
from app.modules.registry import ROLE_MODULE_DEFAULTS, role_module_defaults
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ServiceBinding:
|
||
"""Como uma função se materializa num serviço concreto."""
|
||
|
||
service: str # desk | vm112 | vm123_foss | vm123_odoo | vm123_openpanel | infra
|
||
binding_type: str # group | module | permission | deep_link | ssh
|
||
value: str
|
||
access: str = "full" # full | read | link | api | none
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PlatformRole:
|
||
id: str
|
||
label: str
|
||
category: str # ops | commercial | business | platform | system
|
||
description: str
|
||
bindings: tuple[ServiceBinding, ...] = ()
|
||
desk_modules: tuple[str, ...] | None = None # None = legacy ops (global toggles)
|
||
|
||
|
||
def _desk_perms(*perms: str) -> tuple[ServiceBinding, ...]:
|
||
return tuple(ServiceBinding("desk", "permission", p) for p in perms)
|
||
|
||
|
||
# ── Catálogo mestre (fonte única para docs, provisionamento e introspecção) ──
|
||
|
||
PLATFORM_ROLE_CATALOG: dict[str, PlatformRole] = {
|
||
"super_admin": PlatformRole(
|
||
id="super_admin",
|
||
label="Super Admin",
|
||
category="ops",
|
||
description="Dono — users, tenants, purge, config global",
|
||
desk_modules=None,
|
||
bindings=(
|
||
ServiceBinding("vm123_odoo", "group", "base.group_system"),
|
||
ServiceBinding("vm123_foss", "group", "admin"),
|
||
ServiceBinding("vm123_openpanel", "role", "Super Admin"),
|
||
ServiceBinding("vm112", "permission", "assist.takeover"),
|
||
ServiceBinding("vm112", "permission", "purge.domain"),
|
||
ServiceBinding("infra", "access", "ssh", "full"),
|
||
*_desk_perms("manage_users", "manage_billing", "run_audit", "manage_vm112_domains"),
|
||
),
|
||
),
|
||
"ops_lead": PlatformRole(
|
||
id="ops_lead",
|
||
label="Chefe Ops",
|
||
category="ops",
|
||
description="Gestão operacional, audit, tickets, domínios VM112",
|
||
desk_modules=None,
|
||
bindings=(
|
||
ServiceBinding("vm112", "permission", "assist.takeover"),
|
||
ServiceBinding("vm112", "permission", "purge.domain"),
|
||
ServiceBinding("infra", "access", "ssh", "link"),
|
||
*_desk_perms("run_audit", "manage_vm112_domains", "manage_billing"),
|
||
),
|
||
),
|
||
"technician": PlatformRole(
|
||
id="technician",
|
||
label="Suporte",
|
||
category="ops",
|
||
description="Tickets atribuídos, assist wizard, migração",
|
||
desk_modules=None,
|
||
bindings=(
|
||
ServiceBinding("vm112", "permission", "assist.takeover"),
|
||
ServiceBinding("vm123_openpanel", "permission", "autologin"),
|
||
*_desk_perms("patch_assigned_tickets", "read_migration"),
|
||
),
|
||
),
|
||
"noc": PlatformRole(
|
||
id="noc",
|
||
label="NOC",
|
||
category="ops",
|
||
description="Monitorização read-only — dados sensíveis mascarados",
|
||
desk_modules=None,
|
||
bindings=(
|
||
ServiceBinding("desk", "permission", "mask_sensitive"),
|
||
ServiceBinding("vm104", "permission", "wazuh.read"),
|
||
*_desk_perms("read_tickets", "read_billing"),
|
||
),
|
||
),
|
||
"sales_admin": PlatformRole(
|
||
id="sales_admin",
|
||
label="Sales Admin",
|
||
category="commercial",
|
||
description="Gerente comercial — pipeline, billing validation, FOSS+Odoo manager",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["sales_admin"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-sales-admin"),
|
||
ServiceBinding("vm123_odoo", "group", "sales_team.group_sale_manager"),
|
||
ServiceBinding("vm123_openpanel", "role", "Admin"),
|
||
*_desk_perms("validate_billing", "create_foss_order", "read_crm_leads"),
|
||
),
|
||
),
|
||
"sales_support": PlatformRole(
|
||
id="sales_support",
|
||
label="Sales Support",
|
||
category="commercial",
|
||
description="Analista comercial — pedidos e CRM, sem validar billing",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["sales_support"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-sales-support"),
|
||
ServiceBinding("vm123_odoo", "group", "sales_team.group_sale_salesman"),
|
||
ServiceBinding("vm123_openpanel", "permission", "autologin"),
|
||
*_desk_perms("create_foss_order", "read_crm_leads"),
|
||
),
|
||
),
|
||
"finance": PlatformRole(
|
||
id="finance",
|
||
label="Financeiro",
|
||
category="business",
|
||
description="FOSSBilling, Odoo fiscal, validação billing",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["finance"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-finance-admin"),
|
||
ServiceBinding("vm123_odoo", "group", "account.group_account_manager"),
|
||
ServiceBinding("vm123_odoo", "group", "account.group_account_invoice"),
|
||
*_desk_perms("validate_billing", "create_foss_order"),
|
||
),
|
||
),
|
||
"marketing": PlatformRole(
|
||
id="marketing",
|
||
label="Marketing",
|
||
category="business",
|
||
description="Campanhas, leads, produtos FOSS",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["marketing"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-marketing"),
|
||
ServiceBinding("vm123_openpanel", "permission", "autologin"),
|
||
*_desk_perms("read_crm_leads", "read_funnel"),
|
||
),
|
||
),
|
||
"seo": PlatformRole(
|
||
id="seo",
|
||
label="SEO",
|
||
category="business",
|
||
description="DNS, Search Console, sites OpenPanel",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["seo"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_openpanel", "permission", "autologin"),
|
||
ServiceBinding("infra", "permission", "cloudflare_dns.read"),
|
||
*_desk_perms("read_funnel", "read_crm_leads"),
|
||
),
|
||
),
|
||
"developer": PlatformRole(
|
||
id="developer",
|
||
label="Developer",
|
||
category="platform",
|
||
description="Código wizard/Desk, GitHub, APIs",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["developer"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-dev-api"),
|
||
ServiceBinding("vm112", "permission", "api.dev_key"),
|
||
ServiceBinding("infra", "access", "github", "full"),
|
||
*_desk_perms("read_events"),
|
||
),
|
||
),
|
||
"devops": PlatformRole(
|
||
id="devops",
|
||
label="DevOps",
|
||
category="platform",
|
||
description="Proxmox, Traefik, pfSense, OpenPanel admin",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["devops"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_openpanel", "role", "Super Admin"),
|
||
ServiceBinding("infra", "access", "ssh", "full"),
|
||
ServiceBinding("infra", "permission", "proxmox", "full"),
|
||
*_desk_perms("manage_vm112_domains"),
|
||
),
|
||
),
|
||
"security_analyst": PlatformRole(
|
||
id="security_analyst",
|
||
label="Segurança / SOC",
|
||
category="platform",
|
||
description="Wazuh, incidentes, resposta",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["security_analyst"]),
|
||
bindings=(
|
||
ServiceBinding("vm104", "permission", "wazuh.manage"),
|
||
*_desk_perms("read_audit_overview"),
|
||
),
|
||
),
|
||
"content_editor": PlatformRole(
|
||
id="content_editor",
|
||
label="Conteúdo / CMS",
|
||
category="platform",
|
||
description="Sites clientes OpenPanel",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["content_editor"]),
|
||
bindings=(
|
||
ServiceBinding("vm123_openpanel", "permission", "autologin"),
|
||
),
|
||
),
|
||
"agentic_operator": PlatformRole(
|
||
id="agentic_operator",
|
||
label="Operador Agentes IA",
|
||
category="platform",
|
||
description="Aprova runbooks A7 e acções agentes",
|
||
desk_modules=tuple(ROLE_MODULE_DEFAULTS["agentic_operator"]),
|
||
bindings=(
|
||
ServiceBinding("desk", "permission", "approve_agent_remediation"),
|
||
),
|
||
),
|
||
"api_service": PlatformRole(
|
||
id="api_service",
|
||
label="API Service",
|
||
category="system",
|
||
description="M2M webhooks e workers",
|
||
desk_modules=("core",),
|
||
bindings=(
|
||
ServiceBinding("vm123_foss", "group", "ligbox-dev-api"),
|
||
ServiceBinding("vm123_odoo", "group", "base.group_system"),
|
||
),
|
||
),
|
||
"agent_system": PlatformRole(
|
||
id="agent_system",
|
||
label="Agent System",
|
||
category="system",
|
||
description="Conta dos agentes A0–A7",
|
||
desk_modules=("core", "events"),
|
||
bindings=(),
|
||
),
|
||
}
|
||
|
||
|
||
def catalog_for_role(role_id: str) -> PlatformRole | None:
|
||
return PLATFORM_ROLE_CATALOG.get(role_id)
|
||
|
||
|
||
def bindings_for_service(role_id: str, service: str) -> list[ServiceBinding]:
|
||
role = catalog_for_role(role_id)
|
||
if not role:
|
||
return []
|
||
return [b for b in role.bindings if b.service == service]
|
||
|
||
|
||
def catalog_export() -> dict[str, Any]:
|
||
"""JSON para API / docs — visão unificada estilo Odoo groups."""
|
||
out: dict[str, Any] = {"roles": {}, "services": ["desk", "vm112", "vm123_foss", "vm123_odoo", "vm123_openpanel", "infra", "vm104"]}
|
||
for rid, role in PLATFORM_ROLE_CATALOG.items():
|
||
mods = role.desk_modules
|
||
if mods is None:
|
||
mods_list = list(role_module_defaults(rid) or []) # type: ignore[arg-type]
|
||
legacy = True
|
||
else:
|
||
mods_list = list(mods)
|
||
legacy = rid in ("super_admin", "ops_lead", "technician", "noc")
|
||
out["roles"][rid] = {
|
||
"id": rid,
|
||
"label": role.label,
|
||
"category": role.category,
|
||
"description": role.description,
|
||
"desk_modules": mods_list,
|
||
"desk_modules_legacy_global": legacy,
|
||
"bindings": [
|
||
{"service": b.service, "type": b.binding_type, "value": b.value, "access": b.access}
|
||
for b in role.bindings
|
||
],
|
||
}
|
||
return out
|