runner env

Comandos para gerenciar variaveis de ambiente e secrets.

Visao Geral

O Runner separa configuracao em dois arquivos:

  • .env - Variaveis de configuracao (permissao 644)
  • .secrets - Credenciais sensiveis (permissao 600)

Estes arquivos podem ser gerados automaticamente no primeiro deploy via Env Wizard, a partir das secoes environment: e secrets: do .deploy.yml.

Camadas por instancia (v2.85.0)

O env efetivo de um deploy e o merge de duas camadas, a da instancia vencendo:

valor final = .env  +  .env.<instancia>

A base (.env) guarda o que e comum a todas as instancias (TZ, LOG_LEVEL). A camada da instancia (.env.production, .env.staging) guarda o que nao pode ser comum: endpoint de banco, bucket, chave de API do ambiente. App que so tem .env funciona igual — o merge devolve a base, nada a migrar.

A barreira de procedencia

Uma chave listada em required: tem que resolver de fonte escopada por instancia (.env.<instancia>). Resolver so da base compartilhada dispara:

Origem do deploy Comportamento
fetch --deploy (cron) Avisa e segue — o cron nao derruba a frota por config herdada
Interativo / switch-instance Bloqueia — e onde o incidente acontece, e ha um humano para reagir

O caso que a barreira previne: um DATABASE_URL de staging na base satisfazia o required: de production, o deploy passava e o healthcheck ficava verde (banco de staging e um banco valido), mas producao escrevia no lugar errado.

Escape pontual (nao recomendado — o certo e escopar a chave):

RUNNER_ALLOW_SHARED_REQUIRED=1 runner deploy <app>

Escrever na camada certa

runner env set <app> KEY VALOR                      # instancia ATIVA (default)
runner env set <app> KEY VALOR --instance staging   # outra instancia
runner env set <app> KEY VALOR --shared             # base compartilhada (deliberado)

O default deixou de ser a base: escopado por instancia e o seguro, compartilhar e ato deliberado.

Limitacao conhecida: o bundle cifrado (.runner/secrets.enc) e app-level e nao tem dimensao de instancia. Valores em .env.<instancia> nao entram no bundle e nao sao restaurados por runner deploy --all num servidor novo. Trate a camada da instancia como config a reprovisionar no disaster recovery.

Deteccao Automatica de Secrets (v2.4.2)

O runner detecta automaticamente se uma variavel e sensivel pelo nome, usando Aho-Corasick multi-pattern matching com 3 niveis de confianca:

Confianca Comportamento Exemplos
Alta (95%+) Auto-encripta se tem ckey, warning se nao DB_PASSWORD, API_KEY, GITHUB_TOKEN, STRIPE_SECRET
Media (75%) Aviso "pode ser sensivel, use --secret" MY_TOKEN, APP_SECRET, AUTH_BEARER
Nao detectado Salva no .env sem questionamento LOG_LEVEL, DB_HOST, APP_ENV, CACHE_KEY

Falsos positivos conhecidos sao filtrados automaticamente: keyboard, primary_key, max_tokens, public_key, tokenizer, hash_map, cache_key, etc.

Flags

Flag Efeito
(sem flag) Auto-detecta pelo nome. Alta confianca + ckey = encripta. Sem ckey = .env + warning
--secret Forca como secret. Requer ckey — sem ckey retorna erro
--force Forca como secret sem questionamento. Requer ckey
# Auto-detecta: DB_PASSWORD → secret (alta confianca)
runner env set myapp --key DB_PASSWORD --value xxx
# → Com ckey: "Detectado como secret. Salvando em .secrets (encriptado)"
# → Sem ckey: "Salvando em .env (plaintext). Acessivel a qualquer usuario..."

# Forcar como secret (requer ckey)
runner env set myapp --key CUSTOM_FIELD --value xxx --secret
runner env set myapp --key CUSTOM_FIELD --value xxx --force

# Sem ckey + --secret = erro
runner env set myapp --key X --value Y --secret
# → "Secrets requerem encriptacao. Registre a app com --ckey"

Comandos

Status

runner env status --app <path>

Exemplo:

runner env status --app /data/apps/usuario_meu-app

Output:

Environment de meu-app:

.env:
  FLASK_ENV=production
  DEBUG=false
  LOG_LEVEL=info

.secrets:
  DB_PASSWORD=***
  REDIS_PASSWORD=***
  SECRET_KEY=***

A partir da v2.85.0, env status mostra as camadas resolvidas e a origem de cada chave — se veio da base (.env) ou da camada da instancia (.env.<instancia>). Ver Camadas por instancia.

Definir Variavel

runner env set --app <path> --key <key> --value <value>

Exemplo:

runner env set --app /data/apps/meu-app --key LOG_LEVEL --value debug

Definir Secret

runner env set --app <path> --key <key> --value <value> --secret

Exemplo:

runner env set --app /data/apps/meu-app --key API_KEY --value sk_live_xxx --secret

Sem o valor na linha de comando (recomendado para segredo):

runner env set meu-app API_KEY --secret        # pede o valor num prompt oculto (eco *)
printf %s "$SECRET" | runner env set meu-app API_KEY --secret --stdin   # automação

Valor digitado na linha de comando fica no ~/.bash_history e no ps. O runner mascara as linhas antigas nos arquivos de history e avisa; para a sessão atual do shell, instale o gancho: runner shell-hook --install (v2.135.0, shell-hook).

Regenerar Secret

runner env regenerate --app <path> --key <key>

Gera novo valor aleatorio para o secret.

Exemplo:

runner env regenerate --app /data/apps/meu-app --key SECRET_KEY

Validar Variaveis

runner env validate <app> [--required "VAR1,VAR2,VAR3"] [-i <instância>]

Verifica se todas as variaveis obrigatorias estao definidas e nao-vazias.

Por instância (v2.151.0+). A validação faz a mesma conta do deploy: lê as camadas .env / .env.<instância> e, no esquema v2, o arquivo de secrets da instância. Sem -i, vale a instância do registro (state → default do manifesto → production). Instância fora do manifesto é recusada com Instance '<nome>' not found (v2.151.1+).

Antes da v2.151.0, o env validate lia só .env/.secrets e não aceitava -i. Num registro de instância não-default, ele acusava como ausentes chaves que estavam no cofre da instância, enquanto o deploy acertava.

A partir de v2.32.0, sem --required cai no campo required: do .deploy.yml automaticamente. Empty plaintext (KEY=) conta como missing — fecha o cenario do healthcheck loop de 173s descrito em runner deploy.

Exemplo:

# Override explicito
runner env validate meu-app --required "DB_HOST,DB_USER,DB_PASSWORD"

# Usa required: do manifest (v2.32.0+)
runner env validate meu-app

Output (sucesso):

INFO All required variables are present

Output (falha):

ERROR missing_required: variables required by the manifest are unset or
empty: NEXT_PUBLIC_SUPABASE_ANON_KEY, DB_PASSWORD.
Set them with `runner env set <app> <KEY> <VALUE>` (or `--secret -f` for
secrets), then retry the deploy.

Bulk Load (v2.32.0+)

runner env load <app> carrega N keys de uma vez a partir de um arquivo .env-format. Resolve o atrito de loops bash de runner env set quando voce tem 10+ secrets pra setar.

runner env load <app> [--file <path>] [flags]

Flags:

Flag Descricao
--file <path> Caminho explicito do arquivo .env. Sem isso, walks cwd → <app>/pull/ por candidates .env*/.secrets*
--all-secret Forca todas as keys pra .secrets (requer --ckey)
--all-plain Forca todas as keys pra .env (plaintext)
--no-propagate Nao toca apps que compartilham o ckey desta
--yes, -y Pula prompts interativos (file picker + propagation confirm)
--json Output estruturado

Comportamento:

  1. Source resolution: --file explicit ganha; senao varre cwd primeiro, depois <app>/pull/. Templates (.env.example, .env.template, .env.sample) sao excluidos pra nao silenciosamente sobrescrever secrets reais.
  2. Classify: usa o mesmo secret_detect que runner env set usa por default. Override com --all-secret/--all-plain.
  3. Propagate (DEFAULT ON): walks state dir, fingerprint do ckey desta app, aplica o mesmo write set em cada peer com fingerprint igual. Pula com --no-propagate. Confirm prompt antes de aplicar (ou --yes pra CI).

Exemplo: monorepo com 2 apps que compartilham ckey

runner env load web-api --file ./prod.env --yes
# INFO Set NODE_ENV: production (file: /data/apps/web-api/.env)
# INFO Set DB_PASSWORD: *** (encrypted in .secrets)
# INFO Set NODE_ENV: production (file: /data/apps/web-front/.env)
# INFO Set DB_PASSWORD: *** (encrypted in .secrets)
# Loaded 6 plain + 2 secret keys into web-api from ./prod.env.
# Propagated to: web-front

Apenas a app alvo:

runner env load web-api --file ./api-only.env --no-propagate --yes

Re-run e idempotente — no_changes: true quando o arquivo ja foi totalmente carregado.

Match — conferir um valor sem revelar nenhum

runner env match <app> <KEY> [-i <instance>]
runner env match <app> <KEY> --stdin

Resolve o caso de quem precisa alterar um secret e nao sabe qual e o valor atual: voce cola o que tem em maos e o runner responde apenas se e o mesmo. Nem o valor registrado nem o que voce colou aparecem na saida.

Flag Descricao
--stdin Le o valor a comparar do stdin, em vez de argumento (nao fica no historico do shell)
-i, --instance Instance alvo

Issue #81.

List — as KEYS, sem decifrar

runner env list <app> [-i <instance>]

Lista as chaves de secrets sem decifrar nada (esquema v2). Nao precisa da chave privada, e os valores nunca sao exibidos — util para conferir o inventario de secrets de uma app a partir de um contexto que nao pode le-los.

Issue #65.

Unset — remover uma key

runner env unset <app> <KEY>              # remove do .env (plaintext)
runner env unset <app> <KEY> --secret     # remove do .secrets
Flag Descricao
-s, --secret Remove do .secrets em vez do .env

O alvo padrao e o .env, porque o caso comum e derrubar uma variavel plaintext ou uma duplicata que tambem existe encriptada no .secrets. Como o .secrets vence em runtime, remover a copia plaintext nao quebra a app.

Desde a v2.158.0:

  • chave que não está no arquivo-alvo é erro: exit 1, chave_nao_encontrada: '<KEY>' não está em <onde> — nada removido. A mensagem sugere a outra flag (--secret ou sem);
  • se a chave saiu localmente mas o push do cofre falhou: exit 1, cofre_nao_propagado: …. A chave pode voltar no próximo deploy. Confira o token com runner tokens test <app>.

env set e env unset não mudam o container em execução. Aplique com runner deploy <app> --force.

Arquivos

.env

Variaveis de configuracao (nao sensiveis):

FLASK_ENV=production
DEBUG=false
LOG_LEVEL=info
BASE_URL=https://app.meusite.com.br

.secrets

Credenciais sensiveis (encriptadas em repouso com --ckey):

DB_PASSWORD=senha_secreta
REDIS_PASSWORD=outra_senha
SECRET_KEY=chave_muito_secreta_gerada
API_KEY=sk_live_xxxxxxxxxxxx

Permissoes: chmod 600 .secrets

Comportamento por versao:

Versao Sem --ckey Com --ckey
< v2.0.4 .secrets criado em plaintext .secrets encriptado
v2.0.4+ .secrets nao criado — secrets vao pro .env .secrets encriptado (sem mudanca)

runner env set --secret e runner env regenerate continuam gravando no .secrets se ele existir. Se a app nao tem .secrets (registrada sem ckey), estes comandos gravam no .env.

Templates

O Runner processa templates em .env.template:

Sintaxe

# Valor fixo
FLASK_ENV=production

# Gerar automaticamente
SECRET_KEY=${GENERATE:secret:64}
DB_PASSWORD=${GENERATE:password:32}

# Valor manual (prompt no primeiro deploy)
EXTERNAL_API_KEY=${MANUAL:API key do servico externo}

# Referencia a contexto
PROJECT_NAME=${CONTEXT:PROJECT}
DOMAIN=${CONTEXT:DOMAIN}

Tipos de GENERATE

Tipo Descricao Exemplo
secret:N String alfanumerica de N caracteres abc123xyz...
password:N Senha com caracteres especiais aB3$xY9@...
uuid UUID v4 550e8400-e29b-...
hex:N String hexadecimal de N bytes a1b2c3d4...

Variaveis de CONTEXT

Variavel Descricao
PROJECT Nome do projeto
DOMAIN Dominio principal
VERSION Versao atual
INSTANCE Nome da instancia

Docker Compose

O Runner configura env_file automaticamente:

services:
  app:
    env_file:
      - .env
      - .secrets

Provisionamento GENERATE (v1.3.2)

No primeiro deploy, o Runner le .env.template e gera valores para variaveis com ${GENERATE:...}. Os valores gerados sao gravados em .env e .secrets.

Em deploys seguintes, o Runner nao sobrescreve valores ja resolvidos. Variaveis com padrao GENERATE no template sao ignoradas nas flags -e do container, garantindo que o valor gerado no primeiro deploy seja preservado.

Antes da v1.3.2, valores contendo ${GENERATE:...} eram injetados como -e flags no docker run, sobrescrevendo os valores ja resolvidos em .env/.secrets.

Seguranca

  • .secrets tem permissao 600
  • Dollar signs ($) sao escapados para $$
  • Secrets nao aparecem em logs
  • env status mostra *** para secrets
  • v2.50.0: o aviso de divergência do env set (manifesto declara X mas o runtime usa Y) mascara valores de keys sensíveis — do .secrets, declaradas em secrets: do manifesto, ou com nome secret-like — exibindo só um prefixo de 4 chars + tamanho. Antes o valor ia em claro pro stdout.

Encriptacao e Recovery

Se a app foi registrada com runner add --ckey, os arquivos .env e .secrets sao encriptados e persistidos no repositorio como .runner/secrets.enc apos cada deploy.

Em caso de perda do servidor, runner add --ckey restaura automaticamente os secrets a partir do repo.

Consulte o guia Secrets e Encriptacao para detalhes completos.

By Borlot.com.br on 12/02/2026