Skip to content

dependabot-rollup: add opt-in approve and auto-merge for individually safe updates #36595

Description

Context

PR #36589 added the assign-prs skill. Its first revision also classified, approved and merged individually safe Dependabot PRs. That workstream was removed in review — assign-prs is now assignment-only, and dependency updates belong to dependabot-rollup.

dependabot-rollup today combines compatible updates into a rollup branch and opens a draft PR, explicitly leaving the original PRs untouched. This issue tracks adding the removed capability there instead, as an opt-in: approve and merge Dependabot PRs that are individually safe, without building a rollup.

This is deliberately conservative — the cost of a wrong merge is far higher than the cost of leaving a PR for a human.

Safety conditions

A PR is safe only when all of these hold. Default to unsafe.

  1. Author is Dependabot. The two APIs spell this differently: search/issues returns dependabot[bot], gh pr view --json author returns app/dependabot. Comparing the gh pr view value against dependabot[bot] marks every Dependabot PR unsafe and yields an empty safe list — a bug that looks like a conservative result. Match either spelling.
  2. Patch or minor only. Parse bump <dep> from <version> to <version>, stripping any chore(deps): / chore(deps-dev): prefix. Target major must equal source major. Exclude anything unparseable rather than guessing.
  3. Non-empty diff. changedFiles > 0. A bump followed by a corrective commit can net to zero changed files against the base, which passes every other rule here — including "no workflow files touched", trivially true when no files are touched. Close such a PR instead; Dependabot re-raises it if it still applies.
  4. No workflow files touched. Anything under .github/workflows/** is out of scope regardless of semver: it alters CI execution and is a supply-chain surface.
  5. Every check affirmatively passed. See below — this is the subtle one.
  6. Cleanly mergeable. mergeable == MERGEABLE. Exclude CONFLICTING and DIRTY. UNKNOWN means GitHub hasn't finished computing merge state: re-poll once, then exclude.

The check-verification trap

Credit to Paolo Aliprandi (@paolo-aliprandi), who caught this in review of #36589 (comment).

The original rule was a negative list: reject any entry in statusCheckRollup whose conclusion is FAILURE, TIMED_OUT, CANCELLED or ACTION_REQUIRED. That does not establish that anything passed:

  • an empty statusCheckRollup satisfies it vacuously;
  • a rollup containing only neutral or skipped conclusions also satisfies it.

Once the skill adds its own approval, gh pr merge --auto will then merge as soon as nothing blocks — so a PR with no checks at all is the easiest one to auto-merge, which is exactly backwards.

Any implementation must instead:

  • require a non-empty rollup;
  • affirmatively verify that every relevant check concluded SUCCESS;
  • treat neutral/skipped as unproven, not passing;
  • treat still-running checks as not-yet-safe and re-check later rather than merging optimistically;
  • re-verify immediately before merging, since status changes between planning and execution.

Note that mergeStateStatus == BLOCKED on its own is expected and is not a disqualifier — it usually means only that the required approval hasn't been given yet, which is the approval being added.

Guardrails to carry over

  • Dry-run and explicit approval before approving or merging anything.
  • Never approve or merge a PR not authored by Dependabot.
  • Never merge a semver-major update, or any PR touching .github/workflows/**.
  • Never bypass branch protection or use an administrator merge override.
  • Never merge with a failing, cancelled, timed-out, or still-running required check.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions