mcpField
D
dependabot-triage

dependabot-triage

github.com/akshayrao14セキュリティ041 回インストール6 週間前に更新
リポジトリ

dependabot-triage について

npm、pnpm、yarn、bun を使う JavaScript/TypeScript リポジトリ向けの Dependabot 分析・修正スキルです。影響範囲とリスクを評価し、複数のパッケージマネージャー間でロックファイルのバージョンを確認したうえで、変更や PR 作成前に確認を求めます。

主な機能

  1. 01標準と Fast-Track の分析モード
  2. 02ローカルと CI のパッケージマネージャー検出
  3. 03影響範囲と CVSS による優先順位付け
  4. 04インポート箇所と変更履歴の確認
  5. 05ロックファイル間のバージョン整合性確認
  6. 06確認後の修正 PR 作成

活用シーン

  1. 01複数の Dependabot アラートの優先順位付け
  2. 02JavaScript/TypeScript 依存関係の脆弱性修正
  3. 03CI とローカルのパッケージマネージャー設定の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/akshayrao14/git-practices --skill dependabot-triage

インストール後、Claude Code で/dependabot-triageを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

install.sh
LICENSE
README.md
SKILL.md.tmpl

詳細

Dependabot のトリアージと修正(v2.1)

v2.1 の主な変更点

  • 2 つのモード — Standard と Fast-Track。 Standard は防御的なワークフローです(完全なエクスポージャーマッピング、変更履歴の取得、安全インターロック)。Fast-Track は低リスクの更新向けです(Internal/Dev カテゴリー、CVSS < 7、またはユーザーによるオプトイン)。変更履歴と詳細なエクスポージャー列挙を省略し、確認は 1 回のみのインターロックを使用します。パリティチェックとデュアルライトは、どちらのモードでも必須です。
  • CI ワークフローの検査 — 主要な検出ステップ。 ロックファイルだけでは、CI で何が実行されるか分かりません。CI ではコミット済みのロックファイルとは異なる PM が使われる場合(例:yarn.lock がコミットされているのに、CI では npm install を実行)、またはロックファイル厳密モードの <pm> ci ではなく <pm> install が実行される場合があります。検出結果に基づいて、オーバーライドとパリティマトリックスを決定します。
  • 防御的なバージョン選定 — 「同じメジャーバージョンの最新」ではなく、クラスタ内のすべての CVE を修正する最小のパッチ適用済みバージョンを選びます。
  • エクスポージャーマッピング は、ヒューリスティックな到達可能性の判定に代わるものです。すべてのインポート箇所を分類し(Public/API・Client-Bundle・Internal/Dev)、到達不能であることの証明を試みる代わりに、攻撃対象領域をユーザーに提示します。
  • 必須のロックファイルパリティチェック — マニフェストに触れるすべての PM で、対象パッケージが同じバージョンに解決される必要があります。不一致があれば PR を中止します。CI/CD では、ローカルの健全性チェックとは異なる PM がよく実行されるため、必須です。
  • 安全インターロック付きの変更履歴取得(Standard モード) — 現在のバージョンから対象バージョンまでのリリースノート/CHANGELOG を取得し、BREAKING/DEPRECATED/MIGRATION キーワードを検出します。更新を適用する前に、一時停止してユーザーに明示的な確認を求めます。
  • 自動復帰 — Fast-Track でパリティチェックに失敗するか、更新後のビルドに失敗した場合、再試行を繰り返す代わりに、詳細な分析を行うため Standard モードへの切り替えを提案します。
  • 組織レベルの一括処理は明示的なオプトインのみ — 自動的に開始することはありません。組織全体の列挙は API レート制限を消費し、JavaScript 以外のノイズも表示するためです。

このスキルの対象範囲:npm、pnpm、yarn(classic/berry)、bun。

対象範囲

JavaScript/TypeScript のリポジトリのみ — npm、pnpm、yarn、bun のエコシステムが対象です。バックエンドの Node.js サービス、フロントエンドバンドル(CSR)、サーバーレンダリングアプリ(SSR)、SSR と CSR が混在するフレームワーク(Next.js、Nuxt、Remix、SvelteKit)をカバーします。

まだ対象外:Python(pip/poetry/uv)、Go モジュール、Java(Maven/Gradle)、Ruby(bundler)、Rust(cargo)、.NET(NuGet)。ユーザーが、アラートが JavaScript 以外の依存関係に関するリポジトリを指す Dependabot URL を共有した場合(.dependency.package.ecosystem を確認してください)、その旨を明確に伝えて中止してください。これらのエコシステムに、このスキルの仕組みを適用しないでください。

組織レベルの一括処理では、JavaScript 以外のアラート(例:Python の pillow、Java パッケージ)も表示されます。これらは順位付けテーブルから除外するか、「このスキルの対象外 — 別途対応」として明記してください。

インストール方法(エンジニアごとに一度)

npx skills add akshayrao14/dependabot-triage

エージェントに適したスキルディレクトリ(Codex の ~/.codex/skills、Claude Code の ~/.claude/skills、またはオープン標準の ~/.agents/skills)にインストールします。その後、エージェントのセッションを再起動してください。スキルが /skills(Claude Code)またはエージェントのスキル検出機能から表示されるはずです。

呼び出し方法

トリガーフレーズ(以下のいずれかで、エージェントがこのスキルを使用します):

  • 「<repo> の Dependabot アラートをトリアージして」
  • 「最初に修正すべき脆弱性はどれ? <github.com/.../security/dependabot URL>」
  • 「このリポジトリの Dependabot アラート # を修正して」
  • 「<pkg> を脆弱性のないバージョンに更新して」

次のいずれかを指定してください:

  • リポジトリレベルの Dependabot セキュリティ URL(github.com/<org>/<repo>/security/dependabot)、または
  • リポジトリのパスとアラート番号、または
  • 脆弱性が分かっている場合は、パッケージ名のみ

組織レベルの一括処理は明示的なオプトインのみです。 ユーザーが組織 URL(github.com/orgs/<org>/security/alerts/dependabot)を貼り付けた場合でも、組織全体を自動的に列挙しないでください。最初に確認してください:「組織内のすべてのリポジトリにわたってアラートをページネーションし、多くの API レート制限を使用する可能性があります。続行しますか?」その後、yes の場合にのみ実行します。組織全体の一括処理を明示的に行うトリガーフレーズ:

  • 「組織全体を一括処理して」
  • 「<org> のすべてのリポジトリをトリアージして」
  • 「組織全体のトリアージを実行して」

前提条件

  • リポジトリアクセス権で認証済みの gh CLI(gh auth status)。
  • 対象リポジトリのローカルクローン(エージェントが package.json とロックファイルを読み取る必要があります)。
  • ロックファイルを再生成するための node、pnpm、および/または npm がインストールされていること。
  • ブランチをプッシュして PR を作成する書き込み権限(または、エージェントがコミット手順で停止することを許容すること)。

Claude が行うこと(v2.1 ワークフロー)

Detect PMs   →   Fetch + Rank   →   Mode Selection   →   { Standard | Fast-Track }   →   Apply + Parity Check   →   PR

最初の手順(1~4)はどちらのモードでも同じです。中間の手順はモードによって分岐します。最後の手順(再生成+パリティチェック+PR)は同一で、必須です。

  1. 使用中のパッケージマネージャーを検出する — アラートを取得する前に、ローカルインストール、CI インストール、コンテナビルドのあらゆる状況で、このリポジトリに実際に関与する PM を特定します。後述のオーバーライド+パリティマトリクスは、この情報に依存します。
    • コミット済みのロックファイル:ls package-lock.json pnpm-lock.yaml yarn.lock bun.lock* 2>/dev/null。
    • CI/コンテナのインストールコマンド — CI 設定ファイルと Dockerfile を検索し、実際のインストールコマンドを確認します。
      rg -tg '*.yml' -tg '*.yaml' \
        '\b(npm (install|ci)|yarn install|pnpm install|bun install)\b' \
        .github .gitlab-ci.yml Dockerfile* docker-compose*.yml circle.yml .circleci 2>/dev/null
      
    • コミット済みのロックファイルと CI のインストールコマンドを比較します。CI の PM がコミット済みロックファイルの PM と異なる場合、または CI の PM 用のロックファイルがコミットされていない場合は、それに応じてオーバーライド+パリティマトリクスを拡張します(「オーバーライドのパターン」と「検証(パリティチェック)」を参照)。
    • 最初にユーザーへ PM の設定を分類するよう求めないでください。 ユーザーが把握しているのは、全体の一部(ローカル環境だけで CI は把握していない、またはその逆)であることがよくあります。ロックファイルと CI の検索結果から検出し、見つかった内容を示したうえで、異常がある場合にのみ確認を求めます(例:「yarn.lock がコミットされていますが、CI では npm install が実行されています。どちらも意図した設定か確認してください」)。
  2. アラートを取得する:
    • リポジトリ URL → gh api "repos/<org>/<repo>/dependabot/alerts?state=open&per_page=100"
    • 組織 URL → ユーザーの明示的な確認後に限り、gh api "orgs/<org>/dependabot/alerts?state=open&per_page=100"(すべてのリポジトリを対象にページネーションします)。
    • このスキルでは .dependency.package.ecosystem == "npm" でフィルターし、対象外の JS 以外のアラートを提示します。
    • (repo, package) で重複を排除します。
    • 複数のエコシステムが混在するリポジトリ(Python+npm、Go+npm など): 優先順位付きの表を提示する前に、エコシステムごとにアラートをグループ化します。対象外のエコシステムは、先頭に別のブロックセクションとして出力します。例:「⛔ このスキルの対象外(別途対応してください):pillow × 10(pip)、urllib3 × 2(pip)」。対象外の項目もユーザーが把握して別途対応できるよう、何がカバーされないかを示す必要があります。JS 以外のアラートを黙って除外してはいけません。
  3. 優先順位付けのフレームワーク(影響度 × 露出度 × CVSS)を使って順位付けする。
  4. 最優先の項目についてアドバイザリを確認する — first_patched_version、vulnerable_version_range、cvss.score を抽出します。複数のアドバイザリがある場合は、すべての CVE 修正版を包含する最小バージョンを算出します。
  5. モードを選択する — Fast-Track または Standard を推奨します。 適用条件については「Fast-Track モード」のセクションを参照してください。順位付けした概要とともに、「これは開発用依存関係です。この修正を Fast-Track で進めますか?」 のような一文の推奨を提示します。ユーザーの返答がない、または曖昧な場合は、デフォルトで Standard を選択します。また、CI の PM 用のロックファイルがコミットされていない場合も Standard を選択します。CI のビルドごとに推移的依存関係が新たに解決され、オーバーライドフィールドだけがバージョンを固定する手段となるため、このケースは Fast-Track の対象外です(ロックファイルのパリティを検証できないため)。
標準モード(ステップ 6~8)— 完全な防御的パイプライン
  1. 公開範囲のマッピング — ソース内で対象パッケージのインポート箇所をすべて特定し、それぞれを Public/API · Client-Bundle · Internal/Dev に分類します(「Exposure Mapping」セクションを参照)。件数とサンプルパスを出力します。
  2. 変更履歴の確認 — 現在インストールされているバージョンから対象バージョンまでのリリースノート/CHANGELOG.md を取得します。BREAKING、DEPRECATED、MIGRATION、removed、dropped support を grep します。該当行をそのまま提示します。
  3. 安全インターロック — 一時停止。 公開範囲の概要、変更履歴での該当箇所、選択した対象バージョンをユーザーに表示します。ファイルを編集する前に、明示的な OK(「yes」、「go」、「looks fine」など)を待ちます。BREAKING/DEPRECATED/MIGRATION が該当した場合は、2 回目の肯定を求めます。
Fast-Track モード(ステップ 6~8)— 低リスク向けの簡略手順
  1. 簡易的な公開範囲の確認 — インポート箇所の grep を 1 回実行して、主要な公開範囲カテゴリを確認します。ただし、パスは列挙しません。出力例:Exposure: Internal/Dev (8 sites)。ここで終了し、カテゴリごとの内訳やパス一覧は出力しません。
  2. 変更履歴の確認を省略。 Fast-Track では、変更履歴の確認を省いて速度を優先します。この方法で発生しうる影響範囲は、以下の適格性ルールによって制限されます。
  3. 単一確認のインターロック — 一時停止。 対象バージョン、主要な公開範囲カテゴリ、CVSS、Fast-Track の適格理由を表示します。肯定(「yes」、「go」、「ship it」)が 1 回あれば続行します。曖昧な回答の場合は標準モードに戻ります。
適用(ステップ 9~13)— 両モード共通、必須
  1. ブランチ戦略とベースブランチを確認。 gh repo view --json defaultBranchRef でデフォルトブランチを検出します。main をハードコードしてはいけません。デフォルトでは、検出した最新の origin/<detected-base> を起点として、パッケージごとに PR を 1 つ作成します。
  2. package.json を編集 — ステップ 1 で検出したすべての PM に対して、override フィールドを記述します(npm の overrides、pnpm の pnpm.overrides、yarn の resolutions、bun の overrides。「Override pattern」を参照)。両モードで必須です。
  3. 関連するすべてのロックファイルを再生成 — ステップ 1 で検出した各 PM について、そのインストールコマンドを実行します。コミット済みのロックファイルがない PM については、パリティチェック用に一時的なロックファイルを生成し、コミット前に削除します(「Verify (Parity Check)」を参照)。「プライマリ」のロックファイルはありません。
  4. パリティチェック — ステップ 1 で検出した各 PM について、ロックファイル(または <pm> why の出力)を読み込み、すべての PM で対象パッケージが同じバージョンに解決されていることを確認します。不一致の場合は、両モードとも PR を中止します。 次の対応については「Auto-reversion on parity / build failure」を参照してください。
  5. ブランチにコミットして PR を作成 — プッシュする前に、ユーザーから明示的な OK を得ます。

確認なしでは Claude が行わないこと

  • 直接依存関係をメジャーバージョンをまたいで更新する(破壊的変更)。
  • 変更履歴の確認で BREAKING/DEPRECATED/MIGRATION が見つかった場合に、ユーザーから 2 回目の確認を得ずに更新する。
  • ロックファイルのパリティチェックに失敗した場合に PR を作成する(標準モード/Fast-Track モードのいずれでも)。
  • 両方への override の書き込みを省略する(両モードで必須)。
  • 適格性がないケースで Fast-Track を使用する — Public/API のインポート箇所があり、CVSS ≥ 7.0、アドバイザリの深刻度が critical、またはメジャーバージョンをまたぐ更新が必要な場合。ユーザーの要望にかかわらず標準モードに切り替えます。この安全基準は変更できません。
  • ユーザーが単一のリポジトリ URL だけを貼り付けた場合(またはその逆)に、組織全体へ自動的に展開する。
  • パッケージを削除または置き換える。
  • main にプッシュする/PR をマージする。
  • コミット前フックを省略する。

Fast-Track モード

低リスクな更新のための、ワークフローを簡略化したモードです。変更履歴の確認と詳細な公開範囲の列挙を省き、速度を優先します。ロックファイルの整合性は犠牲にしません。両方への override の書き込みとパリティチェックは引き続き必須です。

適格条件(いずれか1つを満たせば十分です)
  • 開発専用の露出 — 軽量なインポート箇所チェックで、Internal/Dev(設定、スクリプト、テスト、ツール)にある箇所が 90% 以上で、Public/API にある箇所がゼロであることが示されます。
  • 低 CVSS — security_advisory.cvss.score < 7.0 かつ、Public/API にインポート箇所がないこと。
  • ユーザーによるオプトイン — ユーザーが "fast-track"、"just bump it"、"don't bother with the changelog" など、同等の表現を明示的に使用していること。

いずれにも該当しない場合は、デフォルトで標準モードにします。

適格性の絶対条件(例外なし — 常に標準モード)

次の場合、ファストトラックは拒否し、1行で説明して標準モードに切り替えます。

  • パッケージに Public/API のインポート箇所があり、かつ CVSS ≥ 7.0 である。
  • アドバイザリの深刻度が critical である(CVSS にかかわらず)。
  • メジャーバージョンをまたぐ更新が必要である(防御的な最小バージョンが次のメジャーバージョンにある)。
  • CI が、コミット済みのロックファイルがその PM に存在しない状態で、PM の緩いインストールコマンド(ロックファイル厳格準拠の同等コマンドではないもの)を実行している。CI のビルドごとに依存関係が再解決されるため、オーバーライドフィールドだけがその側のバージョンを固定します。リスクが高いため、標準モードで詳細をすべて確認する必要があります。また、比較対象となるコミット済みロックファイルがないため、パリティチェックの対象にもなりません。

これらに例外はありません。該当するケースでユーザーがファストトラックを明示的に希望した場合は、丁寧に断り、安全上の最低基準はユーザーが変更できないことを伝えたうえで、標準モードを実行します。

ファストトラックで省略する内容
手順標準モードファストトラック
露出のマッピング(箇所ごとの列挙)はい — カテゴリごとにパスをすべて列挙省略 — 最も多いカテゴリのみを1行で表示
変更履歴の確認はい — リリースノートと CHANGELOG.md を確認し、BREAKING/DEPRECATED/MIGRATION に該当する項目に印を付ける省略
安全インターロック破壊的変更を示すキーワードがある場合は2回確認1回確認
ファストトラックでも省略しない内容(必須)
手順両モード共通
防御的な最小修正バージョンはい
オーバーライドの二重書き込み(オーバーライドのパターンを参照)はい
両方のロックファイルの再生成はい
ロックファイルのパリティチェックと、不一致時の中止はい
明示的なユーザーの OK を得てからコミットとプッシュはい
推奨の提示

手順 5 で優先順位付きの概要を提示する際は、モード列または1行の推奨文を含めます。

Rank | Repo            | Package           | CVSS | Exposure (dominant) | Recommended mode
1    | webhook-ternity | @types/node       | 5.3  | Internal/Dev        | Fast-Track (Internal/Dev + low CVSS)
2    | webhook-ternity | axios             | 7.5  | Public/API          | Standard (hard-ineligible: Public/API + CVSS ≥ 7)
3    | webhook-ternity | follow-redirects  | 6.5  | Public/API          | Standard (Public/API exposure, no auto-rule fires; opt-in available)

必要に応じて、次の文をそのままプロンプトとして使用してください。「#1 は CVSS 5.3 の開発専用 @types の更新です。この修正をファストトラックで進めますか?」

注:クライアントバンドルの XSS サニタイザーパッケージ(例:dompurify、sanitize-html)で CVSS < 7.0 のものは、適格性テーブルに従い、自動的にファストトラックのルールに該当します。推奨を提示しつつ、次のように注意を促してください。「これはクライアントバンドル内のサニタイザークラスのパッケージです。CVSS に基づきファストトラックの対象ですが、変更履歴を確認するために標準モードを選ぶのもよいでしょう。ご判断ください。」 ユーザーの判断に委ねます。

パリティチェックまたはビルド失敗時の自動切り替え

ファストトラックでは分析を省略しますが、失敗を見過ごすことはありません。更新後に次のいずれかが発生した場合:

  • パリティチェックに失敗した場合(npm と pnpm で異なるバージョンが解決された場合)、または
  • ユーザーが pnpm build / npm test を実行し、失敗したと報告した場合、または
  • プリコミットフック(lint、typecheck)に失敗した場合

…同じパッケージについて、標準モードに切り替えることを提案します。

「ファストトラックで <failure> が発生しました。標準モードで再実行し、変更履歴と露出の完全なマッピングを確認して、実際に何が変わったのかを調べますか?」

失敗後、同じパッケージに対してファストトラックを黙って再試行しないでください。標準モードに切り替えるか、停止して確認を求めてください。更新に失敗した後にファストトラックを繰り返し試すことこそ、このモードが避けるために設計された落とし穴です。

優先順位付けフレームワーク

3 つの軸を、次の順で評価します。

  1. 影響度 — RCE > データ窃取/SSRF > DoS > ロジックのバグ
  2. 露出範囲 — 下記の「露出範囲の分類」を参照します。脆弱性に到達できるかどうかを推測するためのヒューリスティックではありません。パッケージがどこでインポートされているかを分類し、攻撃対象領域の概要としてユーザーに提示します。
  3. CVSS — 同点の場合にのみ使用します。露出範囲の情報なしに生のスコアだけを見ると、誤解を招きます(例:axios の SSRF は 4.8 と表示されますが、axios が Public/API に含まれる場合は、より重要です)。

CVSS=0 の場合のフォールバック。 Dependabot は、アドバイザリのスコアがまだ付いていない場合(新しい GHSA でよくあります)、security_advisory.cvss.score: 0(または null)を返します。未採点のアラートが、CVSS 順のランキングで最下位にならないようにしてください。代わりに security_advisory.severity(常に設定されています)を使います。スコアの概算対応は、critical ≈ 9.5、high ≈ 7.5、medium ≈ 5.0、low ≈ 2.0 です。ランキング表では、フォールバックしたことを明示してください。たとえば cvss: — (high) とし、cvss: 0 とは表示しません。こうすることで、高深刻度のアラートが低い CVSS のアラートより上位にある理由がユーザーに伝わります。

露出範囲の分類

従来のヒューリスティックな「到達可能性」モデルに代わるものです。脆弱性に到達できないことを証明しようとするのをやめるのが目的です。見落としは危険です。代わりに、対象パッケージのすべてのインポート箇所を列挙し、それぞれを分類します。ユーザーは攻撃対象領域をもとに、最終的なリスクを判断します。

カテゴリ
カテゴリ定義ファイルパスの例
Public/API信頼境界の外部からの HTTP/RPC/Webhook トラフィックを処理するコードです。攻撃者が制御する入力が流入します。handlers/、routes/、controllers/、app/api/**/route.{ts,js}、pages/api/**、middleware.{ts,js}、+server.{ts,js}、+page.server.{ts,js}、Lambda のエントリーハンドラー、Express/Fastify のルート定義
Client-Bundleブラウザーのバンドルに含まれるコードです。XSS/DOM インジェクション/ブラウザーに表示される悪意あるユーザーコンテンツを介して到達可能です。src/components/**、src/app/**/{page,layout,loading,error}.{ts,tsx}(.server. サフィックスなし)、src/pages/**(Next.js の従来形式)、Vue/Svelte のコンポーネントファイル、<script> として配信されるエントリーファイルにインポートされるものすべて
Internal/Devビルド、ツール、スクリプト、テスト、設定に関するものです。本番環境のリクエスト処理では実行されず、ブラウザーにも配信されません。vite.config.*、next.config.*、*.config.{js,ts,mjs}、scripts/、tests/、**/*.test.*、**/*.spec.*、.husky/、.cicd/、tools/、bin/(CLI スクリプト)
インポート箇所の列挙方法

ripgrep を優先します(高速で、.gitignore を尊重します)。

# Find every import site of <pkg>
rg -t js -t ts "from ['\"]<pkg>(/|['\"])|require\(['\"]<pkg>(/|['\"])" -l | sort -u

grep を使う場合:

grep -rE "from ['\"]<pkg>['\"]|require\(['\"]<pkg>['\"]\)" \
  --include='*.{js,jsx,ts,tsx,mjs,cjs,mts,cts,vue,svelte}' -l | grep -v node_modules

次に、上記の表に照らし合わせて各パスを分類します。明確に分類できないパスについては、推測せずにユーザーに確認してください。

ユーザーへの提示方法

判定結果ではなく、攻撃対象領域の概要として出力します。

Exposure surface for axios in webhook-ternity:
  Public/API     : 12 sites (e.g. handlers/getAllCandidates.js, handlers/public/idMetadata.js, ...)
  Client-Bundle  : 0 sites
  Internal/Dev   : 3 sites (e.g. tests/util.test.js, scripts/migrate.js, ...)

1 つのインポート箇所が複数のカテゴリにまたがる場合(例:あるユーティリティがルートハンドラーとクライアントコンポーネントの両方から再エクスポートされている場合)は、該当する中で最もリスクの高いカテゴリを適用します。

ユーザーは攻撃対象領域を見て、更新に伴うリスクを受け入れる価値があるかを判断します。Claude は「到達可能です」または「到達できません」とは述べません。

複数リポジトリ/組織全体のランキング(オプトイン)

ユーザーが組織全体への展開を明示的に依頼した場合にのみ実行します。Impact × Exposure × CVSS に加えて、次のルールを適用します。

  • まず (repo, package) ごとにグループ化します。 GitHub は、同じ依存関係に対して N 件の CVE があると、(repo, package) のペアごとに N 件のアラートを生成します。それらをまとめます。1 回の更新でクラスター全体を修正できます。
  • クラスターにボーナスを付与します。 アラートが多数ある (repo, package) のペアが Public/API リポジトリにある場合、個々の CVSS スコアが中程度でも、最も ROI の高い候補です。例:Webhook サービスの HTTP クライアントに関するアラート 30 件は、社内 CLI ツールの CVSS 9 のアラート 1 件より優先度が高くなります。1 件の PR で 30 件のアラートを解消でき、露出度も高いためです。
  • リポジトリの特性は手がかりであり、断定材料ではありません。 バックエンド/Webhook リポジトリには、HTTP ライブラリの Public/API インポート箇所がある傾向があります。フロントエンドリポジトリには、XSS サニタイザーの Client-Bundle インポート箇所がある傾向があります。決めつけずに、Exposure Mapping で確認してください。

順位、リポジトリ、パッケージ、露出の概要(Public/API/Client-Bundle/Internal/Dev の件数)、集約したアラート数を含むランキング表を出力します。ユーザーに選んでもらうか、デフォルト(順位 1)を承認してもらいます。

ブランチ戦略

デフォルト:ブランチごとにパッケージ 1 つ、ブランチごとに PR 1 件です。 レビューしやすく、単一のオーバーライドが下流の何かを壊した場合にも簡単に取り消せます。

ベースブランチを動的に特定する

main をハードコードしてはいけません。ベースは main、master、pre-release、develop などの場合があります。実行時に検出してください。

# Repo's configured default branch (preferred)
gh repo view --json defaultBranchRef --jq .defaultBranchRef.name

# Fallback if gh unavailable
git symbolic-ref refs/remotes/origin/HEAD --short | sed 's@^origin/@@'

ユーザーが異なるリリースフロー(例:PR のマージ先が pre-release で、その後 main に昇格)を使っている場合は、この PR のマージ先ブランチを確認してください。決めつけてはいけません。

必ずローカルではなく、最新のリモートベースからブランチを作成する
BASE=<detected-or-confirmed-base>
git fetch origin "$BASE"
git checkout -b <new-branch> "origin/$BASE"

ローカルのベースブランチは古くなっている可能性があります。そこからブランチを作成すると、上流のコミットを取り込めていないことによる差分が PR に混入します。

複数の PR を扱うセッションでは、新しいブランチを作成する直前に git fetch origin <base> を実行してください。 セッションの前半で取得した情報を再利用してはいけません。同じセッションで先に作成した PR がすでにマージされている(自動マージや迅速なレビューなど)場合、前回の fetch 以降に origin/<base> が進んでいる可能性があります。古い情報を使うと、最新の情報を取得することで防ごうとしていた、マージ時の競合が再び発生します。

戦略の選択肢 — ユーザーに確認する

作業を始める前に、この一連の変更でどの戦略を使うかユーザーに確認してください。

  • (a) パッケージごとに PR を 1 件作成する(デフォルト)— 独立しており、きれいに取り消せます
  • (b) 複数のパッケージを 1 件の PR にまとめる — レビュー対象の PR は減りますが、取り消しが連動します
  • (c) 既存のブランチ/オープン中の PR に積み重ねる — 先行する PR がまだオープン中で、まとめたい場合に便利です

ユーザーが「どちらでも、よりすっきりする方で」と答えた場合は、(a) を選択してください。

複数のマニフェストに同じパッケージがある場合

脆弱性のある同じパッケージが複数のマニフェスト(例:ルートのマニフェストとサブパッケージのマニフェスト)に含まれている場合、デフォルトではすべてのマニフェストを対象に、パッケージごとに PR を 1 件作成します。1 つのブランチですべての該当マニフェストを編集し、該当するすべてのロックファイルを再生成します。これにより PR の数を抑え、修正を一体として扱えます。

マニフェスト間で露出カテゴリに大きな違いがあり(例:ルートのマニフェストでは Public/API、サブマニフェストでは Internal/Dev)、ユーザーが露出レベルごとに明確にレビューを分けることを明示的に希望する場合にのみ、マニフェストごとの PR に分割してください。

複数 PR セッション:順次リベースの競合パターン

ユーザーが戦略(a)— パッケージごとに 1 つの PR — を選択し、複数の PR が同じマニフェストを対象とする場合、後続の PR はすべて、同じ挿入位置(overrides ブロック)でマニフェストの競合が発生します。これは予測可能なものであり、エラーではありません。解決方法は常に追加です。HEAD の overrides を残し、受信した PR のキーを追加してください。

各 PR のマージ後に、次の手順を実行します。

  1. git fetch origin <base>
  2. git checkout <next-branch> && git rebase origin/<base>
  3. 競合を解決し、既存の override キーをすべて残して新しいキーを追加します。
  4. このスキルの Override パターンのセクションを参照し、PM のロックファイルのみを更新するインストールコマンドでロックファイルを再生成します。
  5. git add <manifest> <lockfile> && git rebase --continue
  6. git push --force-with-lease origin <next-branch>

--force(lease なし)は使用しないでください。取得した時点より先にリモートが更新されていた場合に処理を中止する安全チェックが省略されます。

アラートごとのワークフロー

「使用中のパッケージマネージャーを検出する」(ワークフローのステップ 1)が完了していることを前提とします。以下のオーバーライドと整合性マトリックスは、このリポジトリでどのパッケージマネージャーが使われているかを把握している必要があります。

  1. 重複をまとめる:GitHub は、コミットされたロックファイルごとにアラートを 1 件生成します。コミットされたロックファイルが 2 つ(例:package-lock.json と pnpm-lock.yaml)あれば、1 件の脆弱性に対してアラートは 2 件です。パッケージは 1 回だけ修正してください。

  2. アドバイザリを取得する:gh api repos/<org>/<repo>/dependabot/alerts/<n> を実行し、first_patched_version と vulnerable_version_range を抽出します。リストエンドポイントではこれらは表示されません。アラートのまとまりがある場合は、そのすべてのアラートを取得してください。

  3. 場所を特定する:直接依存関係(package.json 内)ですか、それとも間接依存関係ですか? 依存元を検索します:

    node -e "const l=require('./package-lock.json'); for(const[k,v]of Object.entries(l.packages||{}))if(v.dependencies?.['<pkg>']||v.devDependencies?.['<pkg>'])console.log(k,v.version);"
    
  4. 公開範囲のマッピング:「公開範囲のマッピング」セクションを参照してください。すべてのインポート箇所を分類(Public/API · Client-Bundle · Internal/Dev)し、ユーザー向けに影響範囲の概要を作成します。

  5. バージョンの選定(安全性を重視した最小修正版):

    • アラートが 1 件の場合:first_patched_version の ^X.Y.Z。
    • アラートが複数ある場合:クラスタ内のすべての CVE の first_patched_version の最大値を X.Y.Z とした ^X.Y.Z。つまり、すべての修正を包含する最小バージョンです。次のコマンドで算出します:
      for n in <alert-numbers>; do
        gh api repos/<org>/<repo>/dependabot/alerts/$n \
          --jq '.security_advisory.vulnerabilities[0].first_patched_version.identifier'
      done | sort -V | tail -1
      
    • 「同じメジャーバージョン内の最新」をデフォルトにしないでください。 最新バージョンは変更範囲を最大化し、間接依存関係を壊すリスクがあります。安全性を重視した最小バージョンを上書きするのは、(a)ユーザーが明示的に依頼した場合、または(b)最小バージョンがメンテナンスされていない、配布が取り下げられている、あるいは新たな CVE を引き起こす場合に限ります。
    • ユーザーがメジャーバージョンの更新を承認しない限り、現在インストールされているものと同じメジャーバージョンを上限とします。
  6. 変更履歴の確認 — 現在のバージョンから対象バージョンまでのリリースノートを取得します。まず GitHub リリース API を試し、取得できない場合はパッケージの tarball から CHANGELOG.md を確認します:

    # 1. Find the upstream repo
    PKG_REPO=$(npm view <pkg> repository.url | sed -E 's|.*github\.com[/:]([^.]+)\.git|\1|')
    # 2. Pull release notes for the target tag (try with and without leading "v")
    gh release view "v<target>" --repo "$PKG_REPO" --json tagName,body,createdAt 2>/dev/null \
      || gh release view "<target>" --repo "$PKG_REPO" --json tagName,body,createdAt
    # 3. Fallback: CHANGELOG from the published tarball
    npm pack <pkg>@<target> >/dev/null
    tar -xf <pkg>-<target>.tgz -C /tmp/<pkg>
    grep -inE 'BREAKING|DEPRECATED|MIGRATION|removed|drop(ped)? support' /tmp/<pkg>/package/CHANGELOG.md | head -50
    

    該当する行をそのままユーザーに提示してください。言い換えないでください。BREAKING/DEPRECATED/MIGRATION が含まれる場合は、セーフティインターロックを「2 回目の確認が必要」に引き上げてから続行します。

    間接依存関係に関する補足: 2 回目の確認を求める前に、該当パッケージがソースコード内で直接インポートされている箇所があるか(「公開範囲のマッピング」ステップで)確認してください。直接インポートが 0 件の場合、そのパッケージは純粋な間接依存関係です。フラグとともに、これを明示してください:"このフラグが示すパッケージは、ソースコードから直接インポートされていません。コードがそのエラーメッセージを解析したり、内部機能にフックしたりしない限り、破壊的変更が影響する可能性は低いです。" フラグが呼び出し元のコードに明らかに関係しない場合、これにより確認を 2 回から 1 回に減らせます。

  7. セーフティインターロック — 一時停止。 次の内容をユーザーに提示します:

    • 選定した対象バージョンとその理由(安全性を重視した最小バージョンか最新バージョンか、その理由)
    • 影響範囲(カテゴリごとの件数、パスの例)
    • 変更履歴のフラグ(該当行をそのまま提示。問題がなければ「フラグなし」)

    明示的な承認を待ちます。変更履歴にフラグがある場合は、「はい、続けてください」/「対応済みです」といった明確な承認を必須とします。返答がない場合や曖昧な返答の場合は停止します。

  8. ユーザーの承認後:package.json を編集し、両方のロックファイルを再生成して、整合性チェックを実行し、コミットしてから、プッシュしてよいか尋ねます。

オーバーライドのパターン(Node.js)

次の場合にオーバーライドを使用します:

  • 間接依存関係の脆弱性 — パッケージが dependencies/devDependencies にありません。親パッケージを更新せずに修正するには、オーバーライドが唯一の方法です。
  • 間接依存関係も同じパッケージを要求する直接依存関係 — dependencies.<pkg> を更新しても、間接依存関係が同じバージョンになるとは限りません(semver の範囲が異なると、別々に hoist される場合があります)。多層防御としてオーバーライドも追加してください。
デュアルライトは必須です

ステップ 1 で検出したすべての PMについて、どのコンテキスト(ローカルインストール、CI インストール、コンテナビルド)でも override フィールドに書き込みます。PM によって使用する override フィールドは異なります。

PMpackage.json の override フィールド
npmoverrides
pnpmpnpm.overrides
yarn classic (v1)resolutions
yarn berry (v2+)resolutions
bunoverrides

複数の PM が使われているのに 1 つだけに書き込むと、環境のずれが発生します。開発者のローカル環境で解決されるバージョンと、CI で出荷されるバージョンが異なります。まさにこの種のバグを防ぐために、このスキルがあります。現在コミットされているロックファイルが 1 つだけでも、毎回、関連するすべてのフィールドに同じ対象範囲の override を書き込みます。

この組織でよくある構成は npm-CI + pnpm-local です。同じずれは、PM が異なる任意の構成(yarn-local + npm-CI、bun-local + npm-CI など)でも発生します。npm + pnpm の標準的なデュアルライトは次のとおりです。

{
  "pnpm": {
    "overrides": {
      "<pkg>": "^X.Y.Z"
    }
  },
  "overrides": {
    "<pkg>": "^X.Y.Z"
  }
}

yarn + npm の組み合わせでは resolutions と overrides に、yarn + pnpm の組み合わせでは resolutions と pnpm.overrides に書き込みます。上の表に従って使い分けてください。

次に、関連するすべてのロックファイルを再生成します。pnpm + npm の標準的な組み合わせは次のとおりです。

pnpm install --no-frozen-lockfile
npm install --package-lock-only

ほかの PM の再生成コマンドは、「Frontend repos → Lockfile + override syntax per package manager」の表に記載されています。

ワークフローの最後に行うパリティチェックでは、すべての PM で同じ解決済みバージョンが生成されたことを確認します。「Verify (Parity Check)」を参照してください。

npm の EOVERRIDE:override は直接依存関係の範囲内である必要があります

overrides.<pkg> が dependencies / devDependencies で宣言された範囲に収まらない場合、npm はエラーを返します。

EOVERRIDE: Override for <pkg>@<range> conflicts with direct dependency

標準的な修正方法は 2 つあります。

  • 直接依存関係の範囲を狭めることで、override と一致させるか、override より狭い範囲にします。例:直接依存関係の "postcss": "^8" と overrides.postcss: "^8.5.10" を組み合わせるとエラーになります。直接依存関係を "postcss": "^8.5.10" に変更すれば、override が問題なく適用されます。
  • 直接依存関係の範囲を変更したくない場合は、"$<pkg>" で自己参照します。例:"overrides": { "postcss": "$postcss" } — npm は解決済みの直接依存関係のバージョンを再利用します。直接依存関係がすでにパッチ適用済みのバージョンで、推移的依存関係に同じバージョンを適用するだけでよい場合に便利です。

yarn の resolutions にはこの制約はありません。これは npm の overrides に限られます。

フロントエンドのリポジトリ(ブラウザー用バンドル + SSR)

コアワークフローは、React、Next.js、Vite、Vue、Svelte、Angular のリポジトリにもそのまま適用できます。フロントエンド固有の内容は次のとおりです。

パッケージマネージャーごとのロックファイルと override 構文
パッケージマネージャーロックファイルpackage.json の override フィールド再生成コマンド
npmpackage-lock.json"overrides": { ... }npm install --package-lock-only
pnpmpnpm-lock.yaml"pnpm": { "overrides": { ... } }pnpm install --no-frozen-lockfile
yarn (v1)yarn.lock"resolutions": { ... }yarn install
yarn (berry, v2+)yarn.lock"resolutions": { ... }yarn install
bunbun.lockb (または bun.lock)"overrides": { ... }bun install

複数のロックファイルが共存している場合(移行中、または npm-CI / pnpm-local の構成でよくあります)、override を両方に書き込み、それぞれを再生成します。パリティチェックも引き続き適用されます。アラートのペイロードにある .dependency.manifest_path から、アラートが参照しているロックファイルを検出してください。

CSR + SSR 混在時のエクスポージャーマッピング

現代のフロントエンドリポジトリが純粋な CSR であることはほとんどありません。Next.js、Nuxt、Remix、SvelteKit、さらには一部の Vite 構成でも、バンドルとともにサーバーランタイムが提供されます。同じ依存関係が複数のエクスポージャーカテゴリに同時に該当することがあります。

フロントエンドリポジトリで関係する 3 つのカテゴリ:

  1. Public/API — 外部の HTTP/RPC トラフィックを処理するサーバーランタイムです。例:Next.js の app/**/route.{ts,js}、pages/api/**、middleware.{ts,js}、Remix の loader/action、Nuxt のサーバールート、SvelteKit の +page.server.{ts,js} と +server.{ts,js}。バックエンドの Public/API インポートとまったく同じように扱います。
  2. Client-Bundle — ブラウザーのバンドルに含まれるコードです。例:src/components/**、.server. サフィックスのない src/app/**/{page,layout,loading,error}.{ts,tsx}、src/pages/**(Next.js のクラシックなデフォルトエクスポート)、Vue/Svelte のコンポーネントファイル、<script> によって読み込まれるエントリからインポートされるすべてのコード。
  3. Internal/Dev — 設定、ビルド、スクリプト、テストです。例:vite.config.*、next.config.*、*.config.{js,ts,mjs}、scripts/、tests/、**/*.test.*、**/*.spec.*。

同じ依存関係が src/components/Foo.tsx(Client-Bundle)と src/app/api/foo/route.ts(Public/API)の両方でインポートされている場合、優先順位付けでは Public/API カテゴリを適用します。影響範囲が単一の領域に限られないことを理解できるよう、両方をユーザーに示してください。

パスが曖昧な場合(たとえば、共有ユーティリティの lib/http.ts が両方の領域に再エクスポートされている場合)は、推測せずにユーザーに確認してください。

フロントエンド固有の影響度の重み付け

引き続き影響度を最優先しますが、インポート元が Client-Bundle のみか Public/API のみかによって、重み付けの基準が変わります。

  • Client-Bundle のみからのインポート — 優先度が高いもの:XSS サニタイザーのバイパス(dompurify、sanitize-html)、クライアント状態管理ライブラリでのプロトタイプ汚染(lodash.merge、pre-9 の immer)、i18n ライブラリでのテンプレートインジェクション、ルーター/パスマッチャーでの ReDoS。優先度が低いもの:SSRF、ヘッダーインジェクション、NO_PROXY のバイパス(ブラウザーからのアウトバウンド HTTP はありません)。
  • Public/API からのインポート(サーバー側で実行される領域) — サーバー向けの優先度を全面的に適用します。SSRF、ヘッダーインジェクション、HTTP クライアントでのプロトタイプ汚染が再び重要になります。

Client-Bundle からのインポート箇所にしか現れない axios の CVSS-9 の SSRF は、通常は優先度が低くなります。同じ脆弱性でも、Public/API からのインポート箇所にあれば重大です。どちらに該当するかを示すのが Exposure Mapping の出力です。

フレームワークのバージョン固定 — 慎重に進めてください

React/Next/Angular/Vue では、peer deps やファーストパーティのメタパッケージによって、推移的なバージョンが固定されていることがよくあります。更新する前に、以下を確認してください。

  • 親フレームワーク(next、react、@angular/core)の peerDependencies を確認してください。
  • プロジェクトの途中で @types/react、react-dom、next をメジャーアップデートすると、30 以上のパッケージに影響が連鎖することがよくあります。「別 PR と手動のスモークテストが必要」として明示し、セキュリティ更新の PR に含めないでください。
  • core-js、regenerator-runtime、tslib の更新は通常安全です。一方、名前が -loader または -plugin で終わるもの(webpack/rollup/vite エコシステム)の更新はビルドを壊すことがよくあります。PR を作成する前に pnpm build(または同等のコマンド)を実行して確認してください。Changelog Scrape のステップでは、これらの多くが BREAKING/removed フラグによって検出されます。

バージョン範囲のルール

  • デフォルトでは、保守的に最小限のパッチ適用バージョンを指定します。 ^X.Y.Z を使用します。ここで X.Y.Z は、該当するすべての CVE パッチを含む最小バージョンです(単一のアラートの場合は first_patched_version、クラスターの場合はクラスター内の first_patched_version の最大値)。メジャーバージョン内の最新バージョンを指定するのは、明示的に選ぶ場合に限ります。変更範囲が広がるほど、更新自体が何かを壊す可能性が高まります。
  • >=X.Y.Z ではなく、^X.Y.Z を使用します。下限は同じですが、<next_major に上限を設けることで、予期しないメジャーバージョンへの更新を防げます。
  • >X.Y.Z は使用しないでください。パッチ適用バージョン自体が除外されて X.Y.Z+1 を強制されますが、利点はありません。
  • pnpm の条件付きオーバーライド(脆弱性が特定の範囲に限られる場合)には、<pkg>@<range>: <fix> の構文を使用します。例:"axios@<1.12.0": ">=1.12.0"。
  • 条件付きオーバーライドは古くなります。 以前の条件付きオーバーライド(例:"axios@<1.12.0": ">=1.12.0")があり、新しい CVE の範囲が以前の上限を超える場合は、そのエントリーを包括的な "axios": "^<minimal-patched>" に置き換えてください。条件を連鎖させないでください。CVE の新しいバッチごとに下限を引き上げます。
  • 保守的な最小バージョンがメンテナンスされていない、公開取り下げ済み、または新たな CVE を引き起こす場合は、ユーザーに確認してください。次に新しい候補とその変更履歴の調査結果を提示し、ユーザーに選択してもらいます。

検証(パリティチェック)

確認事項は2つです。PR を作成する前に、両方に合格する必要があります。代表的な npm と pnpm の組み合わせだけでなく、手順1で検出されたすべてのパッケージマネージャーで実行してください。

1. パッチ適用バージョンの解決

検出されたパッケージマネージャーごとに、対象パッケージが >= minimal_patched_version に解決されることを確認します。パッケージマネージャーに直接問い合わせる(またはロックファイルを直接読む)のが最も確実な方法です。ロックファイル形式の変更にも対応できます。

# npm: read package-lock.json directly
NPM_VER=$(node -e "const l=require('./package-lock.json'); console.log(l.packages['node_modules/<pkg>']?.version || '');")

# pnpm: ask pnpm itself for the resolved root version
PNPM_VER=$(pnpm why <pkg> --depth=0 --json 2>/dev/null \
  | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{const j=JSON.parse(d);const v=j[0]?.dependencies?.["<pkg>"]?.version || j[0]?.devDependencies?.["<pkg>"]?.version;console.log(v||"")})')

# yarn classic (v1)
YARN_VER=$(yarn why <pkg> 2>/dev/null | grep -oE 'Found "<pkg>@[^"]+"' | head -1 | sed -E 's/.*@//; s/"$//')

# yarn berry (v2+)
YARN_VER=$(yarn why <pkg> --json 2>/dev/null | head -1 \
  | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{try{const j=JSON.parse(d);const k=Object.keys(j.children||{})[0];console.log(j.children?.[k]?.locator?.split("@npm:")[1]||"")}catch{}})')

# bun
BUN_VER=$(bun pm ls --all 2>/dev/null | grep -E '\b<pkg>@' | head -1 | sed -E 's/.*@//')

echo "npm=$NPM_VER pnpm=$PNPM_VER yarn=$YARN_VER bun=$BUN_VER"

実際に使われているパッケージマネージャーの変数だけを使用し、それ以外は無視してください。すべてでパッチ適用済みバージョン(またはそれ以上)が示される必要があります。

コミット済みのロックファイルがないパッケージマネージャー用の一時ロックファイルの生成

CI で、コミット済みのロックファイルがないパッケージマネージャーが使われている場合(例:yarn.lock はコミットされているが、CI では npm install を実行する場合)は、パリティチェックのためだけに一時ロックファイルを生成し、コミット前に削除してください。

パッケージマネージャーロックファイルのみを再生成生成されるファイル
npmnpm install --package-lock-onlypackage-lock.json
pnpmpnpm install --lockfile-onlypnpm-lock.yaml
yarn classicyarn install --mode=update-lockfileyarn.lock
yarn berryyarn install --mode=update-lockfileyarn.lock
bunbun install --frozen-lockfile=falsebun.lock

⚠ すでにコミット済みのロックファイルがないパッケージマネージャーで生成したロックファイルをコミットしないでください。ロックファイルが二重に存在することで生じる不整合こそ、このスキルが防ごうとしている問題です。権威ある pnpm-lock.yaml と並んで生成された yarn.lock があると、次回の yarn install で気づかないうちに不整合が生じ、影響範囲が半減するどころか倍増します。

検出された CI のパッケージマネージャー用にコミット済みのロックファイルがない場合は、次の点も明示的に確認してください。

  • そのパッケージマネージャー用のオーバーライドフィールドが package.json に存在すること(「オーバーライドのパターン → 二重記述は必須」のパッケージマネージャー表を参照)。
  • 対象パッケージの直接依存関係の範囲がオーバーライドと一致していること(EOVERRIDE 対策。「npm EOVERRIDE」を参照)。
2. ロックファイルの整合性(必須 — 不一致があれば PR を中止)
# Collect non-empty resolved versions across all detected PMs
VERS=$(printf '%s\n' "$NPM_VER" "$PNPM_VER" "$YARN_VER" "$BUN_VER" | grep -v '^$' | sort -u)
COUNT=$(echo "$VERS" | grep -c .)

if [ "$COUNT" -eq 0 ]; then
  echo "PARITY ABORT: could not resolve <pkg> in any lockfile"
  exit 1
fi
if [ "$COUNT" -gt 1 ]; then
  echo "PARITY ABORT: PMs disagree:"
  echo "$VERS"
  exit 1
fi
echo "PARITY OK: all PMs resolved <pkg>@$VERS"

PM のいずれかの組み合わせで対象パッケージの解決バージョンが異なる場合は、PR を中止してください。プッシュしないでください。PR を作成しないでください。不完全な修正状態でコミットしないでください。すべてのバージョンと考えられる原因をユーザーに提示してください。

  • オーバーライドがいずれかのオーバーライド機構に設定されていない(最も一般的)— package.json を再編集し、該当するすべてのフィールドにオーバーライドを設定してから、再生成し、再確認します。
  • 条件付き pnpm オーバーライド(pkg@<range>)を npm が認識しない — 一律のオーバーライドに置き換えます。
  • pnpm のホイスティング境界により、異なるバージョンの推移的なコピーが作成される — pnpm-lock.yaml の調査が必要な場合があります(pnpm why <pkg> で複数のバージョンが表示されます)。
  • npm の EOVERRIDE により、オーバーライドが暗黙にブロックされたか、明示的に失敗した — 直接依存関係の範囲を確認します(「npm の EOVERRIDE」を参照)。
  • peer dependency の不一致によって推移的な解決結果が異なる — 強制する前に調査します。

開発環境と CI/CD 間の環境の差異(npm-CI と pnpm-ローカル、npm-CI と yarn-ローカル、bun-ローカルと npm-CI など、PM のあらゆる組み合わせ)が、このスキルで防止するバグの種類です。整合性チェックは必須です。

インストール時の標準出力を鵜呑みにしない

npm install --package-lock-only は、オーバーライドによって再解決が行われ、ロックファイルが実際には変更されていても、up to date と表示することがあります。pnpm、yarn、bun でも、一部の例外的なケースでは同様です。必ず上記の確認コマンドを実行してください。これらのコマンドは、ロックファイル(または PM 独自の解決グラフ)を直接読み取ります。

コミット/PR の形式

  • タイトル:security: bump <pkg> to ^X.Y.Z (CVE-XXXX-YYYYY)
  • 本文:Dependabot アラート番号へのリンク、アドバイザリ(GHSA + CVE)の名前、CVSS の記載、依存関係の連鎖の説明、オーバーライドのみの場合はソースコードに変更がない旨を記載します。

マージ後 — UI の遅延

GitHub の Dependabot UI の件数は、実際の修正から 5~30 分ほど遅れることがあります。マージ直後にユーザーから「閉じたアラートは N 件だけで、予測した M 件ではない」と報告されても、修正が不完全だと決めつけないでください。まず API で確認します。

# Open axios alerts in this repo right now
gh api "repos/<org>/<repo>/dependabot/alerts?state=open&per_page=100" --jq '[.[] | select(.dependency.package.name=="<pkg>")] | length'

# Fixed-today list (sanity check the merge actually closed them)
gh api "repos/<org>/<repo>/dependabot/alerts?state=fixed&per_page=100" --jq '[.[] | select(.dependency.package.name=="<pkg>" and (.fixed_at | startswith("'"$(date -u +%Y-%m-%d)"'")))] | length'

API で修正が確認できても UI に古い件数が表示されている場合は、リグレッションではなく UI の遅延であることをユーザーに伝えてください。正しい情報源は API です。通常、ロックファイルのプッシュから 1 時間以内に UI が更新されます。

プラットフォームに関する注意事項

  • Windows + OneDrive:同期中に OneDrive がファイルを一時的にロックするため、yarn install/npm install/pnpm install が .node ネイティブバイナリで EPERM エラーになることがあります。通常は 1 回再試行すれば解消します。プロセスを終了したり、--force にエスカレーションしたりせず、1 回だけ再試行してください。

コメント