Skip to main content

npm Shrinkwrap renovado: como bloquear dependências do npm com Package-Lock e Yarn.Lock

Escrito por
Headshot of Assaf Hefetz

Assaf Hefetz

10 de janeiro de 2018

0 minutos de leitura

Em 2016, o gerenciamento de dependências ganhou destaque no mundo todo quando um desenvolvedor desconhecido removeu do registro um pequeno pacote do Node.js chamado left-pad — o que quebrou milhares de projetos que dependiam dele e tirou do ar alguns dos maiores sites do mundo. A npm, Inc. precisou intervir e restaurar o pacote para acabar com o caos.

Essa história mostra o quanto as dependências são importantes. Se elas não estiverem disponíveis ou forem diferentes do esperado, problemas sérios podem acontecer.

Esqueça o ShrinkWrap: uma forma elegante de bloquear dependências no Node

Bloquear ou “fixar” dependências é uma prática recomendada amplamente adotada nos ecossistemas Ruby, Python e em outros. A ideia é congelar a versão de um pacote e de suas dependências para que, ao implantar um projeto, sempre seja instalada a mesma versão de cada dependência, tornando a instalação confiável e previsível.

No Node.js, essa prática era bem menos comum até recentemente. O npm Shrinkwrap era a solução, mas tinha vários problemas. Um deles é que o arquivo shrinkwrap.json, que contém informações confidenciais sobre suas dependências, pode ser incluído ao publicar um pacote. Outro é que o Shrinkwrap dificulta a adição de novas dependências. Além disso, o shrinkwrap apresenta um risco de segurança: pode ser vulnerável a ataques de execução remota de código quando não são usadas URLs HTTPS.

Recentemente, a comunidade npm comemorou uma solução mais nova e elegante, integrada ao npm 5: package-lock.json. Quem usa Yarn já contava com o yarn.lock, que oferece bloqueio de dependências integrado para Node. Vamos falar dessas duas soluções daqui a pouco.

Mas, antes, será que você deve bloquear as dependências?

Prós e contras de bloquear (fixar) suas dependências

Muitos profissionais, e até mesmo o guia do governo dos EUA para fabricantes de software, “Before you ship”, recomendam que os projetos fixem todas as dependências. O motivo:

  • Alterações incompatíveis — novas versões das dependências podem introduzir alterações incompatíveis com seu código ou com sua implementação específica.

  • Bugs ou problemas — uma nova versão pode apresentar problemas que passaram despercebidos pelos responsáveis pelo pacote. Como não é possível testar todas as dependências do seu código a cada atualização, é melhor usar por padrão uma versão que já tenha comprovado funcionar no seu ambiente.

  • Previsibilidade — o desenvolvimento ágil e a entrega contínua se baseiam na capacidade de implantar software automaticamente e de forma previsível. Atualizações de pacotes que podem causar comportamentos inconsistentes ou imprevisíveis vão contra essa previsibilidade.

Fixar pacotes também tem desvantagens:

  • Segurança — a Snyk oferece uma ferramenta que verifica vulnerabilidades em código aberto, por isso conhecemos bem os riscos inerentes às dependências. Nossos dados mostram que, pelo menos na comunidade Node.js, 76% dos projetos usam pacotes com vulnerabilidades conhecidas. Ao bloquear ou fixar suas dependências, você também mantém as vulnerabilidades. Se um problema de segurança for descoberto e o responsável pelo pacote lançar uma correção, você continuará usando a versão antiga e vulnerável.

  • Módulos de terceiros — se você é responsável por um módulo de terceiros que, por sua vez, é uma dependência de outros projetos, fixar suas dependências obrigará seus usuários a permanecer nas mesmas versões. A documentação de empacotamento do Python, por exemplo, diz que isso é restritivo demais e não é considerado uma boa prática. Agradecemos a Dustin Ingram por chamar nossa atenção para isso.

Embora o problema de segurança seja significativo, a maioria dos desenvolvedores não vai abrir mão dos benefícios de instalações e implantações previsíveis. Nossa recomendação: bloqueie as dependências, mas inclua a verificação de vulnerabilidades no seu processo de build.

Se você tiver testes e monitoramento de segurança em vigor, saberá quando uma dependência ficar desatualizada ou quando vulnerabilidades forem descobertas e poderá atualizá-la nesse momento. Em um mundo ideal, você atualizaria imediatamente todos os componentes de código aberto do seu projeto assim que novas versões fossem lançadas, para obter a máxima proteção contra falhas e vulnerabilidades. Atualizar pelo menos quando uma vulnerabilidade conhecida for descoberta parece ser uma segunda melhor opção aceitável.

Como bloquear dependências com package-lock

package-lock.json é um novo recurso do npm 5 que descreve a árvore de dependências exata gerada nas instalações anteriores. Assim, é possível gerar uma árvore de dependências idêntica nas instalações seguintes, independentemente de atualizações intermediárias das dependências.

O npm 5 cria automaticamente o arquivo package-lock, que deve ser incluído no controle de versão. Embora isso possa ser trabalhoso, há dois grandes benefícios:

  • Depois de adicionar package-lock ao seu repositório, você conta com uma camada extra de segurança. É possível usar valores de integridade SHA para confirmar que o que está sendo instalado é exatamente o que você esperava.

  • Adicionar package-lock ao repositório acelera o processo de instalação, pois o npm não precisa resolver os metadados dos pacotes instalados anteriormente.

O formato de package-lock.json é idêntico ao de npm-shrinkwrap.json. Se npm-shrinkwrap.json estiver presente, package-lock.json será completamente ignorado.

Estas são algumas das variáveis do arquivo package-lock.json:

  • name — package-lock.json define um bloqueio para um pacote específico; aqui, você informa o nome do pacote.

  • version — a versão que você quer bloquear.

  • lockfileVersion — versão do arquivo package-lock, começando em 1.

  • packageIntegrity — valor de integridade criado a partir de package.json. Pode ser gerado por módulos como ssri.

  • preserveSymlinks — indica se a instalação foi feita com a variável de ambiente NODE_PRESERVE_SYMLINKS.

  • dependencies — um mapeamento do nome do pacote para objetos de dependência. Os objetos de dependência têm as seguintes propriedades:

    • version — um identificador exclusivo deste pacote, que pode ser usado para buscar uma nova cópia dele. Consulte a documentação de package-lock para saber como especificar versões para diferentes fontes de pacotes.

    • bundled — indica se a dependência está incluída no pacote e, em caso afirmativo, se deve ser extraída do módulo pai em vez de instalada como uma dependência separada.

    • dev — indica se essa dependência é uma dependência de desenvolvimento ou uma dependência transitiva de uma delas.

    • Outras propriedades são integrity, resolved, optional e dependencies (subdependências desta dependência).

Acesse a documentação de package-lock.json para saber mais e confira o post de Jiří Pospíšil‘s com boas práticas para bloquear arquivos no npm 5.

Como bloquear dependências com yarn.lock

O Yarn já vem com bloqueio de dependências integrado, como no Ruby. Para garantir instalações consistentes em diferentes máquinas, o Yarn precisa saber exatamente quais versões de cada dependência foram instaladas.

O Yarn fornece um arquivo yarn.lock gerado automaticamente, localizado na raiz do projeto. Assim como package-lock do npm, yarn.lock deve ser incluído no controle de versão.

O arquivo é parecido com este (exemplo retirado da documentação do yarn.Lock).

       # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 
       # yarn lockfile v1 
       package-1@^1.0.0: 
           version "1.0.3" 
           resolved "https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" 
       package-2@^2.0.0: 
           version "2.0.1" 
           resolved "https://registry.npmjs.org/package-2/-/package-2-2.0.1.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" 
           dependencies: 
               package-4 "^4.0.0" 
       ...

Quando você adiciona, atualiza ou remove dependências, o Yarn atualiza automaticamente o arquivo yarn.lock. Você não deve editá-lo diretamente. O Yarn considera apenas o arquivo yarn.lock no nível superior e ignora os arquivos yarn.lock dentro das dependências. O arquivo de nível superior inclui tudo o que é necessário para bloquear as versões de todos os pacotes na árvore de dependências.

Para saber mais, consulte a documentação do yarn.lock ou este guia detalhado da Pluralsight, que explica o Yarn, incluindo o recurso yarn.lock.

Conclusão

As dependências são muito importantes. Para evitar surpresas — e porque cada vez que você instala um pacote pode receber versões diferentes das dependências aninhadas —, a maioria dos desenvolvedores front-end bloqueia ou fixa suas dependências. Os usuários do npm ficaram para trás, mas isso mudou com o novo recurso package-lock do npm 5.

Agora há pelo menos duas maneiras práticas de bloquear pacotes no npm: o arquivo package-lock.json do npm 5, que substitui o shrinkwrap como uma solução mais elegante, e o mecanismo integrado de bloqueio de dependências do Yarn, conhecido como yarn.lock.

Nossa recomendação: bloqueie as dependências, mas não deixe de acompanhá-las. Configure um processo para monitorar continuamente as vulnerabilidades nas suas dependências usando uma ferramenta como a Snyk. De tempos em tempos, revise também sua árvore de dependências e atualize ativamente as que estiverem desatualizadas, para garantir a máxima proteção contra falhas e vulnerabilidades futuras.

Leia mais

illustration hero ai
Blog

PHP corrige duas vulnerabilidades críticas de RCE sem autenticação (CVE-2026-109618, CVE-2026-109619): [atualizado para CVE-2026-115560]

Duas falhas críticas no ciclo de requisições do PHP podem permitir execução remota de código sem autenticação. Atualize para uma versão corrigida ou instale um backport do fornecedor para versões mais antigas.

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.