DATABASE_URL readonly por padrão

TLDR: Torna DATABASE_URL readonly por padrão em todos os ambientes, com DATABASE_URL_WRITE injetado por um entrypoint do commons apenas nos pods de runtime.

Contexto

Hoje todos os pods têm acesso de escrita ao banco por padrão. Qualquer acesso via shell ou k9s recebe uma conexão de escrita. O objetivo é tornar readonly o padrão e exigir opt-in explícito para escrita, feito pelo entrypoint de runtime.

Objetivos

  • DATABASE_URL = readonly por padrão (todos os pods, console, shell)
  • DATABASE_URL_WRITE = escrita, injetado só pelo entrypoint nos pods de runtime
  • O entrypoint loga o modo do banco com cor: laranja = full access, ciano = readonly
  • Sem mudanças na aplicação — o contrato é puramente de infra/runtime

Fora de escopo

— (não registrado na spec original)

Mudanças

Commons (feito)

  • shell/tasks/docker/entrypoint.sh — injeta DATABASE_URL=$DATABASE_URL_WRITE se definido e loga o modo
  • docker/Dockerfile — adiciona COPY entrypoint no stage de runtime e define ENTRYPOINT ["entrypoint"]

onion-backend (branch feat/database-url-readonly-default)

  • config/settings/base.py — DB_URL → DATABASE_URL
  • bin/console — remove o workaround de DB_URL
  • .infra/terraform/secrets.tf — DATABASE_URL = url readonly, DATABASE_URL_WRITE = url de escrita

Terraform staging (a fazer)

  • database.tf — adicionar digitalocean_database_user.onion_readonly
  • secrets.tf — DATABASE_URL = url do onion_readonly, DATABASE_URL_WRITE = url do onion
  • Permissões via SQL: GRANT SELECT ON ALL TABLES TO onion_readonly

Terraform production (a fazer)

  • database.tf — node_count = 2 (primary + standby), adicionar digitalocean_database_connection_pool com mode = "replica"
  • secrets.tf — DATABASE_URL = url do pool replica, DATABASE_URL_WRITE = url do primary

Manifests k8s (a fazer)

  • Remover as env vars DB_URL e DATABASE_URL_READONLY de todos os deployments
  • Adicionar a env var DATABASE_URL_WRITE a partir do secret

Como verificar

  1. mk console.staging → os.environ.get('DATABASE_URL') retorna a url readonly
  2. mk shell.staging → echo $DATABASE_URL retorna a url readonly
  3. Logs do pod no startup mostram “readonly mode” em ciano ou “full access” em laranja
  4. User.objects.first().save() falha no console (permission denied)
  5. Escritas da aplicação (create/update) funcionam normalmente nos pods web/worker

Documentação

Nenhuma mudança de documentação necessária.