DevGuideTK
← Trilha Backend

Dependências e pacotes

Versionamento semântico, arquivos de trava e o risco de segurança das dependências transitivas.

O código que você não escreveu

Um backend moderno usa bibliotecas para quase tudo: servidor HTTP, acesso ao banco, validação, datas, logs, clientes de outros serviços. Cada uma é uma dependência, e o gerenciador de pacotes cuida de baixá-las e de manter as versões certas.

EcossistemaGerenciadorArquivo de dependênciasArquivo de trava
Nodenpm, pnpm, Yarnpackage.jsonpackage-lock.json, pnpm-lock.yaml, yarn.lock
Pythonpip, Poetry, uvpyproject.toml, requirements.txtpoetry.lock, uv.lock, requirements.txt com versões e hashes
GoGo modulesgo.modgo.sum
JavaMaven, Gradlepom.xml, build.gradleTrava do Gradle; no Maven, versões exatas no próprio pom.xml
C#NuGet.csprojpackages.lock.json, quando ativado

Dependências diretas e indiretas

As dependências que você declara são as diretas. Cada uma tem as suas próprias dependências, que têm outras, e assim por diante. Essas são as indiretas, ou transitivas.

Medimos com um projeto Node vazio e uma única dependência, o framework Express na versão 4: 1 dependência direta trouxe 68 pacotes para a pasta node_modules.

seu projeto
└── express (direta)
    ├── body-parser
    │   ├── bytes
    │   ├── raw-body
    │   │   └── ...
    ├── cookie
    ├── send
    │   └── ...
    └── ... mais dezenas de pacotes

Cada um desses 68 pacotes foi escrito por alguém, roda com as mesmas permissões que o seu código e pode ter defeitos ou vulnerabilidades. Você escolheu um; confia em todos.

Versionamento semântico

A maioria dos ecossistemas segue o versionamento semântico (semver): um número no formato MAIOR.MENOR.CORREÇÃO, com uma promessa para cada parte.

MudançaExemploPromessa
CORREÇÃO4.17.0 → 4.17.1Só correções; nada muda para quem usa
MENOR4.17.0 → 4.18.0Recursos novos, compatíveis com o que existia
MAIOR4.17.0 → 5.0.0Mudanças que podem quebrar o código de quem usa

O arquivo de dependências costuma declarar um intervalo de versões aceitas, e não uma versão exata:

Notação (npm)AceitaExemplo com 4.17.0
4.17.0Só essa versão4.17.0
~4.17.0Correções4.17.x
^4.17.0Correções e versões menores4.x, a partir de 4.17.0
* ou latestQualquer umaQualquer versão, inclusive a 5

O ^ é o padrão do npm install. A promessa do semver é uma intenção do autor do pacote, e não uma garantia: versões menores às vezes quebram coisas, por engano.

O arquivo de trava

Se o arquivo de dependências aceita um intervalo, o que é instalado depende do dia em que se instala. Testamos: um package.json pedindo express: ^4.17.0, instalado sem arquivo de trava, recebeu a versão 4.22.3, cinco versões menores depois da declarada. Outra pessoa, em outro dia, receberia outra.

O arquivo de trava (lockfile) registra a versão exata de cada pacote, direto e indireto, e um hash do conteúdo. Com ele, todas as instalações, na sua máquina, na do colega, no CI e na imagem de produção, recebem exatamente os mesmos pacotes.

Sem arquivo de travaCom arquivo de trava
Cada instalação pode receber versões diferentesTodas recebem as mesmas versões
"Funciona na minha máquina"O que passou no CI é o que vai para produção
Uma versão nova com defeito entra sem ninguém saberVersões só mudam quando alguém atualiza a trava, numa mudança revisada

Os comandos de instalação exata recusam um arquivo de trava que não bate com o arquivo de dependências. No teste, depois de acrescentar uma dependência no package.json sem atualizar a trava, o npm ci parou com erro, em vez de instalar algo diferente do registrado.

Integridade: o pacote é o mesmo?

O arquivo de trava também guarda um hash do conteúdo de cada pacote. Se o pacote baixado for diferente do registrado, por um registro comprometido ou um ataque no caminho, a instalação falha.

Testamos nos dois ecossistemas que tornam isso mais visível:

TesteResultado
Go, com o hash de uma dependência alterado no go.sumverifying github.com/google/uuid@v1.6.0: checksum mismatch e SECURITY ERROR
pip com --require-hashes e um hash errado para o requestsTHESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE

Os riscos da cadeia de suprimentos

As dependências são a cadeia de suprimentos do software. Os ataques a ela cresceram muito nos últimos anos, porque comprometer um pacote popular atinge milhares de sistemas de uma vez.

RiscoComo acontece
Vulnerabilidade conhecidaUma versão antiga tem uma falha já publicada. No teste, o Express 4.17.0 apareceu no npm audit com 7 vulnerabilidades, 4 delas de severidade alta
Script de instalaçãoO pacote executa código no momento da instalação, com acesso a arquivos e variáveis de ambiente
Nome parecido (typosquatting)Um pacote malicioso com nome quase igual ao de um popular, esperando um erro de digitação
Mantenedor comprometidoA conta de quem publica é invadida, e uma versão nova traz código malicioso
Pacote abandonadoNinguém corrige mais as falhas; às vezes o nome é assumido por outra pessoa
Confusão de dependênciaUm pacote público com o mesmo nome de um pacote interno da empresa é instalado no lugar dele

O segundo risco merece atenção. Criamos um pacote local com um script postinstall. Ao instalá-lo, o script executou na hora e gravou um arquivo com o diretório do usuário e as 40 variáveis de ambiente do processo, onde costumam estar tokens e senhas. Com --ignore-scripts, nada foi executado.

Por que isso importa quando a IA escreve o código

Assistentes sugerem dependências com naturalidade, e às vezes sugerem pacotes que não existem. Quem publica pacotes maliciosos já explora isso, registrando os nomes que os modelos costumam inventar. Outros problemas comuns:

  • Uma dependência nova para algo que a biblioteca padrão já faz.
  • Versões antigas, do período em que o modelo foi treinado, com vulnerabilidades já corrigidas.
  • npm install no Dockerfile e no CI, em vez da instalação exata com o arquivo de trava.
  • O arquivo de trava fora do repositório, ou apagado para "resolver" um conflito.
  • Atualizações grandes, de várias versões maiores de uma vez, sem ler o que mudou.

O próximo nível compara as estratégias de versões, atualização e segurança.

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.

  • Dependências em cinco minutos

    Explique em no máximo cinco minutos de leitura como funcionam as dependências e os gerenciadores de pacotes, para alguém que instala pacotes sem pensar no que vem junto.
    
    Cubra só o essencial: dependências diretas e indiretas, versionamento semântico, o papel do arquivo de trava e por que instalar um pacote pode ser um risco de segurança.
    
    No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • Versionamento semântico e arquivos de trava

    Quero entender versionamento semântico e arquivos de trava de verdade.
    
    Aja como um mentor. Pergunte primeiro qual ecossistema eu uso (npm, pip, Go, Maven, NuGet).
    
    Conduza assim, uma etapa por vez:
    1. O formato MAIOR.MENOR.CORREÇÃO e a promessa de cada parte.
    2. Os intervalos de versão no meu ecossistema (^, ~, versões exatas) e o que cada um aceita.
    3. Por que o mesmo arquivo de dependências instala versões diferentes em dias diferentes.
    4. O que o arquivo de trava guarda e como ele resolve isso.
    5. Os comandos de instalação exata e por que eles falham quando a trava não bate.
    
    Em cada etapa, me proponha um exemplo e peça que eu preveja o resultado.
  • A árvore de dependências

    Quero entender o tamanho real das dependências do meu projeto.
    
    Pergunte qual ecossistema e qual é o arquivo de dependências do meu projeto.
    
    Explique:
    1. A diferença entre dependências diretas e indiretas.
    2. Como listar a árvore completa no meu ecossistema e contar os pacotes.
    3. Como descobrir por que um pacote indireto está ali (qual direta o trouxe).
    4. O que acontece quando duas dependências precisam de versões diferentes do mesmo pacote.
    5. Por que cada pacote indireto é um risco, mesmo que eu nunca o use diretamente.
    
    Depois me ajude a analisar a árvore do meu projeto e apontar dependências que poderiam ser removidas.
  • Ataques à cadeia de suprimentos

    Quero entender os ataques à cadeia de suprimentos de software.
    
    Explique cada um com um caso real conhecido, se houver, e como ele funciona:
    1. Vulnerabilidades em versões antigas.
    2. Scripts de instalação maliciosos.
    3. Nomes parecidos com pacotes populares.
    4. Contas de mantenedores comprometidas.
    5. Confusão de dependência entre pacotes internos e públicos.
    6. Pacotes inventados por assistentes de IA e depois registrados por atacantes.
    
    Para cada um, diga qual defesa reduz o risco. Depois me descreva três situações e pergunte qual ataque cada uma permite. Corrija as minhas respostas.