Trazendo dados sanitizados de produção para o dev quando não tem rsync
O ambiente de dev do blog-manager sempre rodou com quase nada: um usuário seed, dois blogs fixture. Isso é ótimo para a suite de testes automatizados, que usa fixtures de qualquer forma, mas torna o teste manual (bin/dev, clicando pela interface) praticamente inútil, já que não tem histórico real de posts, nenhuma imagem de destaque real, nada que se pareça com o site de verdade que estou gerenciando. Eu queria uma forma de trazer um snapshot real de produção para o dev sem montar isso na mão toda vez.
O app é SQLite, não Postgres, feito deploy via Kamal com o arquivo do banco de dados vivendo num volume bind-mounted (/data/storage no host, /rails/storage no container). Isso na verdade torna tudo mais simples do que um dump/restore de Postgres, já que o banco inteiro é só um arquivo que eu posso copiar.
O que eu construí
Uma rake task, bin/rails data:pull_from_prod:
- scp o arquivo SQLite de produção para um diretório temp descartável
- Sanitiza no lugar, antes de tocar em qualquer coisa local: zera toda coluna de token/API key criptografada, reseta todas as senhas de usuário para a mesma que
db/seeds.rbjá usa, limpa a tabela de sessions - Pede confirmação, já que está prestes a sobrescrever
storage/development.sqlite3 - Também baixa os arquivos do Active Storage, para que as imagens de destaque realmente resolvam localmente
- Roda as migrations pendentes, já que o schema de produção pode ficar atrás do que eu tenho no checkout local
A parte da sanitização importa mais do que parece. Este app usa Active Record Encryption em coisas como tokens do GitHub e API keys, e o dev não compartilha as chaves de criptografia de produção, então mesmo se eu deixasse essas colunas intactas, elas seriam só lixo no dev, ilegíveis e propensas a estourar erro no decrypt assim que qualquer coisa as tocasse. Zerá-las é a única opção sensata, não só a segura.
O que me surpreendeu
A primeira execução explodiu na hora: no such column: unsplash_access_key. Produção estava rodando um schema de antes de essa migration ser mergeada localmente, o que faz sentido quando penso a respeito (os deploys de produção ficam atrás da main), mas o SQL de sanitização tinha nomes de coluna fixos no código e assumia que o schema local batia com o schema de produção. Corrigi checando PRAGMA table_info antes de tocar em cada tabela e só zerando as colunas que realmente existem naquele snapshot específico.
Segunda surpresa: usei rsync para baixar os arquivos do Active Storage e recebi rsync: command not found, vindo do shell remoto, repassado de volta pela conexão SSH, o que tornou o erro local (unexpected end of file) bem confuso até eu de fato entrar via SSH e checar. O provisionamento de host do Kamal instala o que o Docker/Kamal precisa e nada além disso; rsync nunca fez parte disso. Troquei por um pipe simples de tar sobre SSH, tar -cf - | tar -xf -, já que tar é o mais perto que existe de garantidamente presente, e funcionou de primeira.
Testando de verdade
Rodei contra o host de produção de verdade, em vez de confiar que o código estava certo. Baixei o banco real, confirmei que as colunas sanitizadas realmente estavam nil, subi o servidor de dev, e fiz login via HTTP com a senha resetada contra o usuário real de produção, recebi um 302 e um cookie de sessão, e então confirmei que o dashboard renderizou os dois blogs reais. É bom ter uma task chata de rodar porque ela simplesmente funciona.
O que vem a seguir
Isso cobre a metade “sem dados realistas” do problema. Existe uma questão em aberto separada, se vale a pena manter o ambiente de staging, considerando que ele é pouco usado e tem exatamente esse mesmo problema de dados escassos, de forma independente. Isso está sendo rastreado separadamente; esse mecanismo de sincronização funciona independente de para que lado isso for.
Leitura relacionada
O que acontece quando um job faz broadcast para ninguém
Fechando o loop da imagem de destaque: frontmatter só por inserção, uma guarda que pegou divergência real na primeira execução, e um broadcast sem ouvinte.
Uma correção de desvio de documentação que não foi tão chata quanto parecia
Três itens da auditoria que cada um virou outra coisa: uma alegação meio corrigida, uma recuperação de senha silenciosamente morta, e um e-mail de staging que apontaria para produção.
Um 500 escondido dentro das rotas isoladas de uma engine montada
O painel de jobs retornava um 500 em vez de uma página de login: helpers de rota sem qualificação resolvem contra a engine, não contra a aplicação. Uma linha, mais o gêmeo dormente dela.
Você também pode achar útil
RackNerd VPS
Hospedagem VPS econômica para serviços leves que funcionam continuamente.
Como afiliado da RackNerd, ganho com compras qualificadas.
Saiba maisProton Pass
Gerenciador de senhas focado em privacidade, da equipe por trás do Proton Mail.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisAdGuard para iOS
Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.
Como afiliado da AdGuard, ganho com compras qualificadas.
Saiba mais