Dependências e pacotes
Versionamento semântico, arquivos de trava e o risco de segurança das dependências transitivas.
As decisões sobre dependências são cinco: quando acrescentar uma, como instalar de forma reproduzível, como atualizar, como tratar vulnerabilidades e como reduzir a superfície de ataque.
Antes de acrescentar uma dependência
Toda dependência nova é código que a equipe passa a manter sem ter escrito. Algumas perguntas antes de instalar:
| Pergunta | Sinal de alerta |
|---|---|
| A biblioteca padrão já resolve? | Uma dependência para UUID, cópia profunda de objetos ou formatação simples de datas |
| O pacote é mantido? | Último lançamento há anos, problemas abertos sem resposta |
| Quem mantém? | Uma única pessoa, sem histórico, para algo crítico |
| Quantas dependências ele traz? | Dezenas de pacotes indiretos para uma função pequena |
| O nome é exatamente o esperado? | Uma letra diferente do pacote popular; poucos downloads; publicado há dias |
| A licença é compatível? | Licenças que impõem obrigações ao seu código (como a GPL em software distribuído) |
Instalação reproduzível
| Ecossistema | Comando para desenvolver | Comando para CI e imagem |
|---|---|---|
| Node | npm install | npm ci |
| Python (pip) | pip install -r requirements.txt | pip install --require-hashes -r requirements.txt, com versões e hashes gerados por pip-compile ou uv |
| Python (Poetry, uv) | poetry install, uv sync | poetry install --sync, uv sync --frozen |
| Go | go get, go mod tidy | go mod download e o build; o go.sum é conferido sempre |
| Java | mvn install | mvn -B verify, com versões exatas e o plugin Enforcer |
| C# | dotnet restore | dotnet restore --locked-mode, com RestorePackagesWithLockFile ativado |
A regra é a mesma em todos: o arquivo de trava vai para o repositório, e o CI e o Dockerfile usam o comando que falha se a trava não bater, em vez de resolver versões novas.
Atualizar: pouco e sempre
| Estratégia | Consequência |
|---|---|
| Nunca atualizar | Vulnerabilidades acumulam; um dia uma atualização obrigatória atravessa várias versões maiores de uma vez |
| Atualizar tudo de vez em quando | Uma mudança enorme, difícil de revisar e de reverter; quando algo quebra, ninguém sabe qual pacote foi |
| Atualizações pequenas e frequentes, automatizadas | Cada mudança é pequena, testada pelo CI e fácil de reverter |
Ferramentas como Dependabot e Renovate abrem pull requests automáticos para cada atualização, com as notas da versão. Uma configuração comum:
| Tipo de atualização | Tratamento |
|---|---|
| Correções (patch) e pacotes de desenvolvimento | Integrar automaticamente se os testes passarem |
| Versões menores | Agrupadas por semana, com revisão rápida |
| Versões maiores | Uma por vez, lendo o guia de migração |
| Correções de segurança | Prioridade imediata |
Atualizar automaticamente só é seguro com testes que realmente exercitam o sistema. Sem eles, a automação só acelera a entrada de defeitos.
Vulnerabilidades
| Ecossistema | Ferramenta de verificação |
|---|---|
| Node | npm audit |
| Python | pip-audit |
| Go | govulncheck, que mostra só as vulnerabilidades em funções que o código realmente chama |
| Java | OWASP Dependency-Check, plugins do Maven e do Gradle |
| C# | dotnet list package --vulnerable |
| Todos | Dependabot, Snyk, Trivy e a varredura do próprio GitHub ou GitLab |
Nem toda vulnerabilidade apontada é explorável no seu sistema. Uma falha numa função que o código nunca chama, ou numa dependência só de desenvolvimento, pesa menos que uma falha alcançável a partir de uma rota pública. O govulncheck faz essa análise para Go; nas outras linguagens, a priorização costuma ser manual:
- A vulnerabilidade está numa dependência que vai para produção?
- O código usa a parte afetada?
- A entrada que dispara a falha pode vir de um usuário externo?
- Qual é a severidade e já existe exploração conhecida?
Reduzir a superfície de ataque
| Prática | O que evita |
|---|---|
| Arquivo de trava com hashes, e instalação exata no CI | Versões e conteúdos inesperados |
Desligar scripts de instalação no CI (npm ci --ignore-scripts), liberando só os pacotes que precisam | Código executado na instalação |
| Registro interno ou proxy (Artifactory, Nexus, Verdaccio) | Dependência direta do registro público; confusão de dependência |
Escopo dos pacotes internos (@empresa/pacote) | Um pacote público ocupando o nome de um interno |
| Ações do CI fixadas por hash, e não por etiqueta | Uma ação de terceiros alterada depois de aprovada |
| Menos dependências | Menos código de terceiros para confiar |
Resumo da decisão
- Antes de instalar: a biblioteca padrão resolve? O pacote é mantido e o nome está certo?
- Arquivo de trava no repositório; instalação exata no CI e no Dockerfile.
- Atualizações pequenas e frequentes, automatizadas, com testes que as validem.
- Vulnerabilidades verificadas no CI e priorizadas pelo que é alcançável.
- Superfície de ataque: scripts de instalação desligados no CI, registro interno, pacotes internos com escopo.
O próximo nível mostra os comandos de cada ecossistema, uma configuração de atualização automática e como isolar uma dependência atrás de uma interface própria nas cinco linguagens.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Política de dependências da equipe
Quero definir a política de dependências da minha equipe. Pergunte qual ecossistema usamos, quantos serviços existem e como as dependências são atualizadas hoje. Ajude a definir: 1. Os critérios para aceitar uma dependência nova. 2. A instalação reproduzível no CI e nas imagens. 3. A estratégia de atualização: frequência, automação, o que integrar automaticamente e o que revisar. 4. A verificação de vulnerabilidades e o critério para bloquear um deploy. 5. As medidas contra ataques à cadeia de suprimentos. Termine com um documento curto que eu possa colocar no repositório.
Priorizar vulnerabilidades
A ferramenta de verificação do meu projeto aponta muitas vulnerabilidades e não sei por onde começar. Pergunte qual ecossistema e ferramenta eu uso e peça que eu cole o resultado da verificação. Explique: 1. Como ler o relatório: pacote, versão, severidade, versão corrigida e caminho na árvore. 2. Como priorizar: produção ou desenvolvimento, uso da parte afetada, exposição a entrada externa, severidade e exploração conhecida. 3. Como corrigir quando a vulnerabilidade está numa dependência indireta. 4. O que fazer quando não há versão corrigida. Depois analise o meu relatório e monte uma lista em ordem de prioridade.
Configurar atualização automática
Quero configurar atualizações automáticas de dependências com Dependabot ou Renovate. Pergunte qual plataforma (GitHub, GitLab) e ecossistemas eu uso, e como estão os testes do projeto. Explique: 1. A diferença entre Dependabot e Renovate. 2. Como agrupar atualizações para não receber dezenas de pull requests. 3. O que integrar automaticamente e com quais condições. 4. Como esperar alguns dias antes de adotar versões recém-publicadas, e por que isso protege contra pacotes comprometidos. 5. Como tratar as atualizações de segurança com prioridade. Termine com o arquivo de configuração pronto para o meu caso.