unit-testing-licenses.jpg
Webentwicklung |

Unit-Testing für Lizenzen: Die Rechtmäßigkeit deiner node_modules mit Jest überwachen

mo.jpg.png

Moritz

3. März 2023

tl;dr quick summary
Es ist wichtig, die Open-Source-Lizenzen im Blick zu behalten, die du in deinen JavaScript-Projekten verwendest, denn nicht jede Lizenz ist für jeden Anwendungsfall geeignet. Was wäre, wenn wir dieses Problem lösen, indem wir die Lizenzen deiner node_modules zum Teil der Test-Suite machen?

Hinweis: Dieser Artikel wurde unter Zuhilfenahme von KI aus dem Englischen übersetzt. Hier geht's zum Originaltext.

NPM-Lizenzen als Teil der Test-Suite

Packages aus dem npm-Registry sind das Herzstück der meisten größeren JavaScript-Projekte. Bibliotheken, Frameworks, Tools usw. - alle unsere Projekte stehen auf den Schultern von Giganten Open-Source-Projekten. Den gesamten Code selbst zu schreiben und zu warten wäre unmöglich, selbst für die größten Unternehmen. Aber es gibt einen Preis dafür, und Supply-Chain-Angriffe sind nur eines der Risiken bei der Verwendung von Drittanbieter-Code. In einem kommerziellen Kontext musst du dir immer der rechtlichen Implikationen von Open-Source-Lizenzen bewusst sein. Es gibt eine Vielzahl verschiedener Lizenzen, und sie erlauben alle unterschiedliche Arten der Nutzung. Ich werde explizit nicht auf die Details eingehen (ich bin kein Anwalt, du solltest für diese Angelegenheiten immer Rechtsprofis konsultieren), aber es ist wichtig, die Lizenzen zu verfolgen, die du in deinen Projekten verwendest. Nicht jede Open-Source-Lizenz ist für jeden Anwendungsfall geeignet, und dessen müssen wir uns bewusst sein!

Es gibt 3 Hauptanliegen, die wir behandeln müssen:

  • Wir möchten unseren Kunden (oder ihrem Rechtsteam) einen Überblick über alle Lizenzen geben, die wir in ihrem Produkt verwenden (oft eine vertragliche Verpflichtung).
  • Wir möchten bestimmte Lizenzen vermeiden, daher müssen wir verhindern, dass Entwickler sie unwissentlich hinzufügen.
  • Wir möchten wissen, ob ein Paket aus irgendeinem Grund seine Lizenz geändert hat, und dann prüfen, ob die neue Lizenz immer noch erlaubt ist.

Heute möchte ich zeigen, wie wir diese Probleme angehen können, indem wir Lizenzen zu einem Teil der Test-Suite machen. Diese Test-Suite könnte bei jeder vorgeschlagenen Änderung am Code ausgeführt werden (z.B. als GitHub-Action bei jedem Pull Request), sodass eine unerwünschte Änderung der Lizenzierung frühzeitig zum Fehlschlagen unserer CI führt.

Beispielprojekt

Nehmen wir an, wir haben ein TypeScript-Projekt, das bereits einige Unit-Tests enthält. Es verwendet Jest / ts-jest dafür, aber du kannst die Idee wahrscheinlich für jedes andere Test-Framework anpassen. Wenn du neu bei Jest bist, bieten sie einen ausgezeichneten Setup-Guide. Auch ts-jest hat dich abgedeckt, wenn du TypeScript verwenden möchtest.

Um die gewünschten Informationen einfach zusammenzustellen, werden wir license-checker-rseidelsohn verwenden, das die Pakete aus unserer Paketdatei sammelt und dann Lizenz- und Autor-Informationen aus node_modules extrahiert. Es kann dann eine Liste in verschiedenen Formaten generieren -- in unserem Fall Markdown. Dieses Paket ist auch praktisch, weil es sowohl eine CLI als auch Exports für programmatische Nutzung bietet. So könnte ein CLI-Aufruf aussehen (--direct bedeutet: nur direkte Abhängigkeiten einbeziehen, nicht ihre transitiven Abhängigkeiten):

npx license-checker-rseidelsohn --markdown --direct

Screenshot des Ergebnisses des obigen Befehls: Markdown-Text, der alle Abhängigkeiten (und ihre Lizenzen) eines Beispielprojekts auflistet

Wir können das Ergebnis jetzt in eine Markdown-Datei schreiben (→ npx license-checker-rseidelsohn --markdown > LICENSES.md). Wenn diese Datei im Repository unseres Projekts liegt, rendert GitHub schönes HTML für uns. Für 99% unserer Projekte löst das den Anwendungsfall #1, das Rechtsteam unseres Kunden erhält Zugang zu dieser GitHub-URL und wir sind fertig. Um die Datei aktuell zu halten, können wir auch eine GitHub-Action wie folgt verwenden:

Dadurch wird ein PR geöffnet, wenn die LICENSES.md geändert werden muss.

Das war einfach. Jetzt zum spannenden Teil:

Unit-Tests für die Rechtmäßigkeit

Legen wir alle anderen Prüfungen in einen neuen Unit-Test, nennen wir ihn licenses.test.ts (wir verwenden wieder TypeScript, was dafür nicht notwendig ist, wenn du nicht möchtest). In diesem Test müssen wir ein paar Dinge tun:

Zuerst importieren wir den Checker und promisify ihn, damit wir später async/await verwenden können:

Das Ergebnis vom Checker ist ein Objekt mit packageName@version als Schlüssel und weiteren Informationen als Werte:

Da wir nicht alles davon brauchen, aber die Versionsnummer im Schlüssel ist, sollten wir es wahrscheinlich aufräumen, bevor wir es verwenden. Lass uns all das in beforeAll machen:

Als ersten Test wollen wir herausfinden, ob aktuelle Pakete nicht erlaubte Lizenzen verwenden. Als Beispiel erlaube ich nur ["UNLICENSED", "MIT", "BSD-3-Clause", "Apache-2.0"]. Der eigentliche Test verwendet einen benutzerdefinierten Matcher, damit wir die Ausgabe fehlgeschlagener Test-Nachrichten besser kontrollieren können. Wir müssen TypeScript auch mitteilen, was es von unserem benutzerdefinierten Matcher erwarten kann.

Jetzt ist der erste Test sehr einfach:

Dieser Test wird jedes Paket mit unserem benutzerdefinierten Matcher überprüfen und fehlschlagen, wenn seine Lizenz(en) nicht in der Erlaubnisliste sind. Das löst unseren Anwendungsfall #2.

Für unseren zweiten Test wollen wir die Menge der verschiedenen Lizenzen im Projekt zukunftssicher machen, um zu erkennen, ob ein Paket hinzugefügt, entfernt oder seine Lizenz geändert wurde. Wir können dies mit einem Snapshot-Test tun:

Für diejenigen, die nicht wissen, was ein Snapshot-Test ist: Wenn er zum ersten Mal ausgeführt wird, speichert er einen aktuellen Snapshot des Ergebnisses in einer Datei __snapshots__/licenses.test.ts.snap. Diese Datei muss dann in das Repository eingecheckt werden. Jedes Mal, wenn der Test in Zukunft läuft, wird sein Ergebnis mit diesem Snapshot verglichen. Wenn es sich geändert hat, schlägt der Test fehl und Jest teilt es dir mit.

Gut, lass uns unsere Tests ausführen: → npm run test

Screenshot der CLI-Ausgabe des obigen Befehls: Alle Tests bestanden und Jest teilt uns mit, dass es einen Snapshot aus 1 Test-Suite geschrieben hat

Alles sieht gut aus, alle unsere Pakete entsprechen unserer LICENSE_ALLOW_LIST und wir haben jetzt eine Snapshot-Datei, die wir committen können:

Schauen wir, was passiert, wenn wir eine Abhängigkeit hinzufügen: → npm install @react-hookz/webnpm run test

Screenshot eines weiteren Testlaufs nach Hinzufügen einer Abhängigkeit: Der erste Test besteht, der Snapshot-Test schlägt fehl.

Aus dieser Ausgabe können wir sehen, dass die Lizenz von @react-hookz/web erlaubt ist (der erste Test bestand!), aber sie ist noch nicht im Snapshot. Beheben wir das, indem wir npm run test -- -u ausführen:

Screenshot der CLI-Ausgabe von Jest: Beide Tests bestehen wieder, der Snapshot wurde aktualisiert.

Fügen wir eine weitere Abhängigkeit hinzu: → npm install rimrafnpm run test:

Screenshot der CLI-Ausgabe: Beide Tests schlagen fehl:

Uh oh! rimraf verwendet die ISC-Lizenz, die nicht in unserer Erlaubnisliste ist und unser erster Test hat das erkannt: "ISC" ist keine erlaubte Lizenz (Abhängigkeit: rimraf). Wir können jetzt entscheiden, ob wir dieses Paket entfernen und etwas anderes verwenden oder die Erlaubnisliste des Tests ändern wollen.

Zusammenfassung:

Das sollte funktionieren! Alle 3 Anwendungsfälle werden durch ein paar Zeilen TypeScript und YAML abgedeckt. Du kannst ein vollständig funktionierendes Beispiel-Repo (inklusive GitHub-Actions) hier einsehen: https://github.com/peerigon/blog-license-check-demo

Wenn du nur die Test-Datei willst, hier ist sie:

open source licenses

unit testing

node_modules

Weitere Themen

Michael, 16.04.2025

Green Hosting im Nachhaltigkeitsvergleich

Sustainability

Green Software

Consulting

Hostingsec

Zum Blogartikel

Lea, 04.04.2025

Vue clever nutzen – Wiederverwendbarkeit für Einsteiger:innen

Vue

JavaScript

Reusability

DRY Principle

Components

Composables

Zum Blogartikel
Header-top-ten-mistakes-to-avoid.png

Francesca, Ricarda, 02.04.2025

Die 10 häufigsten Fehler bei der Entwicklung digitaler Produkte – und wie du sie vermeidest

MVP development

UX/UI design

product vision

agile process

user engagement

product development

Zum Blogartikel