ci: auto-merge Dependabot PRs for bounded-risk groups - #30
Conversation
Enables GitHub's native auto-merge on the Dependabot PRs whose risk the grouping in .github/dependabot.yml already bounds: minor-and-patch, linting, testing, types, and the github-actions group. The workflow sets the flag; GitHub merges only after main's required checks pass. Gates on fetch-metadata's dependency-group output rather than update-type. update-type is documented as the highest semver change in the PR, with no stated behaviour for grouped PRs, so the group name is the claim that is actually specified. react and drizzle are excluded (coordinated majors), as is every ungrouped PR — that tier is the next/zod/pg-boss majors and the security updates, both of which want a human.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 27 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a GitHub Actions workflow that enables native squash auto-merge for selected Dependabot dependency groups after repository, actor, permission, and metadata checks. ChangesDependabot auto-merge
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/dependabot-auto-merge.yml:
- Line 37: Update the dependabot/fetch-metadata action reference in the workflow
to use the resolved commit SHA for the intended v3 release instead of the
mutable v3 tag, and add an inline version comment for readability.
- Around line 24-26: Move the contents and pull-requests write permissions from
the workflow-level configuration into the auto-merge job’s permissions block,
preserving both scopes and the existing job behavior. Use the jobs.auto-merge
definition as the target location and remove the top-level permissions block.
- Line 33: Update the condition in the workflow’s pull-request gate to use
github.event.pull_request.user.login for the author check instead of
github.actor, while preserving the existing repository equality check.
- Around line 39-61: Update the bounded-risk group condition in “Enable
auto-merge for bounded-risk groups” to exclude the “actions” dependency group,
or explicitly document and implement acceptance of the workflow-replacement
risk. Preserve auto-merge for the remaining approved groups.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 9ca715d5-187d-4598-b3c4-922ea16d74a4
📒 Files selected for processing (1)
.github/workflows/dependabot-auto-merge.yml
| name: Enable auto-merge | ||
| # The repository guard keeps this from running in forks, where the actor | ||
| # check alone could be satisfied by a branch named to impersonate the bot. | ||
| if: github.actor == 'dependabot[bot]' && github.repository == 'guarzo/authGD' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does GitHub recommend github.actor or github.event.pull_request.user.login to gate Dependabot-only workflow steps?
💡 Result:
Yes, GitHub recommends using github.event.pull_request.user.login rather than github.actor to gate Dependabot-only workflow steps [1][2][3]. Using github.actor is generally insecure for security-sensitive gating because it is susceptible to spoofing [1][4]. For example, an attacker can trigger certain events (such as @dependabot commands) that cause dependabot[bot] to appear as the github.actor on a pull request that they control [5]. In contrast, github.event.pull_request.user.login represents the immutable author of the pull request [1][3]. Checking this value ensures that the workflow is only operating on a pull request actually created by Dependabot [1][5]. Security best practices for workflow gating include: - Use github.event.pull_request.user.login == 'dependabot[bot]' to verify the source of the pull request [1][3]. - Treat github.actor as informational rather than a reliable trust boundary [4]. - When possible, use native GitHub features like environment protection rules with required reviewers instead of relying solely on workflow condition strings [4]. While some documentation mentions using github.actor for simple exclusions (e.g., if: github.actor!= 'dependabot[bot]') [6], security auditors and modern security guidelines emphasize that this is not a robust security control [1][4]. If your workflow requires suppressing bot-triggered reruns, it may be necessary to check both values or use more complex logic, but for identifying a "trusted" Dependabot-authored event, github.event.pull_request.user.login is the correct and recommended approach [7][5].
Citations:
- 1: https://sisaku-security.github.io/lint/docs/rules/botconditions/
- 2: mozilla/fx-private-relay@6319fe7
- 3: https://github.com/emdash-cms/emdash/blob/db2577795fa85a5866e3e637526a0c1ce60295bc/.github/workflows/dependabot-approve.yml
- 4: https://actsense.dev/vulnerabilities/spoofable_actor_condition/
- 5: security: guard bot filtering against dependabot confused deputy attacks github/gh-aw#29432
- 6: https://docs.github.com/en/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions
- 7: [BUG]:
bot-conditionsfalse positive whengithub.actoris used only to suppress follow-up bot reruns zizmorcore/zizmor#1914
🏁 Script executed:
#!/bin/bash
set -eu
file=".github/workflows/dependabot-auto-merge.yml"
if [ -f "$file" ]; then
cat -n "$file" | sed -n '1,90p'
else
echo "Missing $file"
fi
printf '\nWorkflow references:\n'
rg -n --hidden -S "dependabot-auto-merge|github\.actor|pull_request\.user\.login|dependabot\[bot\]" .github 2>/dev/null || true
printf '\nRepository status:\n'
git status --shortRepository: guarzo/authGD
Length of output: 3890
🌐 Web query:
site:docs.github.com GitHub Actions Dependabot pull_request.user.login github.actor workflow condition
💡 Result:
To identify if a GitHub Actions workflow was triggered by Dependabot, you can check the github.actor context, which will be set to 'dependabot[bot]' [1][2]. For workflow conditions (such as skipping a job or enabling specific logic), use an expression like the following in your workflow YAML file: if: github.actor!= 'dependabot[bot]' If you specifically need to verify that a pull request was opened by Dependabot, you can use the event payload: if: github.event.pull_request.user.login == 'dependabot[bot]' Key Considerations: - Default Behavior: Workflows triggered by Dependabot for events like pull_request are treated as if they originated from a fork [3][4]. This means they have a read-only GITHUB_TOKEN by default and do not have access to standard repository secrets [1][3]. - Permissions: You can override the default read-only permissions by explicitly defining the permissions key in your workflow, for example: permissions: pull-requests: write issues: write - Context Differences: While github.actor identifies the entity that triggered the workflow run, github.event.pull_request.user.login specifically checks the author of the pull request [1][5]. Using both in combination is common when you need to distinguish between Dependabot-initiated events and other actions [6].
Citations:
- 1: https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-on-actions
- 2: https://docs.github.com/en/enterprise-cloud@latest/code-security/reference/supply-chain-security/dependabot-on-actions
- 3: https://docs.github.com/en/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions
- 4: https://docs.github.com/en/enterprise-server@3.21/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions
- 5: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts
- 6: https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/automate-dependabot-with-actions
🌐 Web query:
site:docs.github.com github.actor pull_request user.login event payload Actions
💡 Result:
In GitHub Actions, github.actor and the user who triggered a pull_request event via the payload are distinct concepts with specific roles [1][2]. 1. github.actor github.actor is a built-in context property that identifies the username of the user who initiated the workflow run [1][2]. - If the workflow is a re-run, github.actor may differ from github.triggering_actor [1][2]. - Importantly, workflow re-runs always execute with the privileges of the original github.actor, regardless of which user triggered the re-run [1][2]. 2. Pull Request Event Payload (github.event) When a workflow is triggered by a pull_request event, you can access detailed information about the event through the github.event context, which contains the webhook payload [3][1]. The user who performed the action on the pull request (e.g., opened, closed, or synchronized it) is found within this payload [4][3]. - Location: The user information is typically located at github.event.sender.login (the user who performed the action) or github.event.pull_request.user.login (the author of the pull request) [3]. - Distinction: Unlike github.actor, which represents the person who "initiated" the workflow (often the person who pushed code or opened the PR), github.event.sender.login identifies the specific individual who triggered the webhook event (e.g., someone who commented on or labeled the PR) [3][1]. Summary Comparison - github.actor: The person who triggered the workflow run [1]. - github.event.sender.login: The person who performed the specific action (like pushing a commit or labeling) that sent the webhook event [3]. - github.event.pull_request.user.login: The author who originally created the pull request [3].
Citations:
- 1: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts
- 2: https://docs.github.com/en/enterprise-server@3.21/actions/reference/workflows-and-actions/contexts
- 3: https://docs.github.com/en/webhooks/webhook-events-and-payloads
- 4: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows
🌐 Web query:
zizmor bot-conditions actor context may be spoofable github.actor pull_request
💡 Result:
The zizmor tool's "bot-conditions" audit flags the use of github.actor (and related contexts like github.triggering_actor) as potentially spoofable when used to authorize privileged actions in GitHub Actions workflows [1][2][3]. The core issue is that github.actor does not represent the original author of a pull request; instead, it identifies the last actor to perform an action on the triggering context [1][4]. In the context of a pull_request event, an attacker can exploit this by creating a pull request and then using actions—such as rebasing or force-pushing (e.g., via @dependabot commands)—that cause a trusted bot to become the "last actor" [1][5][4]. Because the workflow's conditional check (e.g., if: github.actor == 'dependabot[bot]') relies on this spoofable field, the attacker can bypass the intended permission boundary and execute privileged code [1][5][6]. To remediate this, zizmor recommends using immutable, event-specific contexts that accurately reflect the pull request's author, such as github.event.pull_request.user.login [1][7][3]. Key points regarding the vulnerability: - Spoofable Contexts: zizmor identifies github.actor, github.triggering_actor, and github.event.pull_request.sender.login as contexts that can be spoofed in this manner [2][3]. - Exploitation: Attackers leverage "confused deputy" attacks where they manipulate the branch history or PR activity to associate a trusted bot's identity with the latest trigger event, tricking the workflow into believing the trusted bot initiated the action [5][4][6]. - Mitigation: Replace the spoofable actor check with a check against the PR author's login, which remains constant regardless of subsequent push or sync events [1][7]. Zizmor provides automatic fixes for this specific audit [1][8].
Citations:
- 1: https://docs.zizmor.sh/audits/
- 2: https://github.com/woodruffw/zizmor/blob/main/crates/zizmor/src/audit/bot_conditions.rs
- 3: https://sisaku-security.github.io/lint/docs/rules/botconditions/
- 4: https://yossarian.net/res/pub/hushcon-west-2025.pdf
- 5: security: guard bot filtering against dependabot confused deputy attacks github/gh-aw#29432
- 6: ci: auto-merge Dependabot PRs once CI is green prestomation/ha-home-keeper#132
- 7: https://github.com/zizmorcore/zizmor/blob/563b7b25/docs/audits.md
- 8: https://github.com/zizmorcore/zizmor/blob/main/docs/release-notes.md
🌐 Web query:
GitHub Actions Dependabot auto merge github.actor github.event.pull_request.user.login security
💡 Result:
Using github.actor to identify Dependabot in GitHub Actions workflows is considered insecure because it can be spoofed [1][2]. The github.actor context represents the account that triggered the specific workflow run, which can change if a user manually re-runs the workflow or pushes a follow-up commit to a Dependabot-created branch [3]. To securely identify Dependabot-created pull requests, you should instead use github.event.pull_request.user.login [1]. This value is immutable and remains set to dependabot[bot] regardless of who triggered the workflow or subsequently interacted with the pull request [1][3]. Best practices for securing Dependabot auto-merge workflows include: 1. Use immutable identifiers: Rely on github.event.pull_request.user.login == 'dependabot[bot]' [1][3]. For additional robustness, some organizations also verify the numeric ID github.event.pull_request.user.id == 49699333 [2]. 2. Avoid over-privileged permissions: By default, workflows triggered by Dependabot have read-only permissions [4][5]. Explicitly define the minimal permissions required (e.g., contents: write and pull-requests: write) at the job or workflow level rather than granting global access [6][7][8]. 3. Validate metadata: Use the dependabot/fetch-metadata action to confirm the update type (e.g., patch or minor) before proceeding [9][6][10]. Avoid auto-merging major updates, as these often contain breaking changes that require human verification [6][11]. 4. Respect branch protection: Use gh pr merge --auto, which does not perform an immediate merge but instructs GitHub to merge the pull request once all required status checks and branch protection rules have passed [2][6][10]. This ensures security checks are not bypassed [6][11]. 5. Use dedicated tokens: If you need to perform actions that the default GITHUB_TOKEN cannot (like triggering other workflows), consider using a GitHub App token instead of a long-lived personal access token [8].
Citations:
- 1: https://sisaku-security.github.io/lint/docs/rules/botconditions/
- 2: https://github.com/GoogleCloudPlatform/race-condition/blob/e9035e41a14e456126da0379aaf9f2a9cbe07583/.github/workflows/dependabot-auto-merge.yml
- 3: timpugh/lambda-powertools-reference@f85cef3
- 4: https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-on-actions
- 5: https://docs.github.com/en/enterprise-cloud@latest/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions
- 6: https://tomodahinata.com/en/blog/dependabot-auto-merge-github-actions-automation-guide
- 7: https://github.com/nais/doc/blob/main/docs/build/how-to/dependabot-auto-merge.md
- 8: https://github.com/navikt/automerge-dependabot/blob/main/README.md
- 9: https://github.com/amd/gaia/blob/8b2a6f8cea491316ed594b5dcc59439fc8b39579/.github/workflows/dependabot-automerge.yml
- 10: https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/automate-dependabot-with-actions
- 11: https://gist.github.com/ricog/bdef83b2bf341ecb96bb993f045d60ee
Gate on the pull request author
Replace github.actor == 'dependabot[bot]' with github.event.pull_request.user.login == 'dependabot[bot]'. github.actor can reflect a later event actor and is spoofable for privileged workflow conditions.
🧰 Tools
🪛 zizmor (1.28.0)
[error] 33-33: spoofable bot actor check (bot-conditions): actor context may be spoofable
(bot-conditions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/dependabot-auto-merge.yml at line 33, Update the condition
in the workflow’s pull-request gate to use github.event.pull_request.user.login
for the author check instead of github.actor, while preserving the existing
repository equality check.
Source: Linters/SAST tools
…om auto-merge Review feedback on #30. Pin dependabot/fetch-metadata to 25dd0e3 (v3.1.0) rather than the v3 moving tag. This departs from ci.yml's major-tag convention on purpose: this is the only job holding contents: write, so a repointed tag would run hostile code with write access to the default branch. Both refs resolve to the same commit today. Move permissions from workflow level to the job, so a job added later has to ask for the write token rather than inherit it. Drop the actions group from the auto-merge list. It edits the workflow files themselves, including this one — its own pinned action matches that group's * pattern. CI runs under the configuration being changed, so green says the new action did not break the build, not that it is the code its author published. A handful of PRs a year. Not applied: swapping github.actor for github.event.pull_request.user.login. That widens the gate rather than narrowing it — see the PR discussion.
|
Three of four applied. Verification: 1. Pin Both resolve to the same commit, so the pin costs nothing today. Now Worth noting this departs from 2. Move permissions to the job — applied. Functionally identical today (one job), but a job added later now has to ask for the write token rather than inherit it. 3. This one widens the gate rather than narrowing it, so I'd rather not take it without pushback. The two diverge when a human pushes a commit to a Dependabot branch. GitHub's documented auto-merge example uses 4. Drop I had described the The asymmetry that makes it different from the other groups: CI runs under the configuration being changed. For Auto-merged groups are now Two corrections to this PR's description while I'm here:
Both prerequisites in that Flags section are now resolved: the ruleset is |
Based on
main. Depends on #24 for the groups it names, but does not conflict with it — if this merges first the workflow simply never matches anything.What changed and why
One new file,
.github/workflows/dependabot-auto-merge.yml. It does not merge anything itself: it flips GitHub's native auto-merge flag, and GitHub merges only once main's required checks pass.Gating is on
fetch-metadata'sdependency-groupoutput rather thanupdate-type.update-typeis documented as "the highest semver change being made by this PR" with no stated behaviour for grouped PRs, so the group name is the claim that is actually specified. Verified againstaction.ymlon thev3tag —dependency-groupis a real output there, andgithub-tokennow defaults to${{ github.token }}, so it is omitted.Auto-merged:
minor-and-patch(restricted to minor/patch by its ownupdate-types),linting,testing,types, and theactionsgroup.Not auto-merged:
reactanddrizzle— coordinated majors, and a drizzle-orm/drizzle-kit skew surfaces atfly.toml'srelease_command. Nor any ungrouped PR, which is the next/zod/pg/pg-boss/jose/tsx/typescript major tier. Security updates are ungrouped by design and land there too: they should be merged fast, but by someone who has read the advisory.The action is pinned to the
v3major tag, matching howci.ymlpinsactions/*. It will keep itself current via theactionsgroup — which is itself on the auto-merge list.What CI cannot check
actionlint(not currently in CI) on the new file: clean, no output.npm run format:check->All matched files use Prettier code style!.The workflow's real behaviour cannot be exercised until a Dependabot PR opens, which will be Monday 06:00 UTC at the earliest. The first one is the test.
Deploy notes
None for the app. Two repository settings must be in place or this does not work — see Flags.
Flags
Two prerequisites are not yet met, and the second one is a live risk.
allow_auto_mergeis stillfalseon the repo, sogh pr merge --autowill error and this job will go red on every Dependabot PR until it is enabled. Settings > General > Pull Requests > "Allow auto-merge".The ruleset on
main(id 20330845) is"enforcement": "disabled"and contains only apull_requestrule — norequired_status_checksrule at all. Auto-merge waits on required checks only; with none defined it merges the moment the flag is set, before CI reports. Until that ruleset gains required checks and is set to active, this workflow is strictly worse than not having it.Correction to earlier advice in this thread. I recommended requiring unit tests but leaving e2e advisory. That is not possible as CI is currently written:
ci.ymlhas one job,test/ "Tests (unit, then e2e)", which runs both serially — the serialization the original brief asked for. They are a single check run. Requiring it requires e2e too. The three check names to require are exactly:Typecheck, lint & formatNext buildTests (unit, then e2e)Splitting e2e into its own job would be a separate change, and would need the two jobs kept off the shared database.
Remaining gap either way:
docker buildis not in CI, so a dependency that breaks the image build auto-merges green. Mitigated by there being no CD workflow —.github/workflows/isci.ymlanduptime.ymlonly — so a bad bump sits onmainuntil someone runsfly deploy, rather than reaching production.Summary by CodeRabbit