protect-main requires signed commits, and the build(packaging): … PR the packages job opens had an unsigned commit. #82's DCO sign-off was not enough: peter-evans/create-pull-request signs only with a bot token and explicitly not with a PAT, which is why the v1.0.1 packaging PR went #80 → #83 (re-created unsigned by "update branch") → #84 (cherry-picked and signed by hand).
packages now mints a short-lived token from a release GitHub App (actions/create-github-app-token v3.2.0, SHA-pinned) using the repository variable RELEASE_APP_CLIENT_ID and the release-environment secret RELEASE_APP_PRIVATE_KEY (contents + pull requests write, this repository only, no bypass), and opens the PR with it and sign-commits: true. GitHub signs the commit, its author is the App's [bot] user (exempt from pr / dco), and the PR still triggers the required checks. Same pattern as the standards repository's own release automation.
DEPS_PAT is no longer used by the release workflow (it stays optional for nuget-updates.yml). The preflight step fails when the App id or key is missing.
docs/RELEASING.md (tokens table + "Why a GitHub App" with the one-time setup), ADR 0003 and the threat model revision table record the change.
Create a GitHub App (Settings → Developer settings → GitHub Apps): installed only on KofTwentyTwo/gclo, permissions Contents: write and Pull requests: write, no ruleset bypass.
Repository variable RELEASE_APP_CLIENT_ID = the App's client id.
release environment secret RELEASE_APP_PRIVATE_KEY = the App's private key (.pem), e.g. op read "op://<vault>/<item>/private key" | gh secret set RELEASE_APP_PRIVATE_KEY --env release --repo KofTwentyTwo/gclo.
How it was tested
actionlint clean; create-github-app-token@bcd2ba4 is the v3.2.0 tag and exposes client-id, private-key, permission-contents, permission-pull-requests.
Not exercised on a tag: the next stable release is the first run. If the App is not set up by then, the packages job fails at its preflight and can be re-run alone after the secrets are added.
## What
`protect-main` requires signed commits, and the `build(packaging): …` PR the `packages` job opens had an unsigned commit. #82's DCO sign-off was not enough: `peter-evans/create-pull-request` signs only with a bot token and explicitly not with a PAT, which is why the v1.0.1 packaging PR went #80 → #83 (re-created unsigned by "update branch") → #84 (cherry-picked and signed by hand).
- `packages` now mints a short-lived token from a release GitHub App (`actions/create-github-app-token` v3.2.0, SHA-pinned) using the repository variable `RELEASE_APP_CLIENT_ID` and the `release`-environment secret `RELEASE_APP_PRIVATE_KEY` (contents + pull requests write, this repository only, no bypass), and opens the PR with it and `sign-commits: true`. GitHub signs the commit, its author is the App's `[bot]` user (exempt from `pr / dco`), and the PR still triggers the required checks. Same pattern as the standards repository's own release automation.
- `DEPS_PAT` is no longer used by the release workflow (it stays optional for `nuget-updates.yml`). The preflight step fails when the App id or key is missing.
- `docs/RELEASING.md` (tokens table + "Why a GitHub App" with the one-time setup), ADR 0003 and the threat model revision table record the change.
Closes #85 (follows #81, part of #62).
## Owner steps before the next stable release
1. Create a GitHub App (Settings → Developer settings → GitHub Apps): installed **only on KofTwentyTwo/gclo**, permissions **Contents: write** and **Pull requests: write**, no ruleset bypass.
2. Repository variable `RELEASE_APP_CLIENT_ID` = the App's client id.
3. `release` environment secret `RELEASE_APP_PRIVATE_KEY` = the App's private key (`.pem`), e.g. `op read "op://<vault>/<item>/private key" | gh secret set RELEASE_APP_PRIVATE_KEY --env release --repo KofTwentyTwo/gclo`.
## How it was tested
- `actionlint` clean; `create-github-app-token@bcd2ba4` is the `v3.2.0` tag and exposes `client-id`, `private-key`, `permission-contents`, `permission-pull-requests`.
- Not exercised on a tag: the next stable release is the first run. If the App is not set up by then, the `packages` job fails at its preflight and can be re-run alone after the secrets are added.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
protect-mainrequires signed commits, and thebuild(packaging): …PR thepackagesjob opens had an unsigned commit. #82's DCO sign-off was not enough:peter-evans/create-pull-requestsigns only with a bot token and explicitly not with a PAT, which is why the v1.0.1 packaging PR went #80 → #83 (re-created unsigned by "update branch") → #84 (cherry-picked and signed by hand).packagesnow mints a short-lived token from a release GitHub App (actions/create-github-app-tokenv3.2.0, SHA-pinned) using the repository variableRELEASE_APP_CLIENT_IDand therelease-environment secretRELEASE_APP_PRIVATE_KEY(contents + pull requests write, this repository only, no bypass), and opens the PR with it andsign-commits: true. GitHub signs the commit, its author is the App's[bot]user (exempt frompr / dco), and the PR still triggers the required checks. Same pattern as the standards repository's own release automation.DEPS_PATis no longer used by the release workflow (it stays optional fornuget-updates.yml). The preflight step fails when the App id or key is missing.docs/RELEASING.md(tokens table + "Why a GitHub App" with the one-time setup), ADR 0003 and the threat model revision table record the change.Closes #85 (follows #81, part of #62).
Owner steps before the next stable release
RELEASE_APP_CLIENT_ID= the App's client id.releaseenvironment secretRELEASE_APP_PRIVATE_KEY= the App's private key (.pem), e.g.op read "op://<vault>/<item>/private key" | gh secret set RELEASE_APP_PRIVATE_KEY --env release --repo KofTwentyTwo/gclo.How it was tested
actionlintclean;create-github-app-token@bcd2ba4is thev3.2.0tag and exposesclient-id,private-key,permission-contents,permission-pull-requests.packagesjob fails at its preflight and can be re-run alone after the secrets are added.🤖 Generated with Claude Code