Dependabot を入れると、次に必ず欲しくなるのが auto-merge です。@types/node のパッチを毎回手でマージするのは時間の無駄——けれど何でも自動マージすると、破壊的変更を無人で本番に流し込む事故になります。正解は 「壊れる確率が低いものだけ(patch/minor)を、CI 通過を条件に自動マージし、major は人間がレビューする」 という分業です。
この記事はDependabot 本番運用ガイドの各論として、GitHub Actions による安全な auto-merge を実装レベルで解説します。ここはセキュリティの落とし穴が多いので、token モデルとイベントトリガを特に丁寧に扱います。
この記事のルール:アクション名・出力・トークン挙動は GitHub 公式ドキュメントと
dependabot/fetch-metadataの README(2026年6月時点) に基づきます。auto-merge はセキュリティに直結するため、本番投入前に必ず公式の自動化ガイドで最新を確認してください。GITHUB_TOKEN以外の秘密はワークフローにハードコードしないでください。
1. 全体像:auto-merge は「予約」である
GitHub の auto-merge は「今すぐマージ」ではなく「必須チェックがすべて green になったらマージする」という予約です。だから auto-merge を有効化しても、テストが落ちればマージされません。この性質が安全性の核です。
Dependabot がPRを開く
└─▶ ワークフロー起動(actor が dependabot[bot] か検査)
└─▶ fetch-metadata で update-type 等を取得
└─▶ patch/minor なら gh pr merge --auto を実行(=予約)
└─▶ 必須チェック(テスト/型/lint/ビルド)が green
└─▶ 自動マージ ✅ (赤なら止まる ⛔)
前提として、リポジトリ設定で 「Allow auto-merge」 を有効化しておきます(Settings → General → Pull Requests)。
2. 最小実装:patch/minor を自動マージ
まずは動く最小形。pull_request イベントで起動し、ワークフロー側で書き込み権限を明示するのがポイントです。
# .github/workflows/dependabot-auto-merge.yml
name: Dependabot auto-merge
on: pull_request
permissions:
contents: write # マージに必要
pull-requests: write # PR操作に必要
jobs:
auto-merge:
runs-on: ubuntu-latest
# Dependabot 以外のPRでは何もしない(必須のガード)
if: github.actor == 'dependabot[bot]'
steps:
- name: Fetch Dependabot metadata
id: meta
uses: dependabot/fetch-metadata@v3
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Enable auto-merge for patch & minor
if: |
steps.meta.outputs.update-type == 'version-update:semver-patch' ||
steps.meta.outputs.update-type == 'version-update:semver-minor'
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3つの要点:
if: github.actor == 'dependabot[bot]'— Dependabot 以外のPRで動かさないガード。これを省くと第三者のPRにも反応して危険です。permissions:の明示 — Dependabot がトリガするpull_requestワークフローのGITHUB_TOKENは既定で読み取り専用。auto-merge にはcontents: writeとpull-requests: writeを明示的に与えます(後述)。update-typeでの条件分岐 —version-update:semver-patch/semver-minorのみ。major(semver-major)は意図的に除外し、人間に回します。
3. token モデル:ここがセキュリティの肝
auto-merge で事故る大半はトークンの理解不足です。公式の挙動を正確に押さえます。
- Dependabot がトリガする
pull_requestワークフローのGITHUB_TOKENは、既定で読み取り専用。そして通常の Actions シークレットにアクセスできません。これは侵害された依存が、CI 経由で秘密情報を盗み出すのを防ぐための設計です。 - 書き込みが必要なら、ワークフロー内で
permissions:を宣言して必要な範囲だけ昇格します(Dependabot のpull_requestイベントでは、ワークフローで宣言した権限が尊重されます)。 - ワークフローで秘密が必要な場合(例:プライベートリソースへアクセスするテスト)は、Dependabot シークレットストア(Settings → Secrets and variables → Dependabot)に置きます。Actions シークレットとは別物です。
覚え方:「Dependabot のPRで動く CI は、初期状態が読み取り専用 & 秘密なし」。だから auto-merge は
permissionsの明示が要り、秘密は Dependabot 専用ストアに置く。この2点を外すと「権限がない」「シークレットが空」で詰まります。
3.1 pull_request か pull_request_target か
dependabot/fetch-metadata の README には pull_request_target を使う例もありますが、安全側の既定は pull_request です。理由:
pull_request_targetは、ベースリポジトリの文脈で読み書き可能なトークンを持って動く。ここでPRのコード(=更新された依存を含む)をactions/checkoutして実行すると、侵害された依存が write 権限つきトークンや秘密に触れる経路ができます。- 一方、メタデータ取得 +
gh pr merge --auto(=コードを実行しない操作)だけなら、pull_request+ 明示的permissionsで十分に目的を達成でき、より安全です。
結論:ビルドや任意コード実行を伴わない auto-merge は pull_request を使う。 どうしても pull_request_target が必要なら、PR の head を checkout して実行しないこと、信頼境界を理解した上で使うこと。
マージキューを使う場合:組み込みの
GITHUB_TOKENではキューにPRを追加できません。PAT か GitHub App トークンでワークフローを認証する必要があります(公式注記)。
4. fetch-metadata の全出力で「繊細な方針」を作る
dependabot/fetch-metadata@v3 は14の出力を持ちます。これを使うと「patch/minor だけ」より繊細な自動マージ方針を組めます。
| 出力 | 用途の例 |
|---|---|
update-type | version-update:semver-patch/minor/major で粒度判定 |
dependency-type | direct:production / direct:development / indirect |
dependency-names | 特定パッケージ(例 rails)に限定 |
dependency-group | グループPR(groups設定)かどうかで分岐 |
package-ecosystem | エコシステム別ポリシー(github-actions は自動など) |
directory | モノレポのディレクトリ別ポリシー |
previous-version / new-version | バージョン差分でログ・判断 |
compatibility-score | 互換スコアでしきい値判定 |
alert-state / ghsa-id / cvss | セキュリティ更新を別扱い |
maintainer-changes | メンテナ変更があれば人間レビューに回す |
target-branch | 対象ブランチ別ポリシー |
updated-dependencies-json | 機械処理用の生データ |
4.1 実戦例:開発依存はminorまで、本番依存はpatchのみ自動
- name: Auto-merge policy
# 開発依存は patch/minor を自動、本番の direct 依存は patch のみ自動
if: |
(steps.meta.outputs.dependency-type == 'direct:development' &&
(steps.meta.outputs.update-type == 'version-update:semver-patch' ||
steps.meta.outputs.update-type == 'version-update:semver-minor')) ||
(steps.meta.outputs.dependency-type == 'direct:production' &&
steps.meta.outputs.update-type == 'version-update:semver-patch')
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
設計思想:本番に近いほど慎重に。direct:production の minor は人間レビュー、direct:development(テスト・ビルドツール)はもう少し緩める——という「リスクに比例した自動化」です。
4.2 メンテナ交代は必ず人間が見る
- name: Flag maintainer changes for human review
if: steps.meta.outputs.maintainer-changes == 'true'
run: gh pr comment "$PR_URL" --body "⚠️ メンテナ変更あり。サプライチェーン観点で人間レビュー必須。"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
メンテナの交代は、依存乗っ取り(hijack)の兆候になり得ます。maintainer-changes を見て自動マージから除外し、人間の目を入れるのは安価で効果的な防御です。
5. 安全弁を作る:必須チェック × ブランチ保護
auto-merge は「green ならマージ」。つまり**「何を green の条件にするか」が安全性そのもの**です。安全弁がない auto-merge は、ただのロシアンルーレットです。
5.1 Dependabot PR でも本物の CI を回す
# .github/workflows/ci.yml(Dependabot PR でも走る通常CI)
name: CI
on: pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build
注意:このCIは更新後の依存を
npm ciで入れて実行します。pull_requestで動く Dependabot のCIは読み取り専用トークン・秘密なしなので、万一悪性依存が紛れても被害を最小化できます。秘密が必要な統合テストを Dependabot PR で走らせない設計にすると、より堅牢です。
5.2 ブランチ保護で必須化する
main のブランチ保護(または Rulesets)で次を設定:
- Require status checks to pass before merging に
lint/typecheck/test/buildを必須登録。 - Require branches to be up to date before merging(任意。
rebase-strategyと相談)。 - これで
gh pr merge --autoは必須チェックが全部 green になるまでマージしません=安全弁が効く。
「auto-merge を入れる前に、まず信頼できる必須チェックを用意する」——順序を逆にしないでください。
6. グループPR・cooldown との併用
設定完全ガイドで作った groups / cooldown と auto-merge は綺麗に噛み合います。
- groups で patch/minor を1PRに束ね → そのグループPRを auto-merge:レビュー対象が「major と中身のある更新」だけに減ります。
dependency-group出力でグループPRを判定できます。 - cooldown で出たての版を寝かせる → 寝かせ終わって出てきたものを auto-merge:回帰リスクを下げてから自動取り込み。
- name: Auto-merge grouped patch/minor PRs
if: |
steps.meta.outputs.dependency-group != '' &&
steps.meta.outputs.update-type != 'version-update:semver-major'
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
(--squash でグループPRの履歴を1コミットに畳む、など運用に合わせて選択。)
7. アンチパターン集
- ❌
if: github.actorガードなし → 第三者PRに反応。必須ガードを必ず入れる。 - ❌ major も auto-merge → 破壊的変更を無人で本番へ。patch/minor 限定が鉄則。
- ❌ 必須チェック未設定で auto-merge → 安全弁がない。ブランチ保護とセット。
- ❌
pull_request_targetでPRコードを checkout & 実行 → write トークン/秘密が悪性依存に触れる経路。コード実行を伴わないならpull_request。 - ❌ Actions シークレットに依存 → Dependabot のCIは触れない。Dependabot シークレットストアを使う。
- ❌
permissionsを全体でwrite-all→ 最小権限違反。contents/pull-requestsだけに絞る。
8. FAQ
Q. auto-merge したのにマージされません。
A. --auto は「必須チェックが green になったら」マージします。チェックが pending/失敗、または「Allow auto-merge」やブランチ保護の必須チェックが未設定だと進みません。
Q. Resource not accessible by integration エラーが出ます。
A. Dependabot の pull_request ワークフローは既定で読み取り専用です。ワークフローに permissions: { contents: write, pull-requests: write } を明示してください。
Q. major も含めて全部自動にしたいのですが。
A. 推奨しません。破壊的変更を無人で取り込むリスクに見合いません。major は fetch-metadata の update-type で除外し、人間レビューに回してください。
Q. マージキューを使っています。
A. 組み込み GITHUB_TOKEN ではキューに追加できないため、PAT か GitHub App トークンでワークフローを認証してください。
Q. セキュリティ更新も auto-merge してよいですか?
A. CI(特にテスト)が十分なら patch のセキュリティ更新は自動マージの効果が大きいです。ただし alert-state / cvss を見て重大なものは人間が確認する方針も検討してください。脆弱性対応の全体像はアラート・セキュリティ更新ガイドへ。