Appearance
Breaking changes — administração global e alcance cross-tenant (ADR 0007)
Épico 986. Companion do ADR 0007, que registra por que cada mudança foi feita. Aqui fica o que muda no seu ambiente.
Contrato HTTP para o cliente: v1-http-contract-migration. Modelo de trilhos e parametrização de perfis: admin-scoping-guide.
Resumo em uma tela
| # | Mudança | Quem sente |
|---|---|---|
| 1 | Users.AllowCrossTenantAccess deixou de existir | ninguém perde acesso — ver §1 |
| 2 | Assumir o contexto de um tenant exige vínculo UserTenant | automação que mandava X-Tenant-ID arbitrário |
| 3 | switch:any-group-tenant foi removida | quem trocava de tenant por herança de grupo |
| 4 | A role SystemAdmin passou a existir; a Admin da plataforma mudou de conteúdo | cliente/automação que identifica role pelo nome |
| 5 | Revogar permissão de role de sistema do catálogo responde 409 | quem editava GroupAdmin/Visitor/SystemAdmin por API |
| 6 | Teto de menor privilégio ao conceder permissão de plataforma a uma role | Admin de tenant que compunha roles com admin:system |
Nenhum relogin forçado. Nenhuma migração deste épico bumpa token_version — ver §7.
1. Users.AllowCrossTenantAccess deixou de existir
A coluna, a propriedade de domínio, GrantCrossTenantAccess / RevokeCrossTenantAccess, os dois eventos e a entrada de cache foram removidos. O alcance cross-tenant passa a ser decidido só pela permissão: admin:system, manage:all-users ou manage:all-tenants.
Ninguém perde acesso. Quem alcançava /admin/* tinha a flag e a permissão — a permissão basta. Quem tinha só a flag nunca alcançou nada.
O que passa a funcionar: conceder manage:all-users ou manage:all-tenants pela API de roles é o procedimento inteiro. Não há mais um UPDATE no banco a lembrar depois — que era, até aqui, o único caminho existente para criar um segundo administrador global. O scripts/auth/grant-cross-tenant-access.sql foi removido junto.
Se você tem scripts ou dashboards que leem a coluna, eles quebram: a coluna não existe mais no schema.
2. Assumir o contexto de um tenant exige vínculo UserTenant
Vale para todo mundo, inclusive quem tem admin:system. O middleware faz uma pergunta só: existe vínculo UserTenant ativo no tenant nomeado? Nenhuma permissão responde por ela.
Alcançar dados de outros tenants (o trilho /admin/*, o filtro do EF suspenso) e ser um tenant são perguntas separadas, com portões separados. A primeira é permissão; a segunda é vínculo.
Quem sente: automações que mandavam um X-Tenant-ID arbitrário com o token do admin do seed. Elas passam a receber 403. A correção é criar o vínculo — e só; não há permissão que substitua.
O header
X-Tenant-IDe a querytenantIdcontinuam existindo, e continuam sendo lidos apenas quando o token não traztenant_id(tokenglobal, o seletor de tenant). O fluxo de seleção de tenant não mudou.
3. switch:any-group-tenant foi removida
POST /auth/switch-tenant para um tenant sem vínculo agora responde 403 TENANT_FORBIDDEN no próprio switch, em vez de emitir um token que falharia na requisição seguinte.
A permissão saiu do catálogo e do template GroupAdmin, que caiu de 5 para 4 permissões (read:group-tenants, read:group-analytics, read:group-data, manage:child-tenants).
Ninguém perde capacidade real. O caminho removido produzia um token que já não servia para nada: só o handler do switch honrava a permissão, enquanto o middleware continuava exigindo vínculo — a troca era aceita e toda requisição seguinte respondia 403.
A leitura consolidada não muda. ?scope=group continua resolvendo o direito no tenant do grupo (ADR 0006, G4), e os dois gates seguem intactos.
4. A role SystemAdmin passou a existir
| Antes | Depois | |
|---|---|---|
| Roles do tenant plataforma | Admin (wildcard), Visitor, GroupAdmin | SystemAdmin (wildcard), Admin (13 granulares), Visitor, GroupAdmin |
| Roles de um tenant comum | Admin, Visitor, GroupAdmin | inalterado |
Role do admin@local.com | Admin | SystemAdmin |
| Permissões efetivas do operador do seed | admin:system | inalteradas — admin:system |
SystemAdmin só nasce no tenant plataforma e carrega admin:system sozinha. A Admin do tenant plataforma virou uma Admin comum: as mesmas 13 granulares de qualquer outro tenant.
Quem referencia role por nome em cliente ou automação precisa ajustar. O operador da plataforma não está mais na role chamada Admin. Um código que procura Admin para achar o super-admin passa a achar um administrador de tenant.
Não há migração de dados. A
AuthInitialMigrationfoi regenerada e já nasce no estado final — a role, seu grant, oAdminda plataforma com as 13 granulares e oUserRoledoadmin@local.comapontando paraSystemAdmin. Bancos anteriores à consolidação das migrations do GrydAuth não são alcançáveis e são recriados; a base recriada nasce correta pelo seed.
5. Revogar permissão de role de sistema responde 409
A proteção deixou de comparar o literal "Admin" e passou a ser derivada do catálogo. Cobre agora toda role que o catálogo possui.
| Operação | Antes | Depois |
|---|---|---|
DELETE /roles/{id}/permissions/{permId} numa Admin de sistema | 409 CONFLICT | 409 CONFLICT |
idem em SystemAdmin, GroupAdmin ou Visitor de sistema | sucesso | 409 CONFLICT |
| idem numa role que o tenant criou | sucesso | sucesso |
PUT /roles/{id} reconciliando permissões de role do catálogo | falhava só para Admin | falha para qualquer role do catálogo |
Conceder (AssignPermission) não ganhou simetria: é o método pelo qual o seed e o bootstrap convergem uma role para o template, e uma guarda ali proibiria a plataforma de fazer o próprio trabalho.
6. Teto de menor privilégio ao conceder permissão a uma role
| Operação | Antes | Depois |
|---|---|---|
POST /roles/{id}/permissions/{permId} com permissão de alcance de plataforma, por caller que não a possui | 200 | 403 ROLE_ASSIGNMENT_ESCALATION_BLOCKED |
idem pelo PUT /roles/{id} | 200 | 403 |
| as duas, com permissão de alcance de tenant | 200 | 200 — inalterado |
as duas, por caller com admin:system | 200 | 200 — inalterado |
DELETE /roles/{id}/permissions/{permId} | — | inalterado, sem teto |
O teto cobre apenas as permissões que o catálogo declara PermissionReach.Platform: admin:system, manage:all-users e manage:all-tenants. Permissão que o próprio tenant cria para o negócio dele — product:create e afins — o Admin compõe livremente nas roles dele.
Por que isto entrou junto: enquanto a flag da §1 existia, pôr admin:system numa role era um ato de meio efeito. Com a permissão bastando sozinha, e com o endpoint gated apenas por update:roles (que está nas 13 granulares de todo Admin de tenant), o mesmo ato passaria a produzir um administrador global. O teto é a contrapartida da §1.
7. Nenhum relogin forçado
Nenhuma migração deste épico bumpa token_version. Isso corrige o que o backlog do épico afirmava:
- a migração que dropou a coluna não bumpa: a coluna nunca foi claim, então nenhum token vivo carrega um valor dela;
- a migração que removeu
switch:any-group-tenantnão bumpa: depois dela, nada no código lê a string, então uma claim velha não autoriza nada; - a migração de dados do split
SystemAdmin×Adminnão existe — a base nasce no estado final.
Tokens emitidos antes do deploy continuam válidos até expirarem. Os eventos normais que afetam autorização (mudança de role, de permissão, de vínculo) seguem invalidando como sempre.
8. O que não está no checklist deste release
Duas coisas que o backlog do épico previa e que deixaram de existir. Registradas aqui porque a ausência delas é a informação:
Não há migração de dados a rodar manualmente em homologação. O backlog registrava que TenantAdminPermissionDemoter e GroupScopePermissionMigrator só rodam sob ApplyGrydAuthMigrationsAsync, chamada pelo template do host apenas em IsDevelopment() — e que por isso um ambiente com ASPNETCORE_ENVIRONMENT ≠ Development estaria com admin:system em toda role Admin. Os dois migradores foram removidos, com scripts e runbooks. O gatilho de cada um era um banco provisionado antes de uma mudança de catálogo, e a consolidação das migrations do GrydAuth tornou esses bancos inalcançáveis: a base é recriada e nasce correta pelo seed. Não há o que rodar, e não há ninguém para lembrar de rodar.
Não há janela de migração compartilhada a coordenar. O backlog pedia que as USs 1.4 e 3.4 entrassem na mesma janela para não cobrar dois ciclos de relogin. Ver §7: nenhuma das duas bumpa token_version, e a 3.4 não existe.
9. Checklist de deploy
- Aplicar as migrations. Bancos anteriores à consolidação do GrydAuth não sobem — recrie.
- Conferir se alguma automação sua manda
X-Tenant-IDde um tenant onde a conta de serviço não tem vínculo (§2). Se manda, crie o vínculo antes do deploy. - Conferir se algum cliente ou automação identifica o operador da plataforma pelo nome da role
Admin(§4). Se identifica, troque paraSystemAdmin. - Conferir se alguma rotina revoga permissão de
GroupAdmin,VisitorouSystemAdminpor API (§5) — passa a receber 409. - Conferir se alguma rotina de provisionamento anexa
admin:system/manage:all-*a roles usando credencial que não possui a permissão (§6) — passa a receber 403. - Nada a fazer sobre sessões: não há relogin forçado (§7).