@@ -4,54 +4,22 @@ Releases are cut from the `publish` workflow in GitHub Actions. There is no
44local release script, no automated release on push, and no changesets tool.
55Every release is a manual ` workflow_dispatch ` .
66
7- > ⚠️ ** Current state (as of 2026-04-17):** ` github-actions[bot] ` is not on
8- > the ` main ` branch ruleset's bypass list. As a result, ** every stable
9- > (` channel=latest ` ) publish run will fail at the "Tag and release
10- > (post-publish)" step** with `GH013: Repository rule violations found for
11- refs/heads/main — Changes must be made through a pull request`.
7+ > ** Committer identity:** post-publish commits to ` main ` are made by the
8+ > ` kilo-maintainer ` GitHub App (not the generic ` github-actions[bot] ` ),
9+ > using a short-lived installation token minted inside the workflow. The
10+ > app is the sole principal on ` main ` 's branch-ruleset bypass list — see
11+ > [ Branch protection] ( #branch-protection ) . If you see a release commit
12+ > authored by anyone else, something's wrong; stop and investigate.
1213>
13- > ** Recovery after a failed stable run:**
14+ > ** Required secrets** (already configured, documented here for
15+ > disaster-recovery reference):
1416>
15- > 1 . Check what actually landed on origin:
17+ > - ` KILO_MAINTAINER_APP_ID ` — the numeric App ID.
18+ > - ` KILO_MAINTAINER_APP_SECRET ` — the App's private key (full PEM).
1619>
17- > ``` bash
18- > git fetch origin --tags
19- > git ls-remote --tags origin " vX.Y.Z" # tag?
20- > gh release view " vX.Y.Z" --repo Kilo-Org/shell-security # release?
21- > ` ` `
22- >
23- > 2. ** If the tag exists and only the GitHub release is missing** (the
24- > typical outcome — tags aren' t covered by the branch ruleset and
25- > usually land even when the `main` push is rejected), create the
26- > release against the existing tag:
27- >
28- > ```bash
29- > gh release create vX.Y.Z \
30- > --repo Kilo-Org/shell-security \
31- > --title vX.Y.Z \
32- > --generate-notes \
33- > --verify-tag
34- > ```
35- >
36- > `--verify-tag` makes `gh` fail fast if the tag is missing instead of
37- > silently creating a new one at current `main` HEAD. That' s the whole
38- > recovery — no other steps needed.
39- >
40- > 3. ** If the tag is also missing** (rare), follow
41- > [Scenario 4](# scenario-4-publish-succeeded-but-commit--tag-push-failed)
42- > below. It rebuilds the release commit locally (you can' t tag the
43- > runner-side SHA; that commit lived only in the Actions runner),
44- > tags, pushes, then creates the release. The workflow' s
45- > ` Print recovery instructions on partial failure` step also prints
46- > this full sequence inline in the failed run' s logs for copy-paste.
47- >
48- > After step 2 (common case), `main`' s ` package.json` will be one version
49- > behind. Leave it alone — ` script/version.ts` computes the next version
50- > from git tags, not from ` package.json` , so the drift is cosmetic.
51- >
52- > This banner can be removed once the ruleset bypass is configured (see
53- > [Branch protection](# branch-protection)) or the workflow is refactored
54- > so stable publishes don' t push to `main` at all.
20+ > Both are consumed by ` .github/actions/setup-git-committer/action.yml ` .
21+ > The same pair is used in ` Kilo-Org/kilocode ` ; regenerating the
22+ > private key there would require updating it here too.
5523
5624## Channels
5725
@@ -282,9 +250,9 @@ This is the most dangerous failure mode. Symptom: `npm publish` succeeds
282250step passes, but the workflow fails at the ** "Commit version bump (stable
283251only)"** or ** "Tag release"** step with a ` remote rejected ` error.
284252
285- Most common cause: branch protection on ` main ` does not include
286- ` github-actions[bot] ` in the bypass actors list. See ** Branch protection **
287- below.
253+ Most common cause: ` main ` 's branch ruleset bypass list does not include
254+ the ` kilo-maintainer ` GitHub App, or the App's installation token is
255+ expired/revoked. See ** Branch protection ** below.
288256
289257Recovery steps:
290258
@@ -329,37 +297,38 @@ Recovery steps:
329297 # Add --prerelease for dev releases.
330298 ```
331299
332- 5. Fix the underlying cause (branch protection bypass) before the next release.
300+ 5 . Verify the App token, App installation, and bypass list are still
301+ valid (see ** Branch protection** below) before the next release.
333302
334303## Branch protection
335304
336- When branch protection / rulesets are enabled on ` main` , the
337- ` github-actions[bot] ` actor ** must ** be added to the ruleset ' s bypass actors
338- list. Without it, the publish workflow ' s stable-channel commit step fails,
339- triggering the recovery procedure above.
340-
341- > ** Status today: ** the ` Main branch protection ` ruleset on this repo
342- > ( ` Settings → Rules → Rulesets ` ) is active but does NOT include
343- > ` github-actions[bot] ` as a bypass actor. This is why the banner at the
344- > top of this document describes the manual recovery step as expected
345- > behavior for every stable publish. Two viable durable fixes, pick one:
346- >
347- > 1. ** Add the bot to the bypass list ** (Settings → Rules → the ruleset
348- > → Bypass list → add the ` github-actions ` app with bypass mode
349- > ` Always ` ). Fastest ; keeps the current workflow unchanged.
350- > 2. ** Refactor the stable publish path ** to match the dev-channel flow:
351- > detach HEAD, commit, tag, push only the tag — never touch ` main ` .
352- > Keeps the ruleset strict with no carve-outs ; the trade-off is that
353- > ` main ` ' s `package.json` version drifts behind the latest release
354- > (cosmetic only, since `version.ts` reads from tags).
355-
356- Dev-channel publishes don ' t push to ` main ` (only push the tag), so they ' re
357- less affected by branch protection on `main` itself. The tag push still
358- needs to be allowed — most rulesets allow tag pushes by default, but if
359- yours blocks them, allowlist `github-actions[bot]` for tag operations too.
360-
361- See [AGENTS.md](./AGENTS.md#branch-protection-and-the-release- commit) for the
362- longer-term plan to replace the bot bypass with a dedicated GitHub App .
305+ The ` Main branch protection` ruleset on ` main ` (Settings → Rules →
306+ Rulesets) restricts direct pushes. The publish workflow bypasses this
307+ restriction by authenticating as the ` kilo-maintainer ` GitHub App rather
308+ than the default ` github-actions[bot] ` . Requirements for this to work:
309+
310+ 1 . ** ` kilo-maintainer ` App is installed on ` Kilo-Org/shell-security ` . **
311+ Verify at Settings → GitHub Apps → Installed GitHub Apps. The App is
312+ also installed on ` Kilo-Org/kilocode ` ; same App, same credentials.
313+ 2 . ** Two secrets exist in this repo ** (or at org level, exposed to this
314+ repo): ` KILO_MAINTAINER_APP_ID ` (numeric) and ` KILO_MAINTAINER_APP_SECRET `
315+ (full PEM private key). Regenerating the App's private key requires
316+ updating ` KILO_MAINTAINER_APP_SECRET ` in every repo that uses it.
317+ 3 . ** Bypass actor configured on the ruleset. ** Settings → Rules →
318+ ` Main branch protection ` → ** Bypass list ** must include the
319+ ` kilo-maintainer ` App with bypass mode ` Always ` . Do NOT add the
320+ generic ` github-actions ` app — that would grant bypass to every
321+ workflow in the repo; the point of using the dedicated app is
322+ to keep the bypass narrowly scoped to the publish flow.
323+
324+ If a stable publish fails at the push step and all three above are in
325+ place, check the workflow run's ` Setup git committer ` step output — a
326+ revoked installation or an expired/rotated private key would fail there
327+ rather than at the push.
328+
329+ Dev-channel publishes don't touch ` main ` (they push only the tag via an
330+ orphan commit), so they don't depend on item 3 above — but they still
331+ need items 1 and 2 for the same token minting flow .
363332
364333## First publish of a newly-named npm package (OIDC bootstrap)
365334
0 commit comments