Skip to main content

Cómo abordar el nuevo árbol de dependencias de npm@3

Escrito por
Headshot of Remy Sharp

Remy Sharp

25 de febrero de 2016

0 minutos de lectura

Hasta hace poco, la herramienta de CLI de Snyk solo era compatible con npm@2. Todo cambió cuando lanzamos snyk@1.9.0 y agregamos compatibilidad total con las nuevas estructuras de directorios de npm@3.

Queremos compartir algunos de los desafíos técnicos que enfrentamos y las nuevas herramientas que surgieron del proceso.

Qué diferencias hay en npm@3

Con npm@2, las dependencias de Node se instalaban en el directorio node_modules de cada paquete de Node. Por ejemplo, los directorios del módulo request se ven así:

request/node_modules
  ├── aws-sign2
  ├── aws4
  │   └── node_modules
  │       └── lru-cache
  │           └── test
  ├── bl
  │   ├── node_modules
  │   │   └── readable-stream
  │   │       ├── doc
  │   │       │   └── wg-meetings
  │   │       └── node_modules
  │   │           ├── core-util-is
  ...snipped

Como puedes ver en el fragmento anterior, node_modules ya aparece varias veces. No es tan grave, pero puede generar mucha duplicación. ¡Utilidades populares como lodash pueden aparecer muchísimas veces en un proyecto!

Al principio, npm@2 realiza algunas tareas para eliminar duplicados, pero npm@3 aplana por completo esta estructura de directorios con el objetivo de eliminar toda duplicación. El mismo paquete request se ve así con npm@3:

request/node_modules
  ├── ansi-regex
  ├── ansi-styles
  ├── asn1
  │   └── lib
  ├── assert-plus
  ├── async
  │   └── lib
  ├── aws-sign2
  ├── aws4
  ├── bl
  │   └── test
  ...snipped

Como puedes ver, es completamente diferente, pero, lo que es más importante, no afecta en absoluto la forma en que Node requiere módulos.

¿Cómo afecta esto a Snyk?

Para empezar, tuvimos que reescribir por completo la lógica de recorrido de paquetes de la CLI. Originalmente, Snyk recorría tu directorio node_modules, iteraba por cada subdirectorio y construía una representación en árbol de tus paquetes. Bastante sencillo.

Pero ahora, la estructura plana de directorios de npm@3 no representa en absoluto las relaciones entre tus paquetes. Por ejemplo, el paquete async de la lista de npm@3 anterior es, en realidad, una dependencia del paquete form-data, que a su vez es una dependencia de request. Pero eso no se ve en el árbol de archivos.

Por eso, reescribimos por completo la resolución de paquetes de Snyk y la extrajimos en un módulo independiente llamado snyk-resolve-deps (de código abierto bajo la licencia Apache 2).

Este módulo se usa dentro de la herramienta de CLI de snyk, pero también se puede instalar como herramienta de CLI independiente (al instalarlo con npm install -g snyk-resolve-deps, se obtiene una utilidad llamada snyk-resolve).

snyk-resolve-deps primero recorre toda la estructura de directorios y construye el árbol físico. Luego, este árbol físico pasa a la siguiente etapa, que crea un árbol lógico: la estructura que representa desde dónde se pueden cargar los paquetes.

Esto significa que se admiten las estructuras de directorios de npm@2 y npm@3, y se crea un árbol virtual como este:

❯ snyk-resolve
  request@2.69.1
  ├── aws-sign2@0.6.0
  ├─┬ aws4@1.2.1
  │ └── lru-cache@2.7.3
  ├─┬ bl@1.0.2
  │ └─┬ readable-stream@2.0.5
  │   ├── core-util-is@1.0.2
  ...snipped

En definitiva, esto significa que Snyk ahora puede admitir sin problemas tus proyectos instalados con npm@3, igual que los de npm@2. Podemos encontrar las rutas correctas para aplicar parches y reportar con precisión todas las rutas vulnerables.

¿En qué se diferencia de «npm ls»?

Si conoces las herramientas de npm, seguramente habrás oído hablar de npm ls, que sirve para ver estos árboles.

La gran diferencia entre snyk-resolve-deps y npm ls es que nuestra herramienta muestra el árbol lógico completo y todas las formas en que un paquete llegó a tu proyecto.

Si vemos cómo se incluye request en el código de npm (en la rama 2.x), podemos ver que npm ls nos cuenta una historia (de lo que está disponible en el disco):

Salida de la terminal de `npm ls request`, que muestra varias versiones instaladas del paquete request en un árbol de dependencias.

En cambio, nuestro método de resolución cuenta otra historia. Esto no significa que npm ls esté equivocado; queremos saber exactamente qué está cargando request, y nuestra herramienta snyk-resolve-deps puede decírnoslo:

Salida de la terminal de `snyk-resolve -f request --dev` que muestra un árbol de dependencias de npm con varias versiones del paquete request incluidas.

Como puedes ver, muchos más paquetes dependen del módulo request de lo que podrías pensar al principio. Si ese paquete tuviera una vulnerabilidad, Snyk ahora puede identificar claramente las rutas vulnerables.

snyk-resolve-deps

El paquete snyk-resolve-deps ya está disponible bajo una licencia de código abierto Apache 2. Una vez instalado globalmente, puedes usarlo con el alias snyk-resolve.

La utilidad de CLI tiene varios filtros y opciones, como la vista --disk (que genera un resultado muy similar al de npm ls) y --filter X y --count X para filtrar y encontrar las apariciones de una dependencia específica. Puedes obtener más información con snyk-resolve --help.


Hoy mismo puedes ejecutar npm install -g snyk y analizar de forma anónima cualquier paquete o repositorio de GitHub. Con una cuenta gratuita, también puedes comenzar a monitorear tus proyectos para detectar vulnerabilidades.

Empieza con los retos de Capture the Flag

Aprende a resolver retos de Capture the Flag viendo nuestro taller virtual de nivel básico a pedido.

Leer más

feature insights context
Blog

Los ataques autónomos ya están aquí. La defensa debe estar a su altura.

Los atacantes autónomos están reduciendo el tiempo disponible para defenderse. Descubre cómo el descubrimiento, la corrección, la validación y la prevención continuos pueden ayudar a los equipos de seguridad a seguirles el ritmo.

illustration hero ai
Blog

El huracán de la IA ha llegado

La IA está acelerando por igual la creación de software y los ciberataques. Los líderes deben proteger los agentes y el código desde el inicio, aplicar controles en tiempo de ejecución y validar las defensas de forma independiente.

feature insights context
Blog

¿La prevención es, en esencia, un problema ya resuelto?

La prevención en el código generado por agentes está resuelta desde el punto de vista arquitectónico, pero elegir controles que protejan la seguridad sin ralentizar el desarrollo sigue siendo el desafío.