Dev Factory Code Wiki

devfactory-lib-platform

Código compartilhado (pacote único) referenciado por todos os serviços da plataforma Dev Factory,

C# · 27 arquivos MSBuild · 3 arquivos Markdown · 1 arquivos JSON · 1 arquivos 33 arquivos

Endpoints HTTP 8

MétodoRotaArquivo
GET/{**path}DataPlaneEndpoints.cs
POST/{**path}DataPlaneEndpoints.cs
PUT/{**path}DataPlaneEndpoints.cs
PATCH/{**path}DataPlaneEndpoints.cs
DELETE/{**path}DataPlaneEndpoints.cs
GET/relatoriosAppAuth.cs
POST/admin/...AppAuth.cs
POST/aprovarAppAuth.cs

Estrutura

📁 src/23 arquivos
📁 DevFactory.Platform/
📁 DevFactory.Platform.Aws/
📁 tests/7 arquivos
📁 DevFactory.Platform.Tests/
· .gitignore
· README.md
· version.json

README

lib-platform — DevFactory.Platform

Código compartilhado (pacote único) referenciado por todos os serviços da plataforma Dev Factory, para manter uma só implementação de tenancy + governança e evitar reescrever (e errar) o isolamento por serviço. Montado reaproveitando o código que já está bom hoje (core-control Platform/* + services-ai Auth/*), não reimplementando.

Faz parte da migração para serviços standalone com chamada direta (apps chamam os serviços direto;
core-control — era apis-aws — vira control-plane). Plano e contexto em
~/.claude/plans/devfactory-coordination-docs-limp-partitioned-koala.md.

Por que existe

No modelo de chamada direta, cada serviço (services-documents, services-files, …) precisa sozinho de auth, isolamento por tenant, RBAC, rate-limit e metering — coisas que hoje só existem dentro do data-plane do apis-aws. Esta lib carrega isso uma vez só. O contrato (headers/claims) é igual ao que o services-ai já usa:

Invariante de segurança central — ProjectMatchGuard

O instanceId = {project}-{env}-{service} é a única chave de isolamento (Mongo db, prefixo S3, pk DynamoDB, fila SQS, secret, db SQL df_{project}_{env}). Hoje o projectId vem do path — então, na chamada direta, a key do projeto A conseguiria endereçar dados do projeto B.

ProjectMatchGuard fecha isso: se o {projectId} do path não for o da credencial validada → 403. E TenantScope.TryResolve constrói o instanceId sempre a partir do ProjectId da credencial, nunca do path. Este guard é código novo (o services-ai não tem, pois não recebe projectId no path) e é coberto por testes unitários — é o item nº1 da revisão de segurança.

Conteúdo (incremento 1)

ArquivoOrigemO quê
Tenancy/Contracts.cslift de apis-aws Platform/Contracts.csTenantContext, IResourceProvider, ListQuery, Page<T>, Operation
Tenancy/InstanceResolver.cslift de apis-aws Platform/InstanceResolver.csderiva o instanceId (formato preservado byte-a-byte)
Tenancy/ValidatedCredential.csnovoa credencial já validada (espelha KeyValidation + allowedEnvironments/allowedServices)
Tenancy/ProjectMatchGuard.csnovoo guard + TenantScope.TryResolve (isolamento)
tests/…/InstanceResolverGoldenTests.csnovotrava o formato do instanceId (compat. com dados existentes)
tests/…/ProjectMatchGuardTests.csnovokey de A no path de B → negado; instanceId vem do projeto autenticado

Conteúdo (incremento 2 — governança de auth/tenancy)

ArquivoOrigemO quê
Auth/KeyValidation.cslift+estendido de services-airesposta do validate + ponte ToCredential() (null allow-list = todos)
Auth/ProjectKeyValidator.cslift de services-aivalida a project key no core-control (cache 15s, fail-closed); aceita CORE_CONTROL_URL/APIS_AWS_URL
Auth/UsageReporter.cslift de services-aimetering fire-and-forget p/ core-control /internal/usage (genérico: requests+bytes)
Tenancy/RouteScope.csnovoextrai projectId/env do path (puro, testável)
Auth/PlatformGovernance.csnovoAddPlatformGovernance() + UsePlatformGovernance() (auth → ProjectMatchGuard → TenantContext → metering) + AssertProductionReady() fail-closed + HttpContext.GetTenant()

Uso num serviço (Program.cs):


builder.Services.AddPlatformGovernance(o => o.ServiceKey = "documents");
PlatformGovernance.AssertProductionReady();   // fail-closed em Production
...
app.UsePlatformGovernance();   // antes do mapeamento das rotas de dados
// dentro do provider/endpoint:  var tenant = http.GetTenant();  // já isolado por projeto autenticado

Conteúdo (incremento 3 — controller genérico + envelope)

ArquivoOrigemO quê
ApiResults.cslift de apis-aws (sem AWS)envelopes {data} / {data,pagination} + problem+json (RFC 9457)
DataPlaneEndpoints.cslift+adaptado de apis-awsMapDataPlane(): CRUD + custom verbs (:verb) p/ um provider, contexto via GetTenant(); mapper de exceção opcional (IDataPlaneExceptionMapper) mantém a lib cloud-agnostic
Tenancy/DataPlaneRoute.csnovo (puro)parse de collection[/id][:verb] + verbos de leitura

Um serviço completo agora é ~30 linhas: AddPlatformGovernance + registrar 1 IResourceProvider + UsePlatformGovernance() + MapDataPlane().

A liftar nos próximos incrementos

RBAC (Rbac/RbacClientcore-auth) no caminho de JWT do console, validação de JWT Entra (EntraIdentity), rate-limit (TenantRateLimiting/RedisRateLimiting), e o AddPlatform()/UsePlatform() único que compõe governança+dataplane numa chamada. (Project-key + tenancy + metering + CRUD já estão prontos.)

Build / test (no seu lado — a máquina de dev não tem dotnet no PATH)


dotnet test tests/DevFactory.Platform.Tests/DevFactory.Platform.Tests.csproj