diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..f0b9e8c --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,45 @@ +name: dependabot-auto-merge +# Auto-merges low-risk Dependabot PRs once the required CI checks pass. +# Native auto-merge waits for the branch-protection checks on main (test + +# docker), so a bump only lands if the workflows still go green. Scope: +# - github-actions: all updates (CI-only, low blast radius). +# - npm / docker: minor + patch only — major bumps stay manual for review. +# +# Majors are excluded on purpose, and recent history shows why: the TypeScript +# 5.9 -> 7.0 bump broke the build outright (TS7016), and the Node 24 -> 25 +# base-image bump was declined for being a non-LTS release. Both needed a human. +# +# Merges with --merge rather than --squash to match this repo's history. +# +# NB: package-ecosystem is Dependabot's internal identifier, not the friendly +# name from dependabot.yml — npm reports as `npm_and_yarn` and Actions as +# `github_actions` (they match the dependabot// branch prefix). A +# literal `== 'npm'` would silently never match, which is exactly the trap the +# sibling random-mcp-server repo fell into: it tests `== 'pip'` while the real +# output there is `uv`, so its Python bumps never auto-merge. Hence startsWith. +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + auto-merge: + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v3 + + - name: Enable auto-merge for in-scope updates + if: >- + startsWith(steps.metadata.outputs.package-ecosystem, 'github') + || ( (steps.metadata.outputs.package-ecosystem == 'docker' + || startsWith(steps.metadata.outputs.package-ecosystem, 'npm')) + && (steps.metadata.outputs.update-type == 'version-update:semver-minor' + || steps.metadata.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 }} diff --git a/CLAUDE.md b/CLAUDE.md index 846716e..fca6bd2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,6 +53,15 @@ Run `gh issue list` for the current state. github-actions. `@types/*` and other minor/patch npm bumps are **grouped** into single PRs; majors stay individual so each gets its own review. Security updates are independent of this file and arrive regardless. +- **Low-risk Dependabot PRs auto-merge** via + `.github/workflows/dependabot-auto-merge.yml`: all github-actions updates, + plus npm/docker **minor and patch**. Majors always stay manual — the + TypeScript 5.9 → 7.0 bump broke the build and the Node 24 → 25 base image was + declined, and both needed a human. This relies on branch protection: `main` + requires the `test` and `docker` checks, which is what native auto-merge + waits for. Without required checks, auto-merge would land PRs *without* CI + gating them. `enforce_admins` is off, so direct version-bump pushes to `main` + still work. - **Transitive CVEs are pinned via `overrides`,** not by adding direct dependencies — see the `overrides` block in `package.json` (`js-yaml`, `qs`, `brace-expansion`). When a follow-up advisory lands for something already