Skip to main content

新しいnpm@3の依存関係ツリーに取り組む

著者
Headshot of Remy Sharp

Remy Sharp

2016年2月25日

0 分で読めます

最近まで、SnykのCLIツールがサポートしていたのはnpm@2のみでした。snyk@1.9.0のリリースで状況は一変し、新しいnpm@3のディレクトリ構造を全面的にサポートしました。

この取り組みで直面した技術的な課題と、そこから生まれた新しいツールについてご紹介します。

npm@3の変更点

npm@2では、Nodeの依存パッケージは各Nodeパッケージのnode_modulesディレクトリにインストールされます。たとえば、requestモジュールのディレクトリは次のようになります。

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

上のスニペットからわかるように、すでにnode_modulesが何度も登場しています。これはそれほど悪いことではありませんが、重複が大量に発生する可能性があります。lodashのような人気のユーティリティが、1つのプロジェクト内に何度も何度も現れることもあります。

当初、npm@2では重複を排除するための処理が行われていましたが、npm@3では重複を完全になくすことを目指して、このディレクトリ構造を全面的にフラット化しました。npm@3での同じrequestパッケージは次のようになります。

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

ご覧のとおり、構造はまったく異なりますが、重要なのはNodeでモジュールを読み込む方法にはまったく影響がないことです。

これはSnykにどのような影響を与えるのでしょうか?

まず、CLIのパッケージをたどるロジックを全面的に書き直す必要がありました。従来のSnykはnode_modulesディレクトリをたどり、各サブディレクトリを順に調べてパッケージのツリーを構築していました。比較的シンプルな処理です。

ところが、npm@3のフラットなディレクトリ構造では、パッケージ間の関係をまったく把握できません。たとえば、上のnpm@3の一覧にあるasyncパッケージは、実際にはform-dataパッケージの依存パッケージであり、さらにform-dataはrequestの依存パッケージです。しかし、ファイルツリーからはこの関係がわかりません。

そこで、Snykのパッケージ解決機能を全面的に書き直し、snyk-resolve-depsというスタンドアロンモジュールとして切り出しました(Apache 2ライセンスのオープンソースです)。

このモジュールはsnyk CLIツールで使われていますが、単体のCLIツールとしてもインストールできます(npm install -g snyk-resolve-depsでインストールすると、snyk-resolveというユーティリティが使えるようになります)。

snyk-resolve-depsは、まずディレクトリ構造全体を調べ、物理ツリーを構築します。この物理ツリーを次の段階に渡して、パッケージをどこから読み込めるかを表す論理ツリーを作成します。

つまり、npm@2とnpm@3のどちらのディレクトリ構造もサポートでき、次のような仮想ツリーを作成できます。

❯ 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

これにより、Snykはnpm@2だけでなく、npm@3でインストールされたプロジェクトも問題なくサポートできるようになりました。パッチ適用に必要な正しいパスを特定し、脆弱性のあるすべてのパスを正確に報告できます。

「npm ls」との違いは?

npmのツールに詳しい方なら、こうしたツリーの確認に便利なnpm lsをご存じでしょう。

snyk-resolve-depsとnpm lsの大きな違いは、私たちのツールが論理ツリー全体を表示し、パッケージがプロジェクトに取り込まれた経路をすべて示すことです。

requestがnpmのコード(2.xブランチ)でどのように取り込まれているかを見ると、npm lsがディスク上で利用可能な内容について、次のように示していることがわかります。

`npm ls request`のターミナル出力。依存関係ツリー内にrequestパッケージの複数のバージョンがインストールされていることを示しています。

一方、独自の解決方法では、異なる情報が得られます。これはnpm lsが間違っているということではありません。私たちが知りたいのは、requestを実際に何が読み込んでいるのかということであり、それをsnyk-resolve-depsで確認できます。

`snyk-resolve -f request --dev`のターミナル出力。複数のバージョンのrequestパッケージがバンドルされたnpm依存関係ツリーが表示されています。

ご覧のとおり、requestモジュールは当初の想定よりも多くのパッケージに依存されています。このパッケージに脆弱性があった場合でも、脆弱性のあるパスをSnykが正確に把握できるようになりました。

snyk-resolve-deps

snyk-resolve-depsパッケージは、Apache 2オープンソースライセンスのもと、現在利用できます。グローバルにインストールすると、snyk-resolveという名前で使えます。

このCLIユーティリティには、--diskビュー(npm lsとよく似た内容を表示)や、特定の依存関係を絞り込んで出現箇所を探すための--filter X、--count Xなど、さまざまなフィルターやフラグがあります。詳しくはsnyk-resolve --helpをご覧ください。


今すぐnpm install -g snykを実行して、任意のパッケージやgithubリポジトリを匿名でテストできます。無料アカウントを作成すれば、プロジェクトの脆弱性を今すぐ監視できます。

キャプチャー・ザ・フラッグを始めよう

オンデマンドのバーチャル入門ワークショップを視聴して、キャプチャー・ザ・フラッグの課題の解き方を学びましょう。

続きを読む

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

illustration hero ai
Blog

AIハリケーンが到来

AIはソフトウェア開発とサイバー攻撃の双方を加速させています。リーダーは、エージェントとコードを開発の初期段階から保護し、実行時に制御を徹底するとともに、防御策を独立して検証しなければなりません。

feature insights context
Blog

予防は、本質的に解決済みの問題なのでしょうか?

エージェントが生成するコードの予防策はアーキテクチャ上解決されていますが、開発を遅らせることなくセキュリティを守る制御を選ぶことが、依然として課題です。