Environment Composition — hierarchy + leaf-wins overrides
A partir da v4.6, o CipherVault entrega composição de environments hierárquica — uma feature flagship do Pulumi ESC trazida para o modelo brasileiro.
Permite modelar production → base-config, onde production herda
secrets de base-config e pode sobrescrever entries específicas. O
endpoint /compose resolve a chain inteira retornando o effective set
- chain de origem (para debug).
Modelo de dados
| Tabela | Campos relevantes |
|---|---|
environments | id, tenant_id, name, parent_id (nullable), description |
environment_secrets | environment_id, secret_id, key_name |
Tree estrutura via parent_id. Filhos herdam ancestrais; leaf-wins
em conflito de key_name.
Endpoints
GET /environments Lista (paginated)
POST /environments { name, parent_id?, description? }
GET /environments/:id
PUT /environments/:id Update name/description/parent
DELETE /environments/:id
POST /environments/:id/secrets { secret_id, key_name }
DELETE /environments/:id/secrets/:secretId
GET /environments/:id/compose ★ Walk root → leaf, retorna effective
Exemplo
base-config (id=1, parent=null)
↳ DATABASE_HOST = prod.db.acme
↳ LOG_LEVEL = warn
↳ STRIPE_KEY = sk_live_...
staging (id=2, parent=1)
↳ DATABASE_HOST = staging.db.acme ← override
↳ FEATURE_FLAG_X = true ← novo
production (id=3, parent=1)
↳ LOG_LEVEL = info ← override
GET /environments/3/compose:
{
"environment_id": 3,
"name": "production",
"effective": {
"DATABASE_HOST": {
"value_ref": "secret:42:v3",
"source": [{"environment_id": 1, "name": "base-config"}],
"key_name": "DATABASE_HOST"
},
"LOG_LEVEL": {
"value_ref": "secret:43:v1",
"source": [
{"environment_id": 1, "name": "base-config"},
{"environment_id": 3, "name": "production"} ← winner
],
"key_name": "LOG_LEVEL"
},
"STRIPE_KEY": {
"value_ref": "secret:44:v2",
"source": [{"environment_id": 1, "name": "base-config"}],
"key_name": "STRIPE_KEY"
}
}
}
Campo source retorna a chain — útil pra debug "de onde veio esse valor?".
UI
/Environments (v4.7) entrega:
- Tree visual (D3-like) com expand/collapse
- Chain visualization horizontal para um environment selecionado
- Effective secrets table com source highlighting (cor por environment de origem)
- Bind / unbind inline
Use cases típicos
- DEV/HML/PRD shared config —
base-configparent, ambientes filhos com overrides mínimos - Multi-region —
base-prodparent,prod-us-east,prod-sa-eastfilhos com endpoint regionais - Branch/feature configs —
productionparent,production-experiment-Xfilho com 1-2 feature flags
Limitações
- Sem ciclos —
parent_idvalidado para não criar loop - Single inheritance — não há merge de múltiplos parents (single-rooted DAG)
- Compose runtime cost — chain de N níveis = N queries em sequência. Em prática bound em < 10 níveis. Roadmap: cache materializado por environment com invalidação.
- Pulumi ESC features ainda não cobertas em v4.6: imports de outros environments cruzando tenants, expressões
${env.x.y}em values, dynamic providers.
Phase 2 (roadmap)
- Resolution caching com invalidate cascade
- Templating de values (
${env.parent.HOST}:5432/db) - Cross-tenant imports gated por approval
Referências
backend/src/routes/environments.jsno repo do produto- Pulumi ESC docs — comparação
- Blog post v4.6