Repository navigation
Auto-merge bump PRs whose commit is signed by a bump workflow - #15973
Conversation
The bump workflows now sign their commits with gitsign, using their GitHub Actions OIDC identity (a Fulcio certificate whose SAN is the workflow file on main, logged to Rekor). A new workflow looks for open PRs whose only commit is the PR head and carries a valid gitsign signature from one of those workflow identities. For such PRs it approves (as github-actions[bot]) and enables squash auto-merge (as pyca-boringbot, so the merge triggers push workflows), pinned to the verified head commit. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm
| OIDC identity (requires `id-token: write`). | ||
|
|
||
| inputs: | ||
| sign-commits: |
There was a problem hiding this comment.
why is this an option that defaults to false?
There was a problem hiding this comment.
There was no good reason for it. It only existed because the auto-merge job needs the gitsign binary to run gitsign verify, but it never commits. Turning signing on in that job does nothing, so I've removed the input and the action now always configures signing (7643bbe). I also dropped the id-token precheck: if the permission is missing, gitsign fails on its own at commit time.
Generated by Claude Code
The auto-merge job never commits, so configuring signing there is harmless, and it removes an option whose default didn't make sense. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm
| description: "Only report what would be done" | ||
| type: boolean | ||
| default: false | ||
| schedule: |
There was a problem hiding this comment.
Removed in eb3eafc. It now runs only on workflow_run (when a bump workflow finishes) and workflow_dispatch.
Generated by Claude Code
| schedule: | ||
| - cron: "37 */4 * * *" | ||
| workflow_run: | ||
| workflows: |
There was a problem hiding this comment.
can we reference these by filename?
There was a problem hiding this comment.
Unfortunately not: on.workflow_run.workflows only matches against the workflow's name:. The docs say the filters "match more than one workflow name", and every example uses names. I added a comment saying that, and pointing to BUMP_WORKFLOWS in the script, which does use the filenames, since those are what end up in the signing identity (b96ac71).
If a workflow gets renamed and this list goes stale, the result is just a missed auto-merge, so a person merges it by hand. It can't cause anything to be approved that shouldn't be.
Generated by Claude Code
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm
| type: boolean | ||
| default: false | ||
| schedule: | ||
| - cron: "37 */4 * * *" |
There was a problem hiding this comment.
We shouldn't do a fallback like this. If we miss one the worst case is a person manually merges, so just remove it.
There was a problem hiding this comment.
Agreed. The cron fallback is gone (eb3eafc), so it now runs only on workflow_run and workflow_dispatch.
Generated by Claude Code
| GH_TOKEN: ${{ github.token }} | ||
| # Auto-merge is enabled by pyca-boringbot, so that the eventual | ||
| # merge triggers `push` workflows (which GITHUB_TOKEN would not). | ||
| AUTO_MERGE_TOKEN: ${{ steps.generate-token.outputs.token }} |
There was a problem hiding this comment.
can we not do this with teh regular job token?
There was a problem hiding this comment.
We can, but there's a cost. With auto-merge, the merge is attributed to whoever enabled it. If that's GITHUB_TOKEN (github-actions[bot]), the resulting push to main won't trigger workflows, so ci.yml and wheel-builder.yml wouldn't run their on: push jobs for these merges. That's the documented "events triggered by GITHUB_TOKEN don't start new workflow runs" behavior.
There may be a second problem I haven't verified: GITHUB_TOKEN can't be granted the workflows permission, and two of the three bump PRs edit .github/workflows/ci.yml. That could block the merge entirely.
If you're fine with no push-CI on main for bump merges, I'll switch to GITHUB_TOKEN. That drops the app-token step and keeps the boringbot secrets out of this job entirely. Want me to?
Generated by Claude Code
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm
| GITSIGN_SHA256: "2bc625472a08fea3bb6a57982c7d8b4978d1032251d305ceef3bf2ded0ca4483" | ||
| run: | | ||
| set -euo pipefail | ||
| if [ "${RUNNER_OS}" != "Linux" ] || [ "${RUNNER_ARCH}" != "X64" ]; then |
There was a problem hiding this comment.
we only run these jobs on x86-64 we don't need this branch
There was a problem hiding this comment.
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm
This lets the daily bump PRs (BoringSSL/OpenSSL/AWS-LC, downstreams, x509-limbo/wycheproof) merge without a human, gated on a sigstore signature rather than on anything about the PR itself.
How it works
Signing (the bump workflows). Each bump job gets
id-token: writeand runs a new composite action,.github/actions/setup-gitsign. The action installs gitsign v0.18.0 from a release binary checked against a pinned SHA-256, and sets git to sign every commit with it (gpg.format=x509,commit.gpgsign=true,gitsign.tokenProvider=github-actions,gitsign.rekorMode=offline).peter-evans/create-pull-requestmakes its commits with plaingit commit, so it picks up this config with no other changes. Each commit is signed with a short-lived Fulcio certificate whose SAN is the workflow's identity, for example:The signature is logged in Rekor. Offline mode puts the inclusion proof inside the signature, so verifying it doesn't need a Rekor lookup.
Verifying and merging (
auto-merge-bumps.yml+.github/bin/auto_merge_bump_prs.py). This runs when any bump workflow finishes (workflow_run) and on manual dispatch (which has adry-runinput). It only runs code frommain. For each open, non-draft PR againstmainthat comes from a branch in this repo:main.gitsign verify --certificate-identity=<one of the 3 workflow identities> --certificate-oidc-issuer=https://token.actions.githubusercontent.com.github-actions[bot](GITHUB_TOKEN), with the review pinned to that commit. pyca-boringbot can't do this because it authors the PRs, and GitHub won't let you approve your own PR.--match-head-commit=<verified sha>. It uses the app token because a merge done byGITHUB_TOKENwouldn't trigger thepushCI onmain. The token hasworkflows: writebecause the bump PRs editci.yml.Both steps are idempotent: if a PR already has an approval from us for that head commit, or already has auto-merge enabled, the step is skipped. The script doesn't look at the PR's author, title or branch, only at the signature.
Repo settings needed before this does anything
main's branch protection or ruleset. Otherwise, someone with write access could push to an approved bump branch after verification and before the merge.Testing
auto_merge_bump_prs.pyagainst stubbedgh/git/gitsign. It handled each case correctly: signed PR, unsigned PR, bad signature, fork, already approved and auto-merge already on. It also used the right token for each call.nox -e flakepasses.dry-runwill then show whether verification passes, before anything gets approved.🤖 Generated with Claude Code
https://claude.ai/code/session_01TKUFHFE7g1LPHJakSrKgBm