Repository navigation
feat(workflows): add pr-automerge-dependabot reusable - #676
Conversation
Arms squash auto-merge on Dependabot PRs that bump only allowlisted GitHub Actions publishers (actions/*, github/*, anthropics/*) by a semver patch or minor, so GitHub merges once ci-status passes. Gates on author id 49699333, the github_actions ecosystem, every dependency name, every update type, and verified Dependabot authorship of every commit. Disarms a skipped PR armed on an earlier head. Never merges directly. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…abot Run the gate even when fetch-metadata fails, so a force-pushed PR that was armed earlier gets disarmed. Treat failed, empty or invalid metadata as a skip. Require the event sender to be Dependabot. Require every commit to be committed by web-flow with a signature verified as "valid", because an author id alone can be forged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 3m 46s —— View job Code review — PR #676
Scope: Findings1 inline finding posted on What I verified vs. author-claimedI statically traced the gate logic in No other correctness, test-coverage, or maintainability issues met the high-signal bar for this lane. |
|
Claude finished @kyle-sexton's task in 3m 39s —— View job Security review —
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 220a6a3b60
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
claude-security-review has reviewed this pull request through 1256592; a later push is reviewed from there. |
|
claude-review has reviewed this pull request through 1256592; a later push is reviewed from there. |
… used Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 31s —— View job Security review — PR #676 (incremental,
|
|
Claude finished @kyle-sexton's task in 3m 45s —— View job Code review — PR #676 (incremental, since
|
…warnings in the gate tests Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 49s —— View job Code review — PR #676 (incremental, since
|
|
Claude finished @kyle-sexton's task in 38s —— View job Security review — PR #676 (incremental,
|
…tract (#687) No related issue: follow-up registration for the ci-workflows v0.35.0 reusable reviewed on melodic-software/ci-workflows#676 ## Summary Approves the new ci-workflows `pr-automerge-dependabot.yml` reusable at v0.35.0 in `runner-policy` and adds a lockstep check so its `PUBLISHER_ALLOWLIST` constant cannot drift from `dependabot-policy` `autoMerge.publisherAllowlist`. Contract for hand review (`components/runner-policy/policy.json`, `approvedReusableWorkflowContracts`): ```json "melodic-software/ci-workflows/.github/workflows/pr-automerge-dependabot.yml@69e506b7c119517ef1dfc421479232b386b93a52": { "routing": "runner-input", "runnerInput": "runner", "allowedInputs": ["runner"], "allowedSecrets": {}, "allowedCallerPermissions": { "contents": "write", "pull-requests": "write" } } ``` `allowedCallerPermissions` rather than `minimumCallerPermissions`: `runner-policy.mjs` rejects a write scope in `minimumCallerPermissions` (GitHub downgrades caller write grants on Dependabot PRs), and the job declares exactly these two write scopes. ## Fix - `components/runner-policy/policy.json`: the entry above, spliced as text (diff is additions only). - `components/runner-policy/README.md`: ledger note covering what the reusable does, its gating, permissions, inputs and secrets, pinned actions (`dependabot/fetch-metadata` v3.1.0 `25dd0e34f4fe68f24cc83900b1fe3fe149efef98`, `actions/github-script` v9.0.0 `3a2844b7e9c422d3c10d287c895573f7108da1b3`), and the ci-workflows#676 security review. - `components/dependabot-policy/automerge-lockstep.mjs`: reads the reusable's SHA from its single runner-policy contract key, fetches the reusable at that SHA over the contents API with three attempts (same transport and token handling as `pr-convention-policy/lockstep-drift.mjs`), finds the single `PUBLISHER_ALLOWLIST` step env, and fails on any difference from `policy.json`. - `components/dependabot-policy/README.md` and `THREAT-MODEL.md`: the reusable is live (no longer "planned"), and the lockstep is in scope with its own threat row. - Enforcement rollout (docs/component-lifecycle.md#enforcement-rollout): the lockstep blocks from admission with no report-only period. It compares two files at fixed revisions, so there is no fleet baseline to observe; the observation run against the live pinned reusable matched (`PUBLISHER_ALLOWLIST at 69e506b matches policy.json`). - `package.json`: `lint:dependabot-automerge-lockstep`. - `.github/workflows/ci.yml`: a step in the existing `dependabot-policy` job. The fetch targets an immutable SHA in a public repository, so a separate job would add a `needs` edge to `ci-status` with no isolation gain. ## Verification - `npm run lint:runner-policy`: Runner policy passed. - `node --test components/runner-policy/runner-policy.test.mjs`: 296/296 pass. - `npm run lint:dependabot-automerge-lockstep`: PUBLISHER_ALLOWLIST at 69e506b matches policy.json. - `npm run test:dependabot-policy`: 36/36 pass; `npm run lint:dependabot-policy` passed. - `npm run lint:md`: 0 issues; biome clean; lefthook pre-commit green. ## Related - melodic-software/ci-workflows#676 (security review of the reusable) - ci-workflows release v0.35.0 (`69e506b7c119517ef1dfc421479232b386b93a52`) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: found by the actions-conventions Phase 8 sanity check (16 of 17 repos passed; ci-workflows lacked an auto-merge caller). ## Summary ci-workflows is the only repository without a caller of the shared `pr-automerge-dependabot` reusable, so its own vendor Dependabot bumps (e.g. #674) never arm auto-merge, contrary to the org Dependabot lanes policy (standards#684). A separate caller file cannot exist here because `pr-automerge-dependabot.yml` is the reusable itself, so this adds a thin dogfood caller job to `pr-require-checks.yml`, the pattern the Claude lanes already use. ## Fix - New job `pr-automerge-dependabot` in `.github/workflows/pr-require-checks.yml`: `pull_request` events only, the same action predicate as `pr-review`. It has job-scoped `contents: write` and `pull-requests: write`; workflow-level permissions are unchanged. - It is pinned to the released reusable (`@fb56986… # v0.36.0`), not `./`, so a pull request, a Dependabot bump of an action inside the reusable included, cannot redefine the code that holds the write token. - `ci-status` does not depend on the job, because arming waits on `ci-status`. `ci-fanout-consolidation.test.cjs` now lists it among the jobs that stay out of `ci-status`. ## Verification - `actionlint .github/workflows/pr-require-checks.yml`: exit 0. - `node --test .github/scripts/*.test.cjs`: all pass. - The Claude review lanes skip pull requests that edit their caller workflow (`pr-require-checks.yml`); a local review stands in for them. - To confirm after merge: the next vendor-actions Dependabot PR in this repo shows a passing `pr-automerge-dependabot / …` check and auto-merge armed. ## Related - standards#684 (Dependabot lanes policy) - #674 (vendor bump merged by hand for lack of this caller) - #676 (the reusable) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: Phase 5 plan step (shared Dependabot auto-merge reusable R); tracked in the actions-conventions plan, not an issue.
Summary
Adds
.github/workflows/pr-automerge-dependabot.yml, aworkflow_callreusable that arms GitHub squash auto-merge on low-risk Dependabot PRs. GitHub then merges onceci-statusand every other required check pass. It implements standardscomponents/dependabot-policy/policy.jsonautoMerge(github-actions;actions/*,github/*,anthropics/*; no semver-major;ci-status).Fix
pull_request; PR author id49699333(dependabot[bot]); event sender (github.event.sender.id, the pusher) is49699333; fetch-metadata succeeded, and failed, empty or invalid metadata is a skip; every update's ecosystem isgithub_actions; every dependency name matches the case-sensitive allowlist glob; every update is semver patch or minor (grouped PRs included; an uncomputable type skips); every PR commit, head included, has author49699333, committer19864447(web-flow) and a signature verified with reasonvalid. That commit shape matches live Dependabot commits on medley#2094 and ci-workflows build: bump anthropics/claude-code-action from 1.0.235 to 1.0.239 #651, build: bump anthropics/claude-code-action from 1.0.235 to 1.0.240 #655 and build: bump github/codeql-action/upload-sarif from 4.38.1 to 4.38.2 in the vendor-actions group across 1 directory #674.continue-on-error, and the gate step runs on!cancelled(). A force-push that makes fetch-metadata fail therefore still reaches the disarm.enablePullRequestAutoMerge(mergeMethod: SQUASH, expectedHeadOid: <verified head>). No direct-merge fallback, so nothing merges aroundci-status.env:only. Job permissions:contents: write,pull-requests: write. Input:runner(defaultubuntu-24.04).actions/github-scriptbecause a reusable has no ci-workflows checkout..github/scripts/pr-automerge-dependabot.test.cjsextracts the script and runs it against fixtures, picked up bytest-contracts(node --test .github/scripts/*.test.cjs).Verification
node --test .github/scripts/*.test.cjs: 219 pass, 0 fail (27 in the new file: vendor patch armed, vendor major, community patch, mixed group, vendor group with one major, non-Dependabot author, non-Dependabot sender, foreign head commit, forged author with a non-web-flow committer, unsigned commit, non-validreason, moved head, non-actions ecosystem, lookalike owner,Actions/checkoutcase variant, empty and invalid metadata, failed metadata fetch disarmed, disarm).--mode enforcingexits 0 after merging origin/main (refactor(actions): move the synced comment and machine-path composites to their convention names #675).Related
approvedReusableWorkflowContractsentry and the allowlist lockstep test (separate PRs)..github/workflows/dependabot-automerge.yml.🤖 Generated with Claude Code