ligbox-ops-platform/specs/039-ligbox-ops-authorization-catalog/spec.md
Ligbox Spec Hub b03bb2c37c feat(desk): UI/API Spec 039-041 + deploy atómico e smoke GREEN
Commita governance, user-wizard, operational-feed e catálogo RBAC;
adiciona deploy-desk-full.sh, smoke-desk.sh e regra anti-deploy parcial;
documenta credencial VM112 @betinplace.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 13:32:15 +00:00

420 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Spec 039 — Catálogo Mestre de Autorização Ligbox OPS
**Criado:** 2026-06-29
**Solicitado por:** Roger
**Status:** Aprovado Roger 2026-06-29 — catálogo completo (TODAS superfícies)
**Prioridade:** P0 (governança — pré-requisito da UI Matriz + Controle de acesso)
**Estende:** Spec **003** (RBAC base), **027** (matriz por função), **015** (módulos Desk), **019** (Console)
**Sistemas:** VM122 Desk · VM123 Console/Finance · VM112 Onboard · VM104 Wazuh · Infra (Proxmox, Traefik, pfSense)
---
## 1. Problema (demanda Roger)
Hoje sabemos que **root / `super_admin`** faz tudo (criar, autorizar, gerir, trocar senha), mas **não está documentado nem exposto na UI** o mapa completo de:
- O que **cada função** (`SU`, `CO`, `TEC`, `NOC`, …) pode fazer
- **Porquê** (regra de negócio / risco)
- **Onde** (Desk, Console, FOSS, Odoo, OpenPanel, VM112, APIs internas)
- **A nível de ação** (não só “módulo ON/OFF”): ex. deletar instância OpenPanel, atualizar processo, purge domínio, aprovar runbook A7
Sem este catálogo, a **Matriz de Acesso** e o **Controle de acesso** mostram toggles e módulos, mas **não fecham o mapa** de atribuições por posição.
**Objetivo desta spec:** ser a **fonte única de verdade** para enumerar operações × funções × ambientes, alimentar a Matriz UI (Spec 027-UI) e implementação RBAC (`permissions.py`, bindings Odoo-style, provisionamento VM123).
---
## 2. Relação com specs existentes
| Documento | Nível | O que falta para Matriz completa |
|-----------|-------|----------------------------------|
| [Spec 027](../027-desk-rbac-function-matrix/spec.md) | Função × módulo × ambiente (✅🔒🔗) | Granularidade por **ação** dentro de cada módulo/produto |
| [Spec 027 UI](../027-desk-rbac-function-matrix/ui-access-matrix.md) | Wireframes Matriz | Dados estruturados (YAML) por ação |
| [vm123-product-roles](../027-desk-rbac-function-matrix/contracts/vm123-product-roles.md) | FOSS/Odoo/OpenPanel grupos | Lista exaustiva endpoints FOSS + OpenPanel CE |
| `platform_role_catalog.py` | Bindings por função | Sincronizar com catálogo 039 |
| `permissions.py` | ~30 helpers `can_*` | Um helper por `action_id` do catálogo |
| Controle de acesso (UI) | Toggles informativos | Persistência + ligação a `action_id` |
**Regra:** Spec 039 **não substitui** 027 — **detalha** cada célula da matriz 027 em linhas de ação auditáveis.
---
## 3. Taxonomia de autorização
### 3.1 Camadas
```text
FUNÇÃO (desk_role) ex.: super_admin, ops_lead → código UI: SU, CO, TEC
└── MÓDULO / PRODUTO ex.: admin-users, foss.client, openpanel.site
└── AÇÃO ex.: user.create, domain.purge, instance.delete
└── RECURSO ex.: desk_user, vm112_domain, openpanel_vhost
```
### 3.2 Níveis de efeito (`access_level`)
| Código | Significado | UI Matriz |
|--------|-------------|-----------|
| `full` | CRUD / executar sem aprovação | ✅ |
| `approve` | Executar após aprovação humana | 🟡 |
| `read` | Só leitura (pode mascarar PII) | 🔒 |
| `link` | Deep-link / abrir consola externa | 🔗 |
| `api` | Só via API Desk (M2M ou token) | ⚙️ |
| `system` | Conta sistema / agente | 🤖 |
| `none` | Proibido | ❌ |
### 3.3 Superfícies (`surface`)
| ID | Descrição | Host |
|----|-----------|------|
| `desk` | Ligbox Ops Desk (VM122 UI + API) | desk.ligbox.com.br |
| `console` | Ligbox Ops Console (Spec 019) | console.ligbox.com.br |
| `vm112` | Wizard + Carbonio + API onboard | onboard.ligbox.com.br |
| `vm123_foss` | FOSSBilling Admin API | financeiro.ligbox.com.br |
| `vm123_odoo` | Odoo 16 XML-RPC | financeiro.ligbox.com.br/odoo |
| `vm123_openpanel` | OpenPanel / OpenAdmin / bridge | openpanel.ligbox.com.br |
| `infra` | Proxmox, Traefik, pfSense, SSH hosts | LAN |
| `agents` | Agentes A0A7 | VM122 agentic |
### 3.4 Identificador de ação (`action_id`)
Formato: `{surface}.{domain}.{verb}` — exemplos:
- `desk.auth.user.create`
- `desk.auth.user.freeze`
- `vm112.domain.purge`
- `vm123_openpanel.instance.delete`
- `vm123_foss.invoice.void`
- `console.case.runbook.execute`
---
## 4. Catálogo de funções (códigos UI)
| Código | `desk_role` | Categoria | Mandato resumido |
|--------|-------------|-----------|------------------|
| **RO** | `root` (utilizador) | Sistema | Conta física dono — bypass humano; não é role atribuível |
| **SU** | `super_admin` | Ops | Tudo no Desk + purge + users + módulos + agentes |
| **CO** | `ops_lead` | Ops | Operação diária, audit, domínios, tickets, aprovações ops |
| **TEC** | `technician` | Ops | Tickets atribuídos, assist/takeover, migração e-mail |
| **NOC** | `noc` | Ops | Monitorização read-only, Wazuh, dados mascarados |
| **SAD** | `sales_admin` | Comercial | Pipeline, billing validation, FOSS/Odoo manager |
| **SSU** | `sales_support` | Comercial | CRM, pedidos, clientes — sem validar billing |
| **FIN** | `finance` | Negócio | FOSS/Odoo fiscal, faturas, inadimplência |
| **MKT** | `marketing` | Negócio | Campanhas, produtos FOSS, leads |
| **SEO** | `seo` | Negócio | DNS, sites OpenPanel, performance |
| **DEV** | `developer` | Plataforma | Código, GitHub, APIs, deploy Desk |
| **DVO** | `devops` | Plataforma | Infra, Proxmox, OpenAdmin, SSH |
| **SOC** | `security_analyst` | Plataforma | Incidentes, Wazuh rules, resposta |
| **CMS** | `content_editor` | Plataforma | Sites clientes OpenPanel |
| **AIO** | `agentic_operator` | Plataforma | Aprovar runbooks A7, findings |
| **SVC** | `api_service` | Sistema | M2M webhooks, provisionamento |
| **AGT** | `agent_system` | Sistema | Agentes IA autónomos |
| **PTR** | `partner` | Comercial | Revendedor — clientes próprios, OpenPanel Reseller, FOSS scoped |
### 4.1 Funções RBAC custom (UI)
Funções criadas via `POST /rbac/roles` **MUST** herdar de um único template:
| Template permitido | `desk_role` base | Uso |
|--------------------|------------------|-----|
| **CO** | `ops_lead` | Coordenação, aprovações ops, purge (sem gestão users) |
| **TEC** | `technician` | Suporte restrito — tickets assigned, assist |
**Proibido:** herdar de SU, FIN, DVO ou escolha livre de permissões avulsas no MVP.
---
## 5. Inventário de ações — Controle de identidade (Desk VM122)
### 5.1 Gestão de utilizadores (`desk.auth.*`)
| action_id | Descrição | SU | CO | Demais | API / UI |
|-----------|-----------|:--:|:--:|:------:|----------|
| `desk.auth.user.list` | Listar utilizadores Desk | full | none | none | GET `/v1/auth/users` |
| `desk.auth.user.create` | Criar utilizador (directo) | full | none | none | *gap — hoje só via registo+aprovação* |
| `desk.auth.user.approve_registration` | Aprovar pedido cadastro | full | **full** | none | POST `/v1/auth/registration-requests/{id}/approve` |
| `desk.auth.user.reject_registration` | Rejeitar pedido | full | **full** | none | POST `.../reject` |
| `desk.auth.user.edit` | Editar nome, role, display | full | none | none | PATCH `/v1/auth/users/{username}` |
| `desk.auth.user.freeze` | Desactivar conta (`active=false`) | full | none | **SSU: none** | PATCH `active` |
| `desk.auth.user.password.reset` | Definir nova senha (admin) | full | none | none | PATCH `password` |
| `desk.auth.user.2fa.reset` | Reset TOTP + backup codes | full | none | none | POST `.../reset-2fa` |
| `desk.auth.user.delete` | Remover utilizador | none | none | none | *não implementado — usar freeze* |
| `desk.auth.user.groups.assign` | Ligar grupos/bindings VM123 | full | none | none | Fase 3 `vm123/identity` |
| `desk.auth.role.create` | Criar função custom RBAC | full | none | none | POST `/rbac/roles` |
| `desk.auth.role.clone` | Clonar função | full | none | none | POST `/rbac/roles/{id}/clone` |
| `desk.auth.role.freeze` | Pausar função | full | none | none | PATCH `/rbac/roles/{id}/status` |
| `desk.auth.modules.toggle` | Activar/desactivar módulos Desk | full | none | none | PATCH `/v1/modules/{id}` |
**Porquê:** credenciais humanas Ligbox = superfície de ataque máxima. **Excepção Roger:** CO aprova cadastros; freeze/reset senha permanece **SU only**; **SSU nunca congela**.
### 5.2 Conta própria (`desk.account.*`)
| action_id | Descrição | Quem |
|-----------|-----------|------|
| `desk.account.password.change` | Trocar própria senha + 2FA | Qualquer autenticado |
| `desk.account.2fa.setup` | Configurar TOTP | Qualquer autenticado |
| `desk.account.console_handoff` | Token para Console | Staff com acesso Console |
---
## 6. Inventário — Módulos Desk (por `module_id`)
Cada módulo (Spec 015 `registry.py`) decompõe-se em **acções UI + API**. Resumo por módulo:
### 6.1 `core` — Dashboard, Tickets, Conta
| action_id | Descrição | SU | CO | TEC | NOC | SAD | SSU |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|:---:|
| `desk.ticket.list` | Ver tickets | full | full | full | read* | full | full |
| `desk.ticket.read` | Detalhe ticket | full | full | full | read* | full | full |
| `desk.ticket.patch` | Actualizar estado/notas | full | full | assigned | none | full | full |
| `desk.ticket.assign` | Atribuir responsável | full | full | self | none | full | full |
| `desk.ticket.close` | Fechar ticket | full | full | assigned | none | full | full |
| `desk.dashboard.kpi` | KPIs resumo | full | full | full | read | full | full |
\* NOC: dados sensíveis mascarados (Spec 003).
### 6.2 `overview-home` — Serviços IaaS (Spec 018)
| action_id | Descrição | SU | CO | TEC | DVO | FIN |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|
| `desk.services.client.list` | Listar clientes/domínios | full | full | full | read | read |
| `desk.services.catalog.read` | Catálogo cPanel/serviços | full | full | full | read | read |
| `desk.services.process.update` | Actualizar processo onboard | full | full | read | api | none |
| `desk.purge.auth.generate` | Gerar código purge (root pwd) | full | none | none | none | none |
### 6.3 `vm112-domains` + purge (Spec 017, 032)
| action_id | Descrição | SU | CO | TEC | DVO |
|-----------|-----------|:--:|:--:|:---:|:---:|
| `vm112.domain.list` | Listar domínios orquestrados | full | full | read | read |
| `vm112.domain.read` | Detalhe domínio | full | full | read | read |
| `vm112.domain.purge` | Purge completo domínio | full | full | none | approve |
| `vm112.purge.job.recover` | Recuperar job purge falhado | full | full | none | full |
### 6.4 `assist` — Wizard takeover (Spec 010)
| action_id | Descrição | SU | CO | TEC |
|-----------|-----------|:--:|:--:|:---:|
| `desk.assist.session.list` | Sessões activas wizard | full | full | full |
| `desk.assist.takeover` | Assumir sessão cliente | full | full | assigned |
| `desk.assist.handoff` | Passar sessão | full | full | full |
| `desk.assist.action.execute` | Acções assist aprovadas | full | full | assigned |
### 6.5 `billing-recurrence` (Spec 023)
| action_id | Descrição | SU | CO | FIN | SAD | SSU |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|
| `desk.billing.account.read` | Ficha conta cliente | full | full | full | full | read |
| `desk.billing.state.validate` | Validar billing_state | full | full | full | full | none |
| `desk.billing.link.foss` | Deep-link FOSS | full | full | full | full | link |
### 6.6 `email-migration` (Spec 013, 019)
| action_id | Descrição | SU | CO | TEC | DVO |
|-----------|-----------|:--:|:--:|:---:|:---:|
| `desk.migration.job.create` | Criar job imapsync | full | full | full | read |
| `desk.migration.job.cancel` | Cancelar job | full | full | assigned | none |
| `desk.migration.dns.gate` | Gate DNS pré-migração | full | full | full | read |
### 6.7 `infra` / `infra2-soc` (Spec 033)
| action_id | Descrição | SU | CO | DVO | SOC | DEV |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|
| `desk.infra.stack.read` | Stack health VMs | full | full | full | full | read |
| `desk.infra.stack.probe` | Executar probe serviço | full | full | full | read | api |
| `desk.infra.deploy` | Deploy API/frontend | full | none | full | none | full |
### 6.8 `agentic-ops` (Spec 029, 030)
| action_id | Descrição | SU | CO | AIO | SOC | DEV |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|
| `desk.agent.finding.read` | Ver findings | full | full | full | full | full |
| `desk.agent.runbook.approve` | Aprovar remediação A7 | full | full | full | scope | none |
| `desk.agent.binding.toggle` | UI/Focus/Approve agente×função | full | none | none | none | none |
### 6.9 `events`, `leads`, `audit`, `dns`
Ver matriz Spec 027 §3.2 — cada endpoint `main.py` mapeia para `action_id` (anexo A em `contracts/action-catalog.yaml`).
---
## 7. Inventário — VM123 produtos (granular)
### 7.1 FOSSBilling (`vm123_foss.*`)
Módulos API: `client`, `order`, `invoice`, `product`, `service`, `staff`, `support`, `extension`, hosting→OpenPanel.
| action_id | sales_admin | sales_support | finance | marketing | developer |
|-----------|:-----------:|:-------------:|:-------:|:---------:|:---------:|
| `vm123_foss.client.create` | full | full | full | none | api |
| `vm123_foss.client.delete` | full | none | full | none | none |
| `vm123_foss.order.create` | full | full | read | none | api |
| `vm123_foss.invoice.create` | full | read | full | none | none |
| `vm123_foss.invoice.void` | full | none | full | none | none |
| `vm123_foss.product.edit` | full | read | read | full | api |
| `vm123_foss.staff.manage` | none | none | read | none | api |
| `vm123_foss.hosting.provision` | full | full | read | none | api |
Detalhe endpoints: [vm123-product-roles.md §2](../027-desk-rbac-function-matrix/contracts/vm123-product-roles.md).
### 7.2 Odoo 16 (`vm123_odoo.*`)
| action_id | sales_admin | sales_support | finance |
|-----------|:-----------:|:-------------:|:-------:|
| `vm123_odoo.partner.read` | full | full | full |
| `vm123_odoo.partner.write` | full | full | full |
| `vm123_odoo.sale.order.create` | full | full | read |
| `vm123_odoo.invoice.post` | full | none | full |
| `vm123_odoo.account.move.validate` | none | none | full |
Grupos: `group_sale_manager`, `group_sale_salesman`, `account.group_account_manager`.
### 7.3 OpenPanel (`vm123_openpanel.*`)
| action_id | Descrição | SU | **CO** | SAD | SSU | SEO | CMS | DVO |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|:---:|:---:|
| `vm123_openpanel.site.create` | Novo site/vhost | full | full | full | full | full | full | full |
| `vm123_openpanel.site.delete` | **Remover instância** | full | **full** | none | none | none | none | **none** |
| `vm123_openpanel.ssl.manage` | Certificados LE | full | full | link | link | full | full | full |
| `vm123_openpanel.db.create` | Base de dados | full | full | link | link | full | full | full |
| `vm123_openpanel.cron.manage` | Cron jobs | full | full | none | none | read | full | full |
| `vm123_openpanel.backup.restore` | Restaurar backup | full | full | none | none | none | read | full |
| `vm123_openpanel.openadmin.access` | Painel OpenAdmin :2087 | full | full | link | none | link | none | full |
| `vm123_openpanel.autologin.client` | Login cliente (bridge) | full | full | full | full | full | full | link |
**Gap actual:** Desk não expõe toggles por `action_id` OpenPanel — só deep-links e provisionamento M2M.
---
## 8. Inventário — Console (Spec 019)
**Decisão Roger:** Console na **mesma Matriz** do Desk (superfície `console`, aba dedicada, RBAC herda role Desk via handoff).
| action_id | Descrição | SU | CO | TEC | SOC | AIO |
|-----------|-----------|:--:|:--:|:---:|:---:|:---:|
| `console.case.create` | Abrir chamado CH-* | full | full | full | full | read |
| `console.case.assign` | Assumir chamado | full | full | full | full | none |
| `console.case.timeline.read` | Timeline correlacionada | full | full | full | full | full |
| `console.discover.search` | Discover (estilo Wazuh) | full | full | read | full | read |
| `console.runbook.execute` | Executar runbook | full | full | none | scope | approve |
| `console.wizard.assist.view` | Passo actual wizard | full | full | full | read | read |
| `console.link.wazuh` | Deep-link VM104 | full | full | read | full | read |
Console autentica via **handoff** Desk (`/v1/auth/console-handoff`) — RBAC herda role Desk.
---
## 9. Inventário — Partner / Revendedor (`partner` · PTR)
| action_id | Descrição | PTR | Notas |
|-----------|-----------|:---:|-------|
| `desk.partner.dashboard.read` | Dashboard revendedor (clientes próprios) | full | Módulo `partner-portal` |
| `vm123_foss.client.create` | Criar cliente FOSS (scoped) | full | Só tenants do partner |
| `vm123_foss.order.create` | Pedidos FOSS | full | |
| `vm123_foss.invoice.read` | Ver faturas clientes | read | Sem void |
| `vm123_openpanel.site.create` | Provisionar hosting cliente | full | Via bridge |
| `vm123_openpanel.autologin.client` | Painel cliente | full | |
| `vm123_openpanel.site.delete` | Deletar instância | none | Só SU/CO Ligbox |
| `desk.auth.*` | Qualquer gestão Desk | none | |
| `console.*` | Console ops | none | |
**OpenPanel nativo:** role `reseller` (Spec 028). **FOSS:** grupo `ligbox-partner` (criar no Admin).
---
## 10. Inventário — VM112 Wizard
| action_id | Descrição | SU | CO | TEC | DEV |
|-----------|-----------|:--:|:--:|:---:|:---:|
| `vm112.wizard.session.read` | Estado sessão onboard | full | full | assigned | read |
| `vm112.carbonio.mailbox.create` | Criar caixa mail | api | api | api | api |
| `vm112.carbonio.block.release` | Libertar ACCOUNT_EXISTS | full | full | none | api |
| `vm112.dns.verify` | Verificar DNS wizard | full | full | read | read |
| `vm112.api.webhook.emit` | Emitir evento (sistema) | system | system | system | system |
---
## 11. Matriz resumida — Quem faz o quê (visão Roger)
| Área | Quem manda | Porquê |
|------|------------|--------|
| Criar/editar/freeze utilizadores Desk | **SU** | Credenciais internas |
| **Aprovar cadastros** | **SU**, **CO** | Roger — CO autónomo |
| **Congelar users** | **SU only****SSU nunca** | Segregação comercial |
| Purge domínio / dados cliente | **SU**, **CO** (DVO recover job) | Irreversível — Spec 032 |
| Validar billing / faturação | **SU**, **CO**, **FIN**, **SAD** | Segregação comercial vs financeira |
| FOSS pedidos e clientes | **SAD**, **SSU**, **PTR** (scoped) | Linha de frente |
| FOSS faturas / void | **FIN**, **SU** | Risco fiscal |
| **OpenPanel delete instance** | **SU**, **CO only** | Downtime — Roger 2026-06-29 |
| OpenPanel conteúdo sites | **CMS**, **SEO**, **MKT** | Operação editorial |
| Tickets / assist | **TEC** (assigned), **CO**, **SU** | Menor privilégio |
| Infra / deploy | **DVO**, **DEV**, **SU** | Separação código vs infra |
| Agentes A7 remediação | **AIO**, **CO**, **SU** | Human-in-the-loop |
| Módulos Desk ON/OFF | **SU** | Feature flags globais |
| **Console** | Mesma matriz Desk | Handoff — Roger |
| **RBAC custom** | Herda **CO** ou **TEC** | Templates only |
---
## 12. Implementação — fechar o mapa na UI
### Fase A — Catálogo (esta spec) ✅
- [x] Taxonomia `action_id`
- [x] Inventário por superfície (Desk + VM123 + Console + VM112 + Partner)
- [x] Decisões Roger validadas (§13)
### Fase B — `contracts/action-catalog.yaml` ✅ v1.1
- Lista machine-readable: `action_id`, `label`, `surface`, `roles{}`, `api_route`, `spec_ref`
- Gerar toggles Controle de acesso + export CSV Matriz
### Fase C — API RBAC
- `GET /rbac/actions` — catálogo completo
- `PATCH /rbac/roles/{id}/actions` — persistir overrides (só SU)
- `permissions.py`: `can_action(role, action_id)` único entry point
### Fase D — UI
- Aba **Controle de acesso**: toggles ligados a YAML (não só informativos)
- Abas Matriz: filtrar por `surface` (Desk | FOSS | Odoo | OpenPanel | Console)
- Sidebar função: mostrar **contagem de acções** full/read/none
---
## 13. Decisões Roger (2026-06-29) — FECHADAS
| # | Pergunta | Decisão |
|---|----------|---------|
| 1 | `sales_support` congela utilizadores? | **Não** — só SU |
| 2 | `ops_lead` aprova cadastros sem SU? | **Sim** — CO autónomo |
| 3 | Deletar instância OpenPanel | **SU + CO only** (não DVO) |
| 4 | Console na mesma Matriz? | **Sim** — mesma matriz Desk |
| 5 | RBAC custom herda de? | **CO ou TEC only** |
| 6 | Partner/revendedor | **Nesta spec** — função `partner` (PTR) |
| 7 | Prioridade granularidade | **TODOS** — Desk + FOSS + Odoo + OpenPanel + Console |
**Implementação código (parcial):** `can_approve_registration`, `can_openpanel_delete` → SU+CO; rotas registo actualizadas.
---
## 14. Critérios de aceite
- **FR-039-001**: Cada `action_id` MUST ter exactamente uma linha no catálogo YAML.
- **FR-039-002**: Cada função humana MUST ter coluna em todas as tabelas §59.
- **FR-039-003**: UI Controle de acesso MUST reflectir catálogo (não lista hardcoded).
- **FR-039-004**: Alteração de permissão MUST gerar audit log (`rbac_audit`).
- **FR-039-005**: RO/root MUST NOT aparecer como role atribuível — só nota §4.
- **FR-039-006**: Função `partner` MUST estar no catálogo com scope tenant isolado.
- **FR-039-007**: RBAC custom MUST declarar `inherits_from: ops_lead | technician`.
---
## Anexos
- `contracts/action-catalog.yaml` — inventário estruturado (geração automática)
- `../027-desk-rbac-function-matrix/spec.md` — matriz macro
- `../../projects/ops-desk/api/app/platform_role_catalog.py` — bindings código
- `../../projects/ops-desk/api/app/permissions.py` — guards actuais