From efd06a38b29a75eb91bdfb3965f61ce01e6fdcc5 Mon Sep 17 00:00:00 2001 From: WhiteMuush Date: Tue, 4 Aug 2026 19:32:23 +0200 Subject: [PATCH] ci(deps): group, throttle and auto-merge Dependabot updates Dependabot opened about three pull requests every week: the npm production and development groups, plus one per GitHub Action since that ecosystem had no groups block at all. Regroup npm by semver impact instead of prod/dev, so patches can flow unattended while minors and majors are held for review ahead of a release tag. Group the actions ecosystem. Add the docker ecosystem, which was missing entirely and left the node base image unwatched. Groups default to applies-to version-updates, so a single advisory touching several packages still opened one pull request per package, bypassing both the schedule and the open pull request limit. Each ecosystem now carries a mirrored security-updates group. Add a 7 day cooldown so no release is adopted inside the window where a compromised package is usually caught and yanked. Cooldown covers version updates only and never delays a security fix. Auto-merge patch bumps once the required ci check passes. That check aggregates quality, test, build, integration and e2e, so the merge waits on the full suite. Also run the four workflows on develop. They were scoped to main only, which left the integration branch with no CI at all and deferred every regression to a 60 commit promotion diff. --- .github/dependabot.yml | 65 +++++++++++++++++++--- .github/workflows/ci.yml | 4 +- .github/workflows/codeql.yml | 4 +- .github/workflows/compliance.yml | 2 +- .github/workflows/dependabot-automerge.yml | 42 ++++++++++++++ .github/workflows/security.yml | 4 +- 6 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/dependabot-automerge.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5c48b15..49779a2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,8 +3,15 @@ updates: # Application dependencies. - package-ecosystem: npm directory: "/" + # Monthly only throttles routine version bumps. Security updates ignore the + # schedule and still open as soon as an advisory lands. schedule: - interval: weekly + interval: monthly + # Never adopt a release younger than a week. Compromised packages are + # typically yanked within 72 hours, so this skips the malicious window. + # Cooldown covers version updates only, security updates are never delayed. + cooldown: + default-days: 7 open-pull-requests-limit: 10 # Frozen majors enforced by .githooks/lib/check-frozen-deps.mjs. Ignore # major updates here so Dependabot does not open PRs that CI will reject. @@ -19,14 +26,58 @@ updates: update-types: ["version-update:semver-major"] - dependency-name: "eslint" update-types: ["version-update:semver-major"] + # Split by semver impact, not by prod/dev. Patches are safe enough to flow + # continuously; minors and majors are held for review so the dependency + # state is known when a release tag is cut. + commit-message: + prefix: "build" + prefix-development: "chore" + include: scope groups: - production: - dependency-type: production - development: - dependency-type: development + npm-patch: + patterns: ["*"] + update-types: ["patch"] + npm-risky: + patterns: ["*"] + update-types: ["minor", "major"] + # Groups default to applies-to version-updates. Without this block a + # single advisory touching N packages opens N separate pull requests, + # bypassing the schedule and the open pull request limit. + npm-security: + applies-to: security-updates + patterns: ["*"] - # The GitHub Actions used by the workflows above. + # The GitHub Actions used by the workflows above. Grouped so a bump does not + # open one pull request per action. - package-ecosystem: github-actions directory: "/" schedule: - interval: weekly + interval: monthly + cooldown: + default-days: 7 + commit-message: + prefix: "ci" + include: scope + groups: + actions: + patterns: ["*"] + actions-security: + applies-to: security-updates + patterns: ["*"] + + # Base images. Nothing watched these before, so node and postgres drifted. + - package-ecosystem: docker + directory: "/" + schedule: + interval: monthly + cooldown: + default-days: 7 + commit-message: + prefix: "build" + include: scope + groups: + docker: + patterns: ["*"] + docker-security: + applies-to: security-updates + patterns: ["*"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79f7f93..4aaa13e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [main] + branches: [main, develop] pull_request: - branches: [main] + branches: [main, develop] # Least privilege by default for every job in this workflow. permissions: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 23bcaa5..7133726 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,9 +2,9 @@ name: CodeQL on: push: - branches: [main] + branches: [main, develop] pull_request: - branches: [main] + branches: [main, develop] schedule: # Weekly deep scan, Monday 03:27 UTC. - cron: "27 3 * * 1" diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 601f88c..84a1cc5 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -2,7 +2,7 @@ name: Compliance on: pull_request: - branches: [main] + branches: [main, develop] permissions: contents: read diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml new file mode 100644 index 0000000..2b7670c --- /dev/null +++ b/.github/workflows/dependabot-automerge.yml @@ -0,0 +1,42 @@ +name: Dependabot auto-merge + +# Patch bumps are merged without human review, but only after two independent +# gates: the dependabot.yml cooldown means the release is at least 7 days old, +# and --auto holds the merge until the required "ci" check passes. The "ci" job +# aggregates quality, test, build, integration and e2e, so nothing slips in on a +# partial run. Minor and major bumps stay manual by design. + +on: pull_request + +# Least privilege by default for every job in this workflow. +permissions: + contents: read + +concurrency: + group: dependabot-automerge-${{ github.ref }} + cancel-in-progress: true + +jobs: + automerge: + name: Auto-merge patch updates + runs-on: ubuntu-latest + timeout-minutes: 5 + if: github.actor == 'dependabot[bot]' + permissions: + contents: write + pull-requests: write + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + # A grouped pull request reports the highest bump it contains, so the + # npm-patch group only ever resolves to semver-patch here. + - name: Enable auto-merge for patch updates + if: steps.metadata.outputs.update-type == 'version-update:semver-patch' + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a86f48b..323a7d7 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -2,9 +2,9 @@ name: Security on: push: - branches: [main] + branches: [main, develop] pull_request: - branches: [main] + branches: [main, develop] schedule: # Weekly, Monday 04:27 UTC, to catch newly disclosed advisories. - cron: "27 4 * * 1"