Skip to main content

Den neuen npm@3-Abhängigkeitsbaum meistern

Artikel von
Headshot of Remy Sharp

Remy Sharp

25. Februar 2016

0 Min. Lesezeit

Bis vor Kurzem unterstützte das Snyk-CLI-Tool nur npm@2. Das änderte sich mit der Veröffentlichung von snyk@1.9.0: Seitdem wird die neue Verzeichnisstruktur von npm@3 vollständig unterstützt.

Wir möchten Ihnen einige der technischen Herausforderungen vorstellen, die dabei zu bewältigen waren, sowie die neuen Tools, die dabei entstanden sind.

Was ist neu an npm@3?

Bei npm@2 werden Node-Abhängigkeiten im Verzeichnis node_modules des jeweiligen Node-Pakets installiert. Die Verzeichnisse des Moduls request sehen zum Beispiel so aus:

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

Wie Sie am obigen Ausschnitt sehen, kommt node_modules bereits mehrfach vor. Das ist noch kein großes Problem, kann aber zu vielen Duplikaten führen. Beliebte Hilfsbibliotheken wie lodash können in einem Projekt sehr, sehr oft vorkommen!

Ursprünglich unternimmt npm@2 einige Schritte, um Duplikate zu vermeiden. npm@3 flacht diese Verzeichnisstruktur jedoch vollständig ab, um die Duplikate ganz zu beseitigen. Mit npm@3 sieht dasselbe request-Paket so aus:

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

Wie Sie sehen, hat sich die Struktur komplett verändert. Wichtig ist jedoch: Die Art und Weise, wie Node Module lädt, bleibt davon unberührt.

Welche Auswirkungen hat das auf Snyk?

Zunächst musste die Logik des CLI-Pakets zum Durchlaufen der Verzeichnisse vollständig neu geschrieben werden. Ursprünglich durchlief Snyk Ihr node_modules-Verzeichnis, iterierte dann über jedes Unterverzeichnis und erstellte eine Baumdarstellung Ihrer Pakete. Eigentlich recht einfach.

Doch die flache Verzeichnisstruktur von npm@3 bildet Ihre Paketbeziehungen überhaupt nicht ab. Das Paket async in der obigen npm@3-Auflistung ist beispielsweise tatsächlich eine Abhängigkeit des Pakets form-data, das wiederum eine Abhängigkeit von request ist. Im Verzeichnisbaum ist das jedoch nicht zu erkennen.

Deshalb wurde die Paketauflösung von Snyk vollständig neu geschrieben und in ein eigenständiges Modul namens snyk-resolve-deps ausgelagert (Open Source unter der Apache-2-Lizenz).

Dieses Modul wird im snyk-CLI-Tool verwendet, kann aber auch als eigenständiges CLI-Tool installiert werden. Bei der Installation mit npm install -g snyk-resolve-deps erhalten Sie ein Hilfsprogramm namens snyk-resolve.

snyk-resolve-deps durchläuft zunächst die gesamte Verzeichnisstruktur und erstellt den physischen Baum. Dieser wird anschließend an die nächste Stufe übergeben, die einen logischen Baum erstellt – die Struktur, die abbildet, von wo Pakete geladen werden können.

Damit werden sowohl Verzeichnisstrukturen von npm@2 als auch von npm@3 unterstützt und ein virtueller Baum wie dieser erstellt:

❯ 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

Damit kann Snyk jetzt sowohl Ihre mit npm@3 als auch Ihre mit npm@2 installierten Projekte problemlos unterstützen. Wir können die richtigen Pfade für Patches ermitteln und alle anfälligen Pfade korrekt melden.

Worin liegt der Unterschied zu „npm ls“?

Wenn Sie mit den npm-Tools vertraut sind, kennen Sie wahrscheinlich npm ls, mit dem sich diese Bäume anzeigen lassen.

Der große Unterschied zwischen snyk-resolve-deps und npm ls besteht darin, dass unser Tool den vollständigen logischen Baum anzeigt und alle Wege aufführt, über die ein Paket in Ihr Projekt gelangt ist.

Sehen wir uns an, wie request im Code von npm eingebunden ist (im Branch 2.x). Dann zeigt sich, dass npm ls eine bestimmte Sicht liefert – nämlich darauf, was auf der Festplatte verfügbar ist:

Terminalausgabe von `npm ls request` mit mehreren installierten Versionen des Pakets request in einem Abhängigkeitsbaum.

Unsere eigene Auflösungsmethode erzählt dagegen eine andere Geschichte. Das bedeutet nicht, dass npm ls falsch liegt. Wir möchten vielmehr genau wissen, was request lädt – und unser eigenes snyk-resolve-deps kann uns das zeigen:

Terminalausgabe von `snyk-resolve -f request --dev` mit einem npm-Abhängigkeitsbaum, der mehrere gebündelte Versionen des request-Pakets zeigt.

Wie Sie sehen, ist das Modul request von deutlich mehr Paketen abhängig, als Sie vielleicht zunächst vermuten. Falls dieses Paket eine Sicherheitslücke hätte, kennt Snyk nun genau die betroffenen Pfade.

snyk-resolve-deps

Das Paket snyk-resolve-deps ist ab sofort unter einer Open-Source-Lizenz Apache 2 verfügbar. Nach der globalen Installation ist es unter dem Alias snyk-resolve verfügbar.

Das CLI-Tool bietet verschiedene Filter und Optionen, darunter die --disk-Ansicht (mit einer ähnlichen Ausgabe wie npm ls) sowie --filter X und --count X, um Vorkommen einer bestimmten Abhängigkeit zu filtern und zu finden. Weitere Informationen erhalten Sie mit snyk-resolve --help.


Mit npm install -g snyk können Sie noch heute beliebige Pakete oder GitHub-Repositories anonym testen. Mit einem kostenlosen Konto können Sie außerdem Ihre Projekte auf Sicherheitslücken überwachen.

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.

Gepostet in: