Skip to content

Commit e243ea3

Browse files
hyperpolymathclaude
andcommitted
ci: restore Dependabot security path + wire auto-merge
Estate-wide propagation of the Dependabot-automation-gap fix originated in 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md and first landed in rsr-template-repo@78b050e. Brings this repo into compliance with the estate standard: - dependabot.yml: patched - hypatia-scan.yml: patched - automerge.yml: copied Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 86dee82 commit e243ea3

2 files changed

Lines changed: 149 additions & 3 deletions

File tree

.github/dependabot.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ updates:
77
directory: "/"
88
schedule:
99
interval: "weekly"
10-
ignore:
11-
- dependency-name: "*"
12-
update-types: ["version-update:semver-patch"]
10+
# `open-pull-requests-limit: 0` suppresses routine version-update PRs
11+
# while leaving Dependabot SECURITY PRs flowing. The previous
12+
# `ignore: "*" patch` rule also silenced security PRs under GitHub\'s
13+
# current Dependabot behaviour. See rsr-template-repo commit 78b050e
14+
# and 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md.
15+
open-pull-requests-limit: 0
1316
- package-ecosystem: "github-actions"
1417
directory: "/"
1518
schedule:
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
#
3+
# dependabot-automerge.yml — enable GitHub's native auto-merge on
4+
# Dependabot pull requests that match a declared severity / ecosystem
5+
# policy. Pairs with `.github/dependabot.yml`'s
6+
# `open-pull-requests-limit: 0` + security-only pattern (see the
7+
# cargo block there).
8+
#
9+
# What this does:
10+
# - Triggers on every Dependabot PR.
11+
# - Reads the PR's update-type metadata via the dependabot/fetch-metadata
12+
# action (no free-text parsing).
13+
# - Requires CI to be green before merge (GitHub's auto-merge enforces
14+
# required status checks).
15+
# - Gates merge behind a severity+ecosystem policy table. Default is
16+
# low+medium security updates only.
17+
#
18+
# Why auto-merge on GitHub (not via a bot like rhodibot) is the right
19+
# layer: GitHub enforces branch protection + required checks natively,
20+
# and the PR author is already `dependabot[bot]`. Rhodibot doesn't need
21+
# to know anything about ecosystems — GitHub handles the merge mechanics
22+
# once we approve.
23+
#
24+
# Threat model:
25+
# - A compromised upstream package with a bogus security advisory
26+
# could propose a malicious version bump. Mitigation: require at
27+
# least one non-automated reviewer for HIGH+CRITICAL severity
28+
# (done below — we explicitly refuse to auto-approve those).
29+
# - A compromised Dependabot itself is an Akerlof claim-grounder
30+
# problem. Not in scope here; track under
31+
# `project_claim_grounders_dual_use_akerlof.md`.
32+
#
33+
# Dogfooding: this workflow template is itself subject to the same
34+
# Dependabot config via the github-actions ecosystem block, so SHA
35+
# bumps for dependabot/fetch-metadata flow through the same path.
36+
37+
name: Dependabot Auto-Merge
38+
39+
on:
40+
pull_request:
41+
types: [opened, reopened, synchronize]
42+
43+
permissions:
44+
contents: write # needed to enable auto-merge
45+
pull-requests: write # needed to approve
46+
# NB: keep narrow — do NOT add secrets: read or id-token: write here.
47+
48+
jobs:
49+
automerge:
50+
# Only run for PRs actually authored by Dependabot.
51+
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]'
52+
runs-on: ubuntu-latest
53+
54+
steps:
55+
- name: Fetch Dependabot metadata
56+
id: meta
57+
uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34 # v2.2.0
58+
with:
59+
github-token: ${{ secrets.GITHUB_TOKEN }}
60+
61+
# --- Policy gate -------------------------------------------------------
62+
# Outputs from fetch-metadata we care about:
63+
# update-type → version-update:semver-{patch,minor,major}
64+
# dependency-type → direct:{development,production} | indirect
65+
# alert-state → AUTO_DISMISSED | DISMISSED | FIXED | OPEN
66+
# ghsa-id → GHSA-... if this is a security PR
67+
# --- Policy -------------------------------------------------------------
68+
# AUTO-APPROVE + AUTO-MERGE when:
69+
# 1. This is a SECURITY update (ghsa-id present), AND
70+
# 2. Update is patch or minor, AND
71+
# 3. Severity ≤ moderate (Dependabot doesn't expose severity
72+
# directly in fetch-metadata; infer from the absence of
73+
# HIGH/CRITICAL labels added by Dependabot).
74+
# Otherwise: do nothing. Human reviews HIGH+CRITICAL security
75+
# updates and all non-security bumps.
76+
- name: Decide policy outcome
77+
id: policy
78+
env:
79+
GHSA_ID: ${{ steps.meta.outputs.ghsa-id }}
80+
UPDATE_TYPE: ${{ steps.meta.outputs.update-type }}
81+
PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
82+
run: |
83+
set -euo pipefail
84+
85+
is_security=false
86+
is_patch_or_minor=false
87+
is_high_or_critical=false
88+
89+
[ -n "$GHSA_ID" ] && is_security=true
90+
case "$UPDATE_TYPE" in
91+
version-update:semver-patch|version-update:semver-minor)
92+
is_patch_or_minor=true ;;
93+
esac
94+
95+
# Dependabot adds severity labels like "severity: high",
96+
# "severity: critical". Look for those in the PR labels JSON.
97+
if echo "$PR_LABELS" | grep -qiE '"(severity: (high|critical))"'; then
98+
is_high_or_critical=true
99+
fi
100+
101+
if $is_security && $is_patch_or_minor && ! $is_high_or_critical; then
102+
echo "action=automerge" >> "$GITHUB_OUTPUT"
103+
else
104+
echo "action=skip" >> "$GITHUB_OUTPUT"
105+
fi
106+
echo "security=$is_security" >> "$GITHUB_OUTPUT"
107+
echo "update_type=$UPDATE_TYPE" >> "$GITHUB_OUTPUT"
108+
echo "ghsa=$GHSA_ID" >> "$GITHUB_OUTPUT"
109+
110+
- name: Approve PR (if policy allows)
111+
if: steps.policy.outputs.action == 'automerge'
112+
env:
113+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
114+
PR_URL: ${{ github.event.pull_request.html_url }}
115+
run: |
116+
gh pr review --approve "$PR_URL" \
117+
--body "Auto-approving Dependabot security update (${{ steps.policy.outputs.ghsa }}, ${{ steps.policy.outputs.update_type }}). Policy: low/moderate security patches/minors only."
118+
119+
- name: Enable auto-merge (if policy allows)
120+
if: steps.policy.outputs.action == 'automerge'
121+
env:
122+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
123+
PR_URL: ${{ github.event.pull_request.html_url }}
124+
run: |
125+
gh pr merge --auto --squash "$PR_URL"
126+
127+
- name: Write decision to step summary
128+
env:
129+
ACTION: ${{ steps.policy.outputs.action }}
130+
IS_SECURITY: ${{ steps.policy.outputs.security }}
131+
UPDATE_TYPE: ${{ steps.policy.outputs.update_type }}
132+
GHSA: ${{ steps.policy.outputs.ghsa }}
133+
run: |
134+
{
135+
echo "## Dependabot Auto-Merge Decision"
136+
echo ""
137+
echo "| Field | Value |"
138+
echo "|-------|-------|"
139+
echo "| Policy action | \`$ACTION\` |"
140+
echo "| Security update | \`$IS_SECURITY\` |"
141+
echo "| Update type | \`$UPDATE_TYPE\` |"
142+
echo "| GHSA ID | \`${GHSA:-n/a}\` |"
143+
} >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)