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"