Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions workflow-templates/dependabot-auto-merge.properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Dependabot Auto-Merge",
"description": "Approves and auto-merges Dependabot PRs for patch and minor version updates once CI passes. Major-version bumps are left open for manual review. Requires can_approve_pull_request_reviews enabled for this repo.",
"iconName": "git-merge",
"categories": ["automation", "dependencies"]
}
71 changes: 40 additions & 31 deletions workflow-templates/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
name: Dependabot Auto-Merge

# Safely auto-merges Dependabot PRs after CI passes. Scope is narrow:
# - Only runs when github.actor == 'dependabot[bot]' (not spoofable;
# GitHub sets this from the authenticated user).
# - Only auto-merges patch + minor updates; major-version bumps are
# left open for manual review.
# - Uses pull_request_target so the BASE-branch workflow runs, not
# the PR branch's — a PR modifying this file cannot bypass itself.
# - Never executes PR code; the only action taken is `gh pr merge
# --auto`, which is a GitHub-side API call.
# Caller stub for the reusable `dependabot-auto-merge` workflow. Approves
# and auto-merges Dependabot PRs for patch and minor version updates once
# CI passes; major-version bumps are left open for manual review. This
# stub passes no `with:` inputs -- the reusable workflow declares no
# `inputs:` today, so every behavior (the dependabot[bot]-actor gate, the
# patch/minor scope, the squash-merge strategy) is governed entirely by
# its defaults. The actor gate in particular is NOT visible in this file
# -- it lives inside the reusable workflow itself; see
# smartwatermelon/github-workflows/.github/workflows/dependabot-auto-merge.yml
# to audit it directly.
#
# `gh pr review --approve` satisfies branch-protection rules that
# require review. `--auto` means the merge only happens after all
# status checks pass; failing CI leaves the PR open indefinitely.
# Requires `can_approve_pull_request_reviews: true` in this repo's Actions
# workflow permissions (Settings -> Actions -> General -> Workflow
# permissions) for the approval step to succeed. If unset, the approval
# degrades to a visible ::warning:: instead of blocking the merge outright
# (see smartwatermelon/github-workflows#87).
#
# Provisioned 2026-04-18 as part of the v2.0.1 / Dependabot rollout
# (Phase 5). See the playbook at
# smartwatermelon/github-workflows/docs/plans/2026-04-18-v2-rollout-playbook.md
# Do NOT add `secrets: inherit` here. This workflow needs no secrets
# beyond the ambient GITHUB_TOKEN it mints itself. `secrets: inherit`
# would hand every repo secret (deploy keys, CLAUDE_CODE_OAUTH_TOKEN,
# etc.) to a job evaluating externally-authored PR content under
# pull_request_target -- see the reusable workflow's own header comment
# and smartwatermelon/github-workflows#64 for the full reasoning.
#
# Do NOT add `actions/checkout` to this file either -- same reasoning,
# this file uses pull_request_target and the no-checkout property is
# its core safety invariant.
#
# Pinned to the floating `dependabot-auto-merge-v1` tag (not a fixed
# commit SHA), a deliberate, accepted tradeoff for this template -- not
# an oversight. This workflow runs under pull_request_target with
# contents:write / pull-requests:write, so a floating tag does put trust
# in whoever can push tags to smartwatermelon/github-workflows (today:
# repo owner only) to never move it to something malicious or broken.
# In exchange, bug fixes and hardening land fleet-wide automatically,
# matching how claude-blocking-review.yml@v3 already behaves -- the
# same tradeoff this fleet has already made and lived with for the
# review gate, extended here to the merge-automation workflow. Repos
# that want a stricter, audited pin instead of this default can repoint
# their own copy at `@dependabot-auto-merge-v1.0.0`.

on:
pull_request_target:
Expand All @@ -27,19 +50,5 @@ permissions:
pull-requests: write

jobs:
auto-merge:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- name: Fetch Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2

- name: Approve and enable auto-merge (patch/minor only)
if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr review --approve "$PR_URL"
gh pr merge --auto --squash --delete-branch "$PR_URL"
dependabot-auto-merge:
uses: smartwatermelon/github-workflows/.github/workflows/dependabot-auto-merge.yml@dependabot-auto-merge-v1