Achata qualquer formato
.env, YAML, JSON e ConfigMaps do Kubernetes. O formato vem do nome do arquivo; chaves aninhadas viram caminhos.
# app.yaml
db:
host: db.internal
pool:
max: 20
vira
db.host "db.internal" db.pool.max 20
Em algum ponto entre os dois, uma chave de configuração sumiu ou um timeout perdeu um zero. O confdrift compara as configurações dos seus ambientes e mostra o que divergiu, antes que o deploy mostre.
go install github.com/eduardofrafre/confdrift@latest$ confdrift staging/configmap.yaml production/configmap.yaml DATABASE_URL changed staging "postgres://checkout:<redacted>@db.staging.example.com:5432/checkout" production "postgres://checkout:<redacted>@db.prod.example.com:5432/checkout" FEATURE_NEW_CART missing from production staging "true" production (not set) LOG_LEVEL changed staging "debug" production "info" PAYMENTS_TIMEOUT_MS changed staging "3000" production "300" STRIPE_API_KEY changed staging <redacted> production <redacted> 5 of 6 keys drifted across 2 files (1 missing, 4 changed). $ echo $? 1
O problema
Chaves em outra ordem, outra indentação, ou um YAML ao lado de um JSON, e o diff mostra ruído em todo lugar e a mudança real em lugar nenhum.
Uma feature flag que só existe em staging. Um timeout de 300 onde deveria ser 3000. Um número que virou string. Ninguém vê isso no code review.
O drift fica invisível até o código que depende dele chegar em produção. O confdrift traz esse momento para o pull request.
Como funciona
O confdrift nunca compara texto. Ele transforma cada arquivo numa lista plana de caminhos de chave com valores tipados, então formato, ordem e indentação deixam de importar, e só sobram as diferenças reais.
.env, YAML, JSON e ConfigMaps do Kubernetes. O formato vem do nome do arquivo; chaves aninhadas viram caminhos.
# app.yaml
db:
host: db.internal
pool:
max: 20
vira
db.host "db.internal" db.pool.max 20
Cada chave é conferida em todos os arquivos de uma vez, sejam dois ambientes ou dez. Uma chave está igual, alterada ou ausente em algum deles.
| chave | stg | prod | |
|---|---|---|---|
| RETRY_LIMIT | "5" | "5" | igual |
| TIMEOUT_MS | "3000" | "300" | alterada |
| NEW_CART | "true" | - | ausente |
Um relatório legível para você, JSON para scripts, credenciais ocultadas, e um código de saída que o pipeline entende.
Experimente
Este é o motor real do confdrift compilado para WebAssembly, rodando no seu navegador. Nada do que você digita sai desta página. Renomeie um arquivo para mudar o formato.
As mesmas regras da CLI: o tipo conta, então 5432 e "5432" são diferentes, e chaves que parecem credenciais são comparadas mas impressas como <redacted>.
Uso
# dois ambientes confdrift .env.staging .env.production # ou quantos você tiver confdrift dev.yaml staging.yaml prod.yaml # só chaves ausentes em algum lugar confdrift a.env b.env --keys-only # ignora chaves que devem mesmo diferir confdrift a.env b.env --ignore 'DATABASE_*' # para scripts e bots confdrift a.env b.env --format json
As flags podem vir antes ou depois dos nomes de arquivo. --ignore aceita o curinga * e pode ser repetido.
# .github/workflows/config-drift.yml
on: pull_request
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
- run: go run github.com/eduardofrafre/confdrift@latest --keys-only deploy/staging.env deploy/production.env
Num pipeline, --keys-only costuma ser o que você quer: valores diferem entre ambientes por natureza, mas uma chave definida num e não no outro é um bug esperando o próximo deploy.
.env, .env.production, prod.env. Entende aspas, export, comentários e valores de várias linhas. ${VARS} não são expandidas: se a referência mudou, isso é drift.db.pool.max ou servers[0], então dá para comparar um YAML com um JSON.data. A saída de helm template ou kustomize build funciona direto: os outros recursos são ignorados.Valores de chaves que parecem credenciais (*PASSWORD*, *TOKEN*, *SECRET*, *API_KEY* e parecidas) saem como <redacted>, assim como senhas dentro de URLs. Eles continuam sendo comparados, então um segredo rotacionado ainda aparece como drift. --show-secrets mostra os valores.
| saída | significado |
|---|---|
| 0 | Os arquivos concordam |
| 1 | Drift encontrado |
| 2 | Entrada inválida: arquivo ilegível, erro de parse, flag desconhecida |
Instalação
Cerca de 3 MB, e compara uma configuração real em poucos milissegundos. Escolha sua plataforma:
Exemplo para x86-64; em ARM troque amd64 por arm64.
curl -sL https://github.com/eduardofrafre/confdrift/releases/download/v0.1.0/confdrift_0.1.0_linux_amd64.tar.gz | tar xz sudo mv confdrift_0.1.0_linux_amd64/confdrift /usr/local/bin/ confdrift --version
Exemplo para Apple silicon; num Mac Intel troque arm64 por amd64.
curl -sL https://github.com/eduardofrafre/confdrift/releases/download/v0.1.0/confdrift_0.1.0_darwin_arm64.tar.gz | tar xz sudo mv confdrift_0.1.0_darwin_arm64/confdrift /usr/local/bin/ confdrift --version
Baixe o confdrift_0.1.0_windows_amd64.zip (ou a versão arm64), descompacte e coloque o confdrift.exe no seu PATH. Depois, no PowerShell:
confdrift .env.staging .env.production
Com Go 1.24 ou mais recente:
go install github.com/eduardofrafre/confdrift@latest
Todos os builds, com checksums, estão na página de releases.
Open source
Achou um drift que o confdrift deixou passar, ou um formato que ele deveria ler? Abra uma issue. Se ele pegou algo antes do deploy, você pode apoiar pelo PayPal.