-
-
Notifications
You must be signed in to change notification settings - Fork 0
143 lines (130 loc) · 5.92 KB
/
Copy pathdependabot-automerge.yml
File metadata and controls
143 lines (130 loc) · 5.92 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
132
133
134
135
136
137
138
139
140
141
142
143
# 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]
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
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
is_patch_or_minor=false
is_high_or_critical=false
[ -n "$GHSA_ID" ] && is_security=true
case "$UPDATE_TYPE" in
version-update:semver-patch|version-update:semver-minor)
is_patch_or_minor=true ;;
esac
# Dependabot adds severity labels like "severity: high",
# "severity: critical". Look for those in the PR labels JSON.
if echo "$PR_LABELS" | grep -qiE '"(severity: (high|critical))"'; then
is_high_or_critical=true
fi
if $is_security && $is_patch_or_minor && ! $is_high_or_critical; then
echo "action=automerge" >> "$GITHUB_OUTPUT"
else
echo "action=skip" >> "$GITHUB_OUTPUT"
fi
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"