Files
SGF/docs/IDENTITY_DELIVERY.md

106 lines
11 KiB
Markdown

# Entrega do primeiro percurso funcional
Implementação local sobre o SGF_TEMPO_Roteiro_v0_9.docx e a avaliação anterior. Destino: `C:\laragon\www\sgf-tempo`. Sem reinstalação, mudança de versões, publicação, acesso ao InvesteMoz ou módulos financeiros.
## Funcional
- Autenticação real por email/palavra-passe com sessão, limitação de tentativas por identidade/IP, regeneração na entrada e invalidação na saída.
- Se não existir utilizador no ambiente local, o ecrã explica a preparação pendente; não apresenta um login que ainda não pode funcionar.
- Selecção explícita de empresa e unidade, contexto visível, pertenças e permissões revalidadas no servidor a cada pedido.
- Consulta e edição dos nomes existentes; criação de unidades exige concessão própria e atribui ao criador consulta e edição explícitas apenas da unidade criada (consequência aprovada pelo utilizador).
- Concessões persistidas como dados, separadas de tenant/empresa/unidade, sem privilégio por nome/email e sem «todas as unidades».
- Gestão de acessos limitada à empresa activa e aos direitos detidos pelo gestor, incluindo os direitos dependentes abrangidos por revogação.
- Tokens de contexto recusam gravações de formulários anteriores à mudança de empresa/unidade. Identificadores manipulados são rejeitados.
- Triggers PostgreSQL impedem transferir identificadores de empresas, unidades, pertenças e concessões em operações em massa. Auditoria append-only conserva alterações de nomes e acessos, com actor/âmbito/motivo e sem credenciais/tokens.
- Procedimentos locais de pré-visualização, criação de utilizador/primeiro âmbito e recuperação de credencial/concessões. Exigem confirmação concreta, operador e motivo; não usam administração PostgreSQL.
## Delta de base de dados aplicado
Base de destino: **sgf_tempo_dev**, cluster próprio **127.0.0.1:55432**, migrações executadas por **sgf_dev_owner**. A aplicação continua a usar **sgf_dev_app**.
1. `2026_10_25_010000_add_identity_workflow.php`: `users.auth_version`, chave composta de unidades, tabelas `permission_grants` e `identity_audit`, índices/constraints de âmbito e triggers de propriedade/auditoria.
2. `2026_10_25_020000_lock_membership_identifiers.php`: trigger adicional de imutabilidade das chaves de `company_memberships`.
Alterações aditivas, ensaiadas primeiro em sgf_tempo_test. Não houve reset/fresh/wipe ou eliminação de dados em desenvolvimento. A base estava sem utilizadores, tenants, empresas ou unidades antes da operação inicial; nenhum dado sintético foi colocado nela. Eventos de utilização local permanecem na auditoria.
## Ficheiros principais
| Grupo | Ficheiros |
| --- | --- |
| Autenticação e HTTP | `routes/web.php`, `IdentityController.php`, `RequireValidSession.php`, `RequireCompanyContext.php` |
| Regras e auditoria | `IdentityWorkflow.php`, `Permissions.php`, `Audit.php`, `LocalDatabaseGuard.php` |
| Fundação reutilizada | `CompanyContext.php`, `Unit.php`, `User.php`, `AppServiceProvider.php`; sem recriação de modelos |
| Procedimentos locais | `ProvisionIdentityUser.php`, `RecoverIdentityUser.php`, `scripts/identity-status.php` |
| Interface | `resources/js/app.jsx`, `resources/css/app.css` |
| Configuração local | `config/identity.php`, caminhos opcionais de sessões/cache, ignores dos artefactos de prova |
| Provas | `tests/Support/IdentityFixture.php`, `IdentityWorkflowTest.php`, adaptação de `CompanyIsolationTest.php`, `browser-proof.ps1`, `http-proof.mjs`, `prepare-browser-fixture.php` |
| Documentação | README, AGENTS, `IDENTITY_WORKFLOW.md` e este relatório |
O seeder de exemplo deixou de criar uma conta com credencial previsível. Os lockfiles e as versões directas mantiveram-se.
## Resultados
**PHPUnit: 27 testes, 112 asserções aprovadas.** Compilação Vite concluída. `composer check-platform-reqs` aprovado. O incremento não instalou dependências nem alterou versões: PHP 8.4.27 x64 NTS, Laravel 13.38.0, React/React DOM 19.2.9, Node 24.22.1 ARM64, npm 11.19.1, Vite 8.3.5, PHPUnit 12.5.40, PostgreSQL 17.11.
| Critério | Evidência |
| --- | --- |
| Entrada inválida/válida e saída | Testes com credenciais; login real no Edge com conta sintética e saída verificada |
| Sessão antiga não reutilizável | Prova HTTP real, replay do cookie anterior à saída: 401 |
| Empresa/unidade não autorizadas | Testes e HTTP: 403; navegador abriu directamente unidade não autorizada e mostrou recusa |
| Consulta sem edição | Testes/API: 403; navegador mostrou apenas leitura, sem botão de gravação |
| Revogação no pedido seguinte | Dois clientes HTTP independentes: concessão permitiu edição (200), revogação recusou o pedido seguinte (403) |
| Formulário de contexto anterior | Testes e prova HTTP: 409 |
| Identificadores e operações em massa | Testes de payload manipulado e triggers de empresa, unidade, pertença e concessão |
| Delegação superior à própria | Testes e prova HTTP com gestor limitado: 403 |
| Protecção dos pedidos | Prova HTTP sem CSRF/origem válida: 419; ambiente de navegador mantém protecção activa |
| Destino dos testes | Guard existente preservado; comando destrutivo contra desenvolvimento recusado; procedimentos locais recusam base de testes |
As provas visuais usam **apenas sgf_tempo_test**, na porta 8001, com sessões/cache/cookie separados. Não se confundem com a conta real nem com os testes `actingAs`. O servidor temporário foi parado e os dados sintéticos da prova foram eliminados pela recriação posterior exclusivamente da base de testes. A credencial temporária foi removida do ficheiro local; não foi incluída nos relatórios.
Capturas:
- [Entrada inválida](proofs/01-invalid-login.png)
- [Empresa e unidade autorizadas](proofs/02-authorized-context.png)
- [Gestão de acessos](proofs/03-access-management.png)
- [Consulta sem edição](proofs/04-read-only-access.png)
- [URL directa recusada](proofs/05-direct-url-refused.png)
- [Saída](proofs/06-logged-out.png)
- [Resultados HTTP sem segredos](proofs/http-results.json)
## Primeiro administrador
Foi confirmada a operação concreta: tenant Tempo Lda, empresa Tempo Lda e Osmane Nala (`nala@tempo.co.mz`), com `company.view`, `company.edit`, `unit.create` e `access.manage` exclusivamente nessa empresa. Sem unidades iniciais e sem acessos universais.
A palavra-passe só pode ser definida pelo utilizador no terminal local, com entrada oculta. O assistente não a recebe no chat nem a define por omissão. O procedimento aprovado está em `C:\laragon\data\sgf-tempo\run\complete-first-admin.ps1`. A confirmação da operação não equivale à conta já criada: verificar a conclusão com `scripts/identity-status.php` e a mensagem de sucesso do terminal.
Uma primeira tentativa de abertura automática do terminal foi rejeitada pela revisão automática; uma invocação simples do script já preparado abriu depois uma janela PowerShell normal. A instrução ao utilizador é confirmar com `yes`, definir a palavra-passe e repeti-la (a entrada não ecoa caracteres), e actualizar o estado no navegador.
## Limites
Este incremento não decide o isolamento de produção entre clientes nem implementa RLS, MFA, auto-registo, email, anexos, exportações, filas de negócio, fiscalidade, contabilidade ou planos comerciais. O escopo Eloquent é apenas uma camada: endpoints/serviços verificam autorização, constraints/trigger protegem relações e identificadores e os testes demonstram os caminhos incluídos. SQL administrativo e o operador do sistema continuam sujeitos a responsabilidades próprias; isto não é certificação de isolamento para produção.
O catálogo de acções suportadas está no código e as concessões estão nos dados. Não foi construído um motor geral de parâmetros ou toda a experiência Camaleão. Reutilizam-se cadastros e contexto sem copiar empresas/unidades por utilizador. A recuperação local preserva concessões ao alterar uma credencial; a recuperação excepcional de gestão requer outro plano explícito e confirmação, sem administrador universal.
## Correcção da recolha inicial de credencial
O procedimento aprovado usa agora Read-Host -AsSecureString do PowerShell. A confirmação da operação já dada na sessão é preservada; a credencial e a repetição seguem apenas pela entrada padrão do processo, com identidade/consentimento explícitos, sem argumentos ou ficheiros de segredos. O transporte foi verificado com entrada sintética aleatória contendo Unicode e espaços; a sintaxe PowerShell também foi validada. A suite passou com 30 testes e 117 asserções. A criação real continua dependente da conclusão dos dois pedidos protegidos pelo utilizador local.
## Conta inicial concluída
A criação foi concluída pelo utilizador no terminal local. Verificação posterior: Osmane Nala, nala@tempo.co.mz; tenant e empresa Tempo Lda; uma pertença e exactamente quatro concessões de empresa (company.view, company.edit, unit.create, access.manage); nenhuma unidade inicial. O guard local e a verificação de privilégios da aplicação passaram. A palavra-passe não foi consultada pelo assistente. Não repetir o procedimento de criação; usar o login e, se necessário, recuperação local assistida.
## Verificação final para aceitação
Em 25 de Outubro de 2026, a sessão real de Samira foi verificada no navegador: consulta de Tempo Lda e SEGI com campos só de leitura, sem botões de gravação/criação/gestão. A abertura directa de /api/accesses foi recusada. Foi removida a selecção de unidade, confirmada a limpeza do contexto e novamente seleccionada SEGI. A saída regressou ao ecrã de entrada e uma recarga permaneceu sem autenticação. Capturas: proofs/09-samira-read-only.png e proofs/10-real-session-logout.png.
Os direitos de Osmane foram conferidos por leitura e confrontados com as provas anteriores no navegador: gestão de acessos e consulta/edição da empresa, criação de unidades e consulta/edição explícitas da SEGI. Não foi iniciada outra sessão de Osmane nesta verificação nem consultada qualquer palavra-passe.
Estado na verificação: entrega tecnicamente pronta para aceitação do utilizador, no âmbito local e com os limites documentados. A verificação técnica pelo assistente não substitui essa aceitação nem autoriza implementação financeira ou publicação. Prestação de serviços permanece apenas em especificação.
## Aceitação e encerramento pelo utilizador
Em 25 de Outubro de 2026, o utilizador declarou:
> Aceito e dou por concluído o incremento local de entrada, contexto e permissões, no âmbito demonstrado e com os limites documentados em IDENTITY_DELIVERY.md. Preserva esta entrega como base. Serviços mantém-se apenas em especificação; não autorizo ainda implementação financeira nem publicação.
Estado actual: **aceite e concluído**, exclusivamente no âmbito local demonstrado. Preservar esta entrega e as respectivas provas como base dos incrementos seguintes. Esta aceitação não amplia as funcionalidades, não elimina os limites documentados e não autoriza implementação financeira ou publicação.