-
-
Notifications
You must be signed in to change notification settings - Fork 0
131 lines (128 loc) · 6.05 KB
/
Copy pathdependabot-automerge.yml
File metadata and controls
131 lines (128 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# SPDX-License-Identifier: MPL-2.0
#
# dependabot-automerge.yml — enable GitHub's native auto-merge on
# Dependabot pull requests that match a declared severity / ecosystem
# policy. Pairs with `.github/dependabot.yml`'s
# `open-pull-requests-limit: 0` + security-only pattern (see the
# cargo block there).
#
# What this does:
# - Triggers on every Dependabot PR.
# - Reads the PR's update-type metadata via the dependabot/fetch-metadata
# action (no free-text parsing).
# - Requires CI to be green before merge (GitHub's auto-merge enforces
# required status checks).
# - Gates merge behind a severity+ecosystem policy table. Default is
# low+medium security updates only.
#
# Why auto-merge on GitHub (not via a bot like rhodibot) is the right
# layer: GitHub enforces branch protection + required checks natively,
# and the PR author is already `dependabot[bot]`. Rhodibot doesn't need
# to know anything about ecosystems — GitHub handles the merge mechanics
# once we approve.
#
# Threat model:
# - A compromised upstream package with a bogus security advisory
# could propose a malicious version bump. Mitigation: require at
# least one non-automated reviewer for HIGH+CRITICAL severity
# (done below — we explicitly refuse to auto-approve those).
# - A compromised Dependabot itself is an Akerlof claim-grounder
# problem. Not in scope here; track under
# `project_claim_grounders_dual_use_akerlof.md`.
#
# Dogfooding: this workflow template is itself subject to the same
# Dependabot config via the github-actions ecosystem block, so SHA
# bumps for dependabot/fetch-metadata flow through the same path.
name: Dependabot Auto-Merge
on:
pull_request:
types: [opened, reopened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: write # needed to enable auto-merge
pull-requests: write # needed to approve
# NB: keep narrow — do NOT add secrets: read or id-token: write here.
jobs:
automerge:
# Only run for PRs actually authored by Dependabot.
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Fetch Dependabot metadata
id: meta
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# --- Policy gate -------------------------------------------------------
# Outputs from fetch-metadata we care about:
# update-type → version-update:semver-{patch,minor,major}
# dependency-type → direct:{development,production} | indirect
# alert-state → AUTO_DISMISSED | DISMISSED | FIXED | OPEN
# ghsa-id → GHSA-... if this is a security PR
# --- Policy -------------------------------------------------------------
# AUTO-APPROVE + AUTO-MERGE when:
# 1. This is a SECURITY update (ghsa-id present), AND
# 2. Update is patch or minor, AND
# 3. Severity ≤ moderate (Dependabot doesn't expose severity
# directly in fetch-metadata; infer from the absence of
# HIGH/CRITICAL labels added by Dependabot).
# Otherwise: do nothing. Human reviews HIGH+CRITICAL security
# updates and all non-security bumps.
- name: Decide policy outcome
id: policy
env:
GHSA_ID: ${{ steps.meta.outputs.ghsa-id }}
UPDATE_TYPE: ${{ steps.meta.outputs.update-type }}
PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
run: |
set -euo pipefail
is_security=false
[ -n "$GHSA_ID" ] && is_security=true
# Owner policy (deliberate: velocity over caution). Auto-merge EVERY
# Dependabot update — patch, minor AND major, security or routine.
# Safe because GitHub's auto-merge only COMPLETES once the required
# checks (secret-scanner, codeql, hypatia-scan, openssf-compliance,
# build/test) are green: a bump that breaks fails CI and the PR stays
# OPEN with an email ("oi, it broke") instead of landing on a red
# main; a bump that passes lands within minutes with no chasing.
# This is preferred over making Dependabot a ruleset BYPASS actor,
# which would let bumps skip those very checks (no gate, no signal).
echo "action=automerge" >> "$GITHUB_OUTPUT"
echo "security=$is_security" >> "$GITHUB_OUTPUT"
echo "update_type=$UPDATE_TYPE" >> "$GITHUB_OUTPUT"
echo "ghsa=$GHSA_ID" >> "$GITHUB_OUTPUT"
- name: Approve PR (if policy allows)
if: steps.policy.outputs.action == 'automerge'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr review --approve "$PR_URL" \
--body "Auto-approving Dependabot security update (${{ steps.policy.outputs.ghsa }}, ${{ steps.policy.outputs.update_type }}). Policy: low/moderate security patches/minors only."
- name: Enable auto-merge (if policy allows)
if: steps.policy.outputs.action == 'automerge'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr merge --auto --squash "$PR_URL"
- name: Write decision to step summary
env:
ACTION: ${{ steps.policy.outputs.action }}
IS_SECURITY: ${{ steps.policy.outputs.security }}
UPDATE_TYPE: ${{ steps.policy.outputs.update_type }}
GHSA: ${{ steps.policy.outputs.ghsa }}
run: |
{
echo "## Dependabot Auto-Merge Decision"
echo ""
echo "| Field | Value |"
echo "|-------|-------|"
echo "| Policy action | \`$ACTION\` |"
echo "| Security update | \`$IS_SECURITY\` |"
echo "| Update type | \`$UPDATE_TYPE\` |"
echo "| GHSA ID | \`${GHSA:-n/a}\` |"
} >> "$GITHUB_STEP_SUMMARY"