Skip to content

Sign bot commits via a GitHub App token - #181

Merged
Bill Traynor (wmat) merged 3 commits into
mainfrom
signed-bot-commits
Oct 19, 2026
Merged

Bill Traynor (wmat) merged 3 commits into
mainfrom
signed-bot-commits

Conversation

@wmat

Copy link
Copy Markdown
Collaborator

Problem

The riscv org ruleset on main requires two things: the DCO check and verified commit signatures. Every PR this template's bots open is unsigned, so none of them can merge. The first one to hit this was riscv/riscv-performance-event-sampling#90 (a template-sync PR): DCO was green, and the merge box said "Commits must have verified signatures."

Three workflows open bot PRs, and all three push with GHTOKEN, a personal access token:

  • template-sync.yml: the sync PR
  • version-bot.yml, milestone-pr: the milestone PR
  • build-pdf.yml, stamp-site-version: the site version stamp PR

peter-evans/create-pull-request signs commits only with bot tokens. Its docs say that with a PAT "the action will create the pull request, but commits will not be signed." GITHUB_TOKEN isn't an option either, because a sync PR always changes .github/workflows/, which GITHUB_TOKEN can't push. Today the only workaround is for a maintainer to check out every bot PR, re-sign the commit, and force-push.

Change

If a GitHub App is configured, each of the three workflows gets a token for it with actions/create-github-app-token@v3 and passes sign-commits: true to create-pull-request. GitHub then signs the commit as the App's bot. The App is configured by:

  • variable BOT_APP_CLIENT_ID
  • secret BOT_APP_PRIVATE_KEY

If neither is set, nothing changes: the workflows fall back to GHTOKEN, then GITHUB_TOKEN, as before. template-sync.yml now prints a warning when its commit will be unsigned.

DCO keeps passing. With sign-commits: true the commit's author is the App's bot, and Probot DCO skips commits by bots by default. The existing Signed-off-by: trailer stays and records who triggered the run.

Docs:

  • README.adoc: a new section, "Signed commits: use a GitHub App". It also corrects the old claim that GHTOKEN could hold an App token; those tokens expire within an hour, so they can't be stored as a secret.
  • MIGRATION.md: a Step 16 checklist item.
  • CHANGELOG.md: an entry.

Setup needed (org admin, once, not per repo)

  1. Create a GitHub App owned by riscv, with Contents, Pull requests and Workflows set to read and write.
  2. Install it on the org. All repositories also covers repos created later.
  3. Add the org variable BOT_APP_CLIENT_ID (the App's client ID) and the org secret BOT_APP_PRIVATE_KEY (a generated private key), each visible to all repositories.

Rollout note: in each downstream repo, the sync PR that delivers these workflows is opened by the old template-sync.yml. That one PR is still unsigned and needs a manual re-sign (gh pr checkout N && git commit --amend --no-edit -S && git push --force-with-lease). PRs after it are signed.

Verification

  • All three workflows load as valid YAML. pre-commit passes.

  • actionlint 1.7.7 reports no findings in the new steps. Its two findings are pre-existing SC2129 style notes on lines this PR doesn't touch.

  • Not yet tested end to end. That needs the App to exist. Two things still need confirming on a real run:

    • sign-commits produces a verified commit when the change touches .github/workflows/. This is why the App needs the Workflows permission.
    • The org's DCO check passes on the bot-authored commit.

    One template-sync dispatch in a downstream repo after setup settles both.

Alternative considered

Adding a bypass actor to the org ruleset. A ruleset bypass applies to the account doing the merge, not to who wrote the commits. So it would let those people merge any unsigned PR, not just bot PRs. It would also bypass DCO, which sits in the same ruleset.

🤖 Generated with Claude Code

Bill Traynor (wmat) and others added 2 commits October 19, 2026 05:40
Under the riscv org's ruleset, main requires verified signatures as well
as DCO. The three workflows that open PRs (template-sync, the
version-bot milestone PR, the build-pdf site stamp PR) push with
GHTOKEN, a personal access token, and create-pull-request cannot sign
with a PAT. Every bot PR was blocked with "Commits must have verified
signatures" while DCO was green (riscv-performance-event-sampling#90).

When a GitHub App is configured (vars.BOT_APP_CLIENT_ID,
secrets.BOT_APP_PRIVATE_KEY), mint its token with
actions/create-github-app-token@v3 and pass sign-commits: true, so
GitHub signs the commit as the App's bot. Probot DCO skips bot-authored
commits. Without the App, behavior is unchanged: fall back to GHTOKEN.

Document the setup in README.adoc, add a MIGRATION.md Step 16 check,
and warn in template-sync when commits will be unsigned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bill Traynor <wmat@riscv.org>
Both sides added an entry at the top of CHANGELOG.md's [Unreleased]
section: this branch's bot-signing entry and #179's version-stamp
entry from main. Keep both. No other path conflicted; version-bot.yml
auto-merged and carries both this branch's App-token step and #179's
tag fallback.

Signed-off-by: Bill Traynor <wmat@riscv.org>
Bill Traynor (wmat) added a commit to riscv/riscv-high-assurance-cryptography that referenced this pull request Oct 19, 2026
Throwaway branch for testing riscv/docs-spec-template#181. Delete
once the signed-commit evidence is captured.

Signed-off-by: Bill Traynor <wmat@riscv.org>
The riscv organization already carries the App's client ID and private
key as the secrets TEMPLATE_SYNC_APP_CLIENT_ID and
TEMPLATE_SYNC_PRIVATE_KEY, so read those rather than asking an org
admin to re-create them as BOT_APP_CLIENT_ID and BOT_APP_PRIVATE_KEY.

The client ID moves from a variable to a secret, which forces one
structural change: GitHub's context availability table permits
`secrets` in `env`, `with` and `run`, but not in `jobs.<id>.steps.if`,
so the mint step can no longer test the credential directly. It is
allowed in `jobs.<id>.env`, so each of the three jobs now hoists the
test into a job-level `HAS_APP` and the gate reads `env.HAS_APP`.

Observed on riscv/riscv-high-assurance-cryptography: a dispatch of the
previous version skipped "Mint GitHub App token" because
vars.BOT_APP_CLIENT_ID was empty, and the sync commit came back
verified=false, reason=unsigned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Bill Traynor <wmat@riscv.org>
Bill Traynor (wmat) added a commit to riscv/riscv-high-assurance-cryptography that referenced this pull request Oct 19, 2026
Picks up riscv/docs-spec-template#181 at ceea3b8.

Signed-off-by: Bill Traynor <wmat@riscv.org>
@wmat
Bill Traynor (wmat) merged commit 19b598d into main Oct 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant