# 依存関係の管理

> サイトが npm 依存関係をどのようにインストール、検証、更新するか

---

LLMS index: [llms.txt](/llms.txt)

---

npm 依存関係はコミット済みの `package-lock.json` によって固定され、インストール時にはレビュー済みのライフサイクルスクリプトのみが実行されます。
これらの制御の背景にある脅威モデルと根拠については、[Supply-chain security][] を参照してください。

## インストール時の動作 {#install-contracts}

CI、devcontainer、Netlify は、ロック固定かつスクリプト無効でインストールし、その後、レビュー済みのフック1つだけを明示的に再有効化します。
それは固定された Hugo バイナリを取得する `hugo-extended` のリビルドです。
リビルドは `scripts/rebuild-hugo-extended.mjs` を通じて実行され、制限付きバックオフでフェッチをリトライし、`HUGO_*` インストーラーオーバーライドが設定されている間は実行を拒否します。
環境ごとの詳細は以下のとおりです。

- **CI**: `npm run ci:min` を実行します。
  サイトをビルドするジョブは続けて `npm run ci:prepare` を実行します。
- **Devcontainer**: `npm run install:safe` を実行します。
  同じ動作を保証しますが、オプショナルな依存関係を保持します。
- **Netlify**: `npm run install:safe` を実行します。
  [Netlify][] のビルドコマンドによって、[不活性な自動インストール](#inert-netlify-auto-install)の後、クリーンなワーキングツリーのチェックの間に実行されます。
  - ロックのドリフトやその他の Git で検出可能な変更があればビルドが失敗します。
  - インストールが変更していないパスでの失敗については、後述の[古い Netlify ビルドキャッシュ](#netlify-build-cache)を参照してください。
- **ローカル**: `npm run install:safe`、または標準の `npm install` を実行します。
  標準の `npm install` は、`package.json` と一致する間はロックに従い、ライフサイクルスクリプトを無効化するかわりに[許可リスト](#lifecycle-script-allowlist)でゲートします。
  詳細は[ローカルセットアップ][local setup]を参照してください。

ネストされた [Docsy][] テーマのセットアップも同じ動作に従います。
`prepare` ステップが Docsy 自身のロック固定かつスクリプト無効のテーマ依存関係インストールを呼び出します。

### 古い Netlify ビルドキャッシュ {#netlify-build-cache}

Netlify は[デプロイコンテキスト][deploy context]ごとにビルドキャッシュを保持します。

- プロダクション用に1つ
- Deploy Preview 用に**ヘッドブランチ名**ごとに1つ。
  そのブランチ名の最初のビルド時にプロダクションキャッシュからシードされます。
  キャッシュの系統は明示的なクリアでのみ消滅します。
  ブランチの削除は Netlify からは見えないため、同じ名前で再作成されたブランチ（リサイクルされたボットブランチ名を含む）は古いキャッシュに再接続されます。

各キャッシュには[リポジトリのクローンが含まれており][includes a clone of the repository]、git サブモジュールを削除するコミットをチェックアウトすると、サブモジュールのワーキングツリーがそのまま残ります。
そのため、削除されたサブモジュールがキャッシュに乗って後のビルドに未追跡の残留物として混入し、クリーンなワーキングツリーのチェックに失敗する可能性があります。
デプロイログには `??` 接頭辞のステータス行としてそのパスが表示されます。

パスを `.gitignore` に追加するのではなく、該当する[ビルドキャッシュ][build cache]をクリアしてください。

- **プロダクション**:
  - **Deploys** > **Trigger deploy** からキャッシュをクリアしてサイトをデプロイします。
- **Deploy Preview**: 既にビルドされた各ブランチは独自のキャッシュコピーを保持しており、プロダクションのクリア後も影響を受けません。
  - PR の最新デプロイページから **Retry** > **Clear cache and retry with latest branch commit** でクリアします。
    ブランチ全体を一括でクリアする方法はありません。

> [!IMPORTANT]
>
> git サブモジュールを削除した後は、残留物がブランチごとのキャッシュにシードされる前に、削除の一環としてプロダクションビルドキャッシュをクリアしてください。
> また、リサイクルされたボットブランチ名の系統もクリアしてください。
> プロダクションのクリアではそれらに到達しません。

## 依存関係の更新 {#updating}

### 通常の更新 {#routine-updates}

`npm run update:packages` は `package.json` のみを更新します。
提供されるバージョンには[リリースクールダウン](#release-cooldown)が適用されます。
その後、ロックファイルを再生成し、両方のファイルをまとめてコミットします。

```sh
npm install --package-lock-only --ignore-scripts
```

### スクリプトを持つパッケージ {#script-bearing-packages}

`allowScripts` エントリを持つ（または必要とする）パッケージを追加または更新する場合、変更を行うコントリビューターは以下を行います。

1. 新しいバージョンのライフサイクルスクリプトをレビューする。
2. 結果を、依存関係の変更と一緒にコミットし、PR レビューで検証する。
   必要なスクリプトは正確なバージョン承認として、不要なスクリプトは名前レベルの拒否（`false`、以降のバージョンアップ時に更新不要）として記録する。
3. 新しい承認の場合、[`.github/renovate.json5`][] の Renovate 自動マージ除外リストにもそのパッケージを追加する。
   承認済みパッケージのすべてのバージョンアップには上記の手順が必要なため、その更新 PR はコントリビューターを待つ必要がある。

### ロックファイルのメンテナンス {#lock-file-maintenance}

- **依存関係を変更した場合**: [通常の更新](#routine-updates)と同様にロックファイルを再生成し、`package.json` と一緒にコミットする。
- **ロックファイルのマージコンフリクト**: `main` のバージョンを採用し、再生成コマンドを再実行する。
- **依存関係を変更していないのにロックファイルが変更された場合**（`postinstall` チェックがインストール時にこれを検出すると警告します）: ドリフトを示しています。
  ロックファイルを復元し、リライトをコミットするのではなく調査してください。

## サプライチェーン制御 {#controls}

### サプライチェーン監査 {#audit}

サプライチェーン監査テスト [`scripts/supply-chain-audit.test.mjs`][] は、`test:local-tools` の実行ごとにコミット済みファイルのみから以下の制御を検証します。
これにより、制御の退行はインシデントを待たずにテスト失敗として検出されます。
監査自体の検証原則については、その[設計ページ](/site/design/supply-chain-audit/)を参照してください。

PR で監査が失敗した場合、アサーションメッセージに期待される条件が記載されています。
よくあるケースは以下のとおりです。

- **`allowScripts` エントリを持つ依存関係をバージョンアップした場合**: [スクリプトを持つパッケージ](#script-bearing-packages)に従ってください。
  失敗メッセージにエントリが移行すべきバージョンが示されます。
- **インストールパスのスクリプト、`.npmrc`、または `netlify.toml` を変更した場合**: その失敗こそが目的です。
  監査はインストール面を固定し、変更のたびに意図的なレビューが行われるようにしています。
  変更に合わせて対応するアサーションを更新し、PR にその理由を記載してください。

グリーンにするためだけにアサーションを緩和しないでください。
各アサーションはこのページの制御を強制しているため、まず変更によってどの制御が緩和されるかを把握してください。

監査のスコープ外:

- GitHub ワークフローファイル
- [Docsy][] テーマ自身の依存関係インストール（上流で監査済み）
- インストール境界を越えたビルド側の npm スクリプト

### リリースクールダウン {#release-cooldown}

バージョン解決では、設定された最小経過期間より新しいリリースは無視されます。

- **適用**: [`.npmrc`][] の `min-release-age`。
- **スコープ**:
  - 影響を受けるのはバージョン解決操作のみです。
    ロック固定インストール（`npm ci`）はバージョンを解決しません。
  - npm はプロジェクト設定をユーザー設定より優先するため、ユーザーの `.npmrc` でより厳しいクールダウンを設定していても、ここのプロジェクト値に緩和されます。
    特定の呼び出しで自分の設定を維持するには、`npm_config_min_release_age` 環境変数を設定してください。
    この変数は両方の設定より優先されます。
- **[Renovate][]**: 開く更新 PR に独自のクールダウンを適用します。
  [`.github/renovate.json5`][] の `minimumReleaseAge` で設定されます。
  人間のレビューなしでマージされる更新にはより長い期間が設定されます。

### ライフサイクルスクリプト許可リスト {#lifecycle-script-allowlist}

インストール時にパッケージのライフサイクルスクリプトが実行されるのは、その正確な名前とバージョンが `allowScripts` 許可リストに記載されている場合のみです。

- **適用**: [`package.json`][] の `allowScripts` マップ。
  [`.npmrc`][] の `strict-allow-scripts` によりフェイルクローズドとなります。
- **拒否**:
  - `false` に設定されたエントリは、レビュー済みの拒否を記録します。
    パッケージはインストールされますが、そのスクリプトはスキップされます。
  - 拒否は何も許可しないため、バージョンをまたいで名前単位でパッケージをカバーします。
- **`--ignore-scripts` との相互作用**:
  - 許可リストはフィルタリングのみを行います。
    `ignore-scripts` が無効にしたスクリプトを再有効化することは決してないため、スクリプト無効のインストールでは許可リストの有無にかかわらず何も実行されません。
  - レビュー済みの例外は、呼び出し箇所で明示的に `--ignore-scripts=false` を指定する必要があります。

### npm バージョンフロア {#npm-version-floor}

アクティブな npm が engines フロアより古い場合、インストールは失敗します。
engines フロアとは、上記の制御をサポートする最も古いバージョンです。

- **適用**:
  - [`package.json`][] の `engines` がフロアを設定します。
  - [`.npmrc`][] の `engine-strict` によりフェイルクローズドとなります。
- **フロアポリシー**:
  - npm が制御の適用ギャップを修正するたびにフロアは引き上げられます。
  - Node LTS リリースにバンドルされる npm バージョンに準拠するため、デフォルトのツールチェーンでチェックを通過できます。
- **Netlify**:
  - Netlify の Node バンドルのデフォルト npm はフロアより古い場合があります。
    [`netlify.toml`][] の [`NPM_VERSION`][netlify-deps] でフロアを満たすバージョンを固定しています。
  - 少なくともフロアが引き上げられた際にはこの固定値も更新してください。

### 不活性な Netlify 自動インストール {#inert-netlify-auto-install}

ビルド開始時の Netlify の[自動インストール][netlify-deps]は、[`netlify.toml`][] の [`NPM_FLAGS`][netlify-deps] によって無効化されます。

- `--dry-run`: npm はインストールが何を変更するかを解決してログに記録しますが、何も書き込みません。
- `--ignore-scripts`: ライフサイクルスクリプトは、ドライランの副作用としてではなく、明示的な指示により無効化されたままになります。

**スコープ**: `NPM_FLAGS` は Netlify のビルド設定であり npm の設定ではありません。
自動インストールにのみ適用され、ビルドコマンドの npm 実行には適用されません。

**多層防御**: [実際のインストール][install contracts]は `npm ci` であり、`node_modules` を丸ごと置換します。
そのため、自動インストールやビルドキャッシュの `node_modules` 内の残留物は、クリーンなワーキングツリーのチェックからは見えない（Git で検出可能な変更のみを見る）にもかかわらず、ビルドには持ち越されません。

### 素の npx の禁止 {#no-bare-npx}

リポジトリの設定（パッケージスクリプト、CI、ヘルパースクリプト、コントリビュータードキュメント）は、`npx BIN` としてバイナリを呼び出しません。
`node_modules` が古いか存在しない場合、`npx` は公開レジストリにフォールバックし、その名前を持つパッケージが何であれ実行します。
インストールプロンプトは防御になりません。
非インタラクティブなコンテキストではスキップされ、その他の場合は反射的に「はい」を誘います。
ローカライズされたコントリビュータードキュメントのコピーは、[ドリフトトラッキング][drift tracking]を通じてこのルールに追従します。

- **代替手段**:
  - パッケージスクリプトは、依存関係が提供するバイナリを直接呼び出します。
    npm が `node_modules/.bin` を `PATH` に追加するため、バイナリが存在しなければレジストリへの通信なしに大きなエラーで失敗します。
  - その `PATH` エントリがないコンテキスト（ドキュメント、スタンドアロンスクリプト）では、`npm exec --no -- BIN` を使用します。
    これはインストールを行いません。
- **適用**: レビューの規律による。
  自動化されたチェックはありません。

<!-- prettier-ignore-start -->
[`.github/renovate.json5`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/.github/renovate.json5
[`.npmrc`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/.npmrc
[`netlify.toml`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/netlify.toml
[`package.json`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/package.json
[`scripts/supply-chain-audit.test.mjs`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/scripts/supply-chain-audit.test.mjs
[build cache]: https://docs.netlify.com/build/configure-builds/troubleshooting-tips/
[deploy context]: https://docs.netlify.com/deploy/deploy-overview/#deploy-contexts
[Docsy]: https://www.docsy.dev/
[drift tracking]: /docs/contributing/localization/#track-changes
[includes a clone of the repository]: https://answers.netlify.com/t/what-does-clear-cache-and-deploy-site-do-specifically/9419/2
[install contracts]: #install-contracts
[local setup]: /docs/contributing/development/#local-setup
[netlify-deps]: https://docs.netlify.com/build/configure-builds/manage-dependencies/#npm
[Netlify]: https://www.netlify.com/
[Renovate]: https://docs.renovatebot.com/
[Supply-chain security]: /site/design/supply-chain-security/
<!-- prettier-ignore-end -->
