依存関係
ロックファイルとは?
ロックファイルは、パッケージマネージャーが解決したすべての依存関係(直接・推移的の両方)の正確なバージョンを記録し、次回のインストールで同じツリーが得られるようにするものです。ビルドにとって最良の計画ではありますが、ビルドが実際に使ったものの記録ではありません。
更新日
ロックファイルが記録するもの
package.jsonやpyproject.tomlなどのマニフェストには、依存するパッケージと許容するバージョン範囲が記載されています。
パッケージマネージャーはこれらの範囲を、推移的依存関係を含むツリー全体の正確なバージョンに解決し、
その結果をロックファイルに書き込みます。
npmのドキュメントでは、package-lock.jsonは「the exact tree that was generated,
such that subsequent installs are able to generate identical trees」(生成されたツリーを正確に記述し、以降のインストールで同一のツリーを生成できるようにするもの)と説明されています。
package-lock.jsonの1つのエントリは次のようになります。
"node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-...",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
}
}
- versionは、選ばれた正確なバージョンです。
- resolvedは取得元です。レジストリのtarball URL、またはコミットを含むgit URLです。
- integrityはtarballのSubresource Integrityハッシュで、改ざんされたダウンロードは失敗します。
- dependenciesはそのパッケージ自身の依存関係で、これによってツリー、つまり 依存関係グラフがつながります。
パッケージマネージャー別のロックファイル
| パッケージマネージャー | ロックファイル | 変更せずにインストールする方法 |
|---|---|---|
| npm | package-lock.json | npm ci |
| Yarn (Berry) | yarn.lock | yarn install --immutable |
| pnpm | pnpm-lock.yaml | pnpm install --frozen-lockfile |
| uv | uv.lock | uv sync --locked |
| Poetry | poetry.lock | poetry install |
| Cargo | Cargo.lock | cargo build --locked |
| Bundler | Gemfile.lock | bundle config set frozen true |
| Go modules | go.modのバージョンとgo.sumのチェックサム |
ビルドコマンドはデフォルトでgo.modを更新しません |
素のpipでは、正確なバージョンを記載したrequirements.txtが代わりによく使われます。記載したものは固定されますが、
記載されていないものはインストールのたびに解決し直されます。
CIでは固定インストールを使う
ロックファイルが役に立つのは、ビルドがそこからインストールする場合だけです。通常のnpm installは、
package-lock.jsonがpackage.jsonと一致しなくなると、ロックファイルを更新することがあります。その結果、ビルドは気づかないうちに
新しいツリーを解決します。npm ciは自動化された環境向けに作られています。
package-lock.jsonまたはnpm-shrinkwrap.jsonが必須です。- ロックファイルと
package.jsonが食い違う場合、ロックファイルを更新せずにエラーで終了します。 - 既存の
node_modulesを最初に削除します。 package.jsonやロックファイルに書き込むことはありません。
上の表のほかのコマンドも、それぞれのパッケージマネージャーで同じ役割を果たします。
アプリケーションとライブラリ
アプリケーションやデプロイするものについては、ロックファイルをコミットしてください。ライブラリの場合、ロックファイルが固定するのは自分の開発環境と
CIだけです。npmはpackage-lock.jsonを公開せず、ルートプロジェクト以外では無視します。
ライブラリをインストールするアプリケーションは、指定されたバージョン範囲内で依存関係を自ら解決します。npm唯一の
例外はnpm-shrinkwrap.jsonで、これは公開され優先されますが、ほとんどの
ライブラリでは使うべきではありません。
ロックファイルが出荷したものの記録にならない理由
ロックファイルは、1つのプロジェクトにおける1つのパッケージマネージャーの計画です。リリースを生成したビルドは、 その計画に従う以上のことをしています。
- 使われていない可能性がある。固定されていないインストール、ロックファイルの欠如、モノレポ内の2つ目のロックファイルなどがあれば、 ツリーは手元のファイルとは異なる形で解決されています。
- キャッシュ。CIキャッシュから復元されたパッケージは取得されずにインストールされます。また、部分一致のキーで復元されたキャッシュは 現在のロックファイルより古い可能性があります。 GitHub Actionsのキャッシュが隠すものをご覧ください。
- ビルドツール。セットアップアクション、コンパイラー、リンター、コードジェネレーターは別の経路で入り込み、 それぞれ独自の依存関係ツリーを持っています。
-
ダウンロードとインストールスクリプト。ビルドステップ内の
curlやパッケージのインストールスクリプトは、 どのロックファイルにも載っていないコードを取得します。これが隠れた依存関係です。 - ベースイメージ。コンテナビルドは、どの言語のロックファイルの外にもあるイメージやOSパッケージを 取り込みます。
integrityハッシュは、これらのどれにも役立ちません。ロックファイル内のパッケージが改ざんされていないことは証明しますが、 ビルドがその外で何を取得したかについては何も示しません。ロックファイルからSBOMを作るSCAツールも、 同じ死角を引き継ぎます。
ビルドを記録し、ロックファイルも維持する
ロックファイルは引き続きコミットし、固定インストールでそこからインストールしてください。ビルドを繰り返し実行しやすくなりますが、それだけで再現可能なビルドになるわけではありません。 リリースに何が含まれるかの記録については、CRACIがビルドそのものを記録します。CRACIのGitHub Actionsランナー上の パッケージを認識するプロキシが、各ジョブが取得したすべてのパッケージ(CIキャッシュから復元されたパッケージを含む)を記録し、各ジョブのSBOMは 自らの完全性を示します。この記録は、ロックファイルのスキャンよりも、実際に使われている依存関係をより完全に把握できます。 ビルド時SBOMをご覧いただくか、デモを予約して、お手元のビルドで 両者を比較してください。
ロックファイルに関するよくあるご質問
ロックファイルとは何ですか?
ロックファイルは、パッケージマネージャーが解決したすべての依存関係(直接・推移的の両方)の正確なバージョンを、取得元とチェックサムとともに記録するファイルです。以降のインストールではこれを読み込み、バージョン範囲を解決し直すことなく同じツリーを再現します。
ロックファイルはコミットすべきですか?
はい。アプリケーションやデプロイするものについてはコミットしてください。コミットされたロックファイルがないと、新規インストールのたびにバージョン範囲が解決し直され、新しい推移的バージョンが取り込まれる可能性があります。コミットしたうえで、CIではnpm ciなどの固定インストールでそこからインストールしてください。
ロックファイルは推移的依存関係も固定しますか?
はい。それが主な役割です。マニフェストには直接の依存関係と許容範囲しか記載されませんが、ロックファイルにはツリー内のすべてのパッケージについて選ばれた正確なバージョンが記録されます。
公開するライブラリにもロックファイルは適用されますか?
ライブラリの利用者には適用されません。たとえばnpmはpackage-lock.jsonを公開せず、ルートプロジェクト以外では無視します。ライブラリをインストールするアプリケーションは、package.jsonが許容する範囲内で依存関係を自ら解決します。
package-lock.jsonのintegrityフィールドは何をするものですか?
パッケージtarballのSubresource Integrityハッシュ(通常はsha512)を保持します。npmはダウンロードしたパッケージをこれと照合するため、ロックされたバージョンの改ざんされたtarballはインストールに失敗します。保護されるのはロックファイル内のパッケージであり、ビルドがその外で取得するものは対象外です。
ロックファイルはSBOMと同じですか?
いいえ。ロックファイルは入力、つまり1つのプロジェクトでパッケージマネージャーが従う計画です。SBOMはリリースの構成一覧です。SCAツールはロックファイルからSBOMを作ることが多く、ビルドがロックファイルどおりに、それ以外を何もインストールしなかった場合には有効です。