Skip to content

fix(release): authenticate the manifest push as a GitHub App - #2643

Merged
namastex888 merged 1 commit into
devfrom
fix/release-manifest-app-token
Jul 25, 2026
Merged

namastex888 merged 1 commit into
devfrom
fix/release-manifest-app-token

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

The release pipeline has been silently broken since 2026-07-20

Every release since then failed at "Advance authoritative channel manifests", freezing the channel pointers:

Channel Points to Released
stable 5.260720.10 Jul 21
dev 5.260723.8 Jul 23

Meanwhile v5.260724.1 published 12 assets that no channel can reach, and v5.260724.2 (the #2624 promotion tag) has no release at all. Nothing merged after Jul 23 is installable.

Root cause: the ruleset, not the credential

The main ruleset (id 9203218, enforcement active) carries a pull_request rule with an empty bypass_actors list. Every direct push to main is rejected GH013 regardless of how the pusher authenticates.

That is why two credential models in a row failed the same way:

  • the deploy key (also disabled org-wide) silently fell back to github-actions[bot] → 403;
  • the fine-grained PAT that replaced it → preflight passed on Jul 24, push still rejected GH013.

The workflow's own diagnostic blamed token scope, which sent the last fix down the wrong path.

Fix: mint a short-lived App token

A GitHub App is the narrowest identity that can hold a ruleset bypass. Granting the bypass to a RepositoryRole instead would hand every admin direct push to main, undoing the least-privilege posture F16–F18 established in the stable-release security gate.

  • Preflight now requires RELEASE_MANIFESTS_APP_ID + RELEASE_MANIFESTS_APP_PRIVATE_KEY
  • Token minted per run via actions/create-github-app-token pinned to fee1f7d6 (v3.2.0) — expires in ~1h, so no long-lived credential can push to main
  • Checkout uses the minted token
  • Push-rejection diagnostic now names the ruleset bypass, not just token scope
  • HUMAN SETUP header rewritten with App provisioning steps and the exact gh api bypass command
  • release-docs.test.ts pinned the PAT model; it now pins the App model and asserts the PAT wiring is gone

secrets: inherit already exists in both callers, so the new secrets propagate with no change to the call chain.

Required one-time provisioning (before this can work)

  1. Create an org-owned GitHub App (e.g. genie-release-bot) — Repository permissions → Contents: Read and write, nothing else. Generate a private key.
  2. Install it on automagik-dev/genie only.
  3. Add RELEASE_MANIFESTS_APP_ID and RELEASE_MANIFESTS_APP_PRIVATE_KEY to the release-manifests environment.
  4. Add the App as an Integration bypass actor on ruleset 9203218.
  5. Delete the now-unused RELEASE_MANIFESTS_TOKEN secret.

Verification: 46 pass / 0 fail on release-docs.test.ts + reconcile-release-note.test.ts; all three workflows parse as valid YAML; every external action in the file remains pinned to a 40-hex SHA.

The manifest job has failed every release since 2026-07-20, freezing the
channel pointers: stable at 5.260720.10 and dev at 5.260723.8, while
v5.260724.1 published 12 assets that no channel can reach and the
v5.260724.2 promotion tag has no release at all.

Root cause is not the credential's scope. The 'main' ruleset (id 9203218)
carries a pull_request rule with an EMPTY bypass_actors list, so every
direct push to main is rejected GH013 no matter how the pusher
authenticates. The deploy key failed that way (deploy keys are also
disabled org-wide), and the fine-grained PAT that replaced it failed the
same way — the preflight passed on 07-24 and the push still 403'd.

An App is the narrowest identity that can hold a ruleset bypass; granting
it to a RepositoryRole would hand every admin direct push to main and
undo the least-privilege posture F16-F18 established. So the job now
mints a short-lived App token per run (expires ~1h, nothing long-lived
can push to main) and checks out with it.

- release-publish.yml: preflight requires RELEASE_MANIFESTS_APP_ID and
  RELEASE_MANIFESTS_APP_PRIVATE_KEY, mints via create-github-app-token
  pinned to fee1f7d6 (v3.2.0), checkout uses the minted token; HUMAN
  SETUP header rewritten with the App + ruleset-bypass provisioning
  steps and the exact gh api bypass command
- push-rejection diagnostic now names the ruleset bypass, not just scope
- release.yml / version.yml: secrets-inherit comments follow the rename
- release-docs.test.ts: the contract test pinned the PAT model; it now
  pins the App model and asserts the PAT wiring is gone

Requires one-time provisioning before the next release: create the App,
store its credentials in the release-manifests environment, and add it
as an Integration bypass actor on ruleset 9203218.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dd41ef33-c78c-4d56-860d-defd34c85c25

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-manifest-app-token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 265c809351

ℹ️ 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".

Comment on lines +1060 to +1063
# gh api repos/automagik-dev/genie/rulesets/9203218 -X PUT \
# -f 'bypass_actors[][actor_type=Integration]' \
# -F 'bypass_actors[][actor_id]=<APP_ID>' \
# -f 'bypass_actors[][bypass_mode]=always'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Correct the ruleset bypass provisioning command

When an administrator follows this required one-time setup, the two -f arguments put the values inside the field brackets (bypass_actors[][actor_type=Integration]) rather than using the nested-field syntax bypass_actors[][actor_type]=Integration required by gh api. Moreover, PUT /repos/{owner}/{repo}/rulesets/{ruleset_id} expects the ruleset definition, so the command should first preserve the existing name, enforcement, conditions, rules, and bypass actors instead of submitting only the new actor. As written, provisioning fails or risks replacing existing rules, leaving the App without the bypass and every manifest publication blocked by GH013.

Useful? React with 👍 / 👎.

@namastex888
namastex888 merged commit 6c96f9d into dev Jul 25, 2026
12 checks passed
lirazsiri pushed a commit to lirazsiri/genie that referenced this pull request Jul 28, 2026
The org-wide deploy-key ban made the ssh model unusable, and the
fine-grained PAT that replaced it still could not push: the 'main'
ruleset carried a pull_request rule with an empty bypass_actors list, so
every direct push was rejected GH013 regardless of token scope. That
froze the channel pointers from 2026-07-20 onward.

Resolved without touching the deploy-key policy: PR automagik-si#2643 (promoted in
automagik-si#2644 as 73bd48a) mints a per-run GitHub App token — genie-release-bot,
app id 4393439, contents:write + metadata:read only, installed on this
repository alone, sole ruleset bypass actor Integration:4393439:always.
No user, role, or Actions bypass was added, and the token expires in ~1h
so no long-lived credential can push to main.

The dev/homolog criterion stays UNCHECKED until a post-merge dev release
actually advances a channel manifest — this commit is that release's
trigger.
lirazsiri pushed a commit to lirazsiri/genie that referenced this pull request Jul 28, 2026
…onstration

Codex P2 on PR automagik-si#2702 caught the closure commit leaving the wish
internally contradictory: the G2 acceptance criterion, the QA
criterion, two Review Results closure sentences, and INDEX's pr-2545
line still said no live two-maintainer run had been captured / stable
promotion remained BLOCKED. All five sites now record the evidence:
stable run 30240023804 (v5.260727.5) — automagik-genie dispatched,
independent maintainer approved (prevent_self_review), 36 immutable
assets, all three manifests advanced; credential half landed as the
genie-release-bot App (automagik-si#2643/automagik-si#2644).
@automagik-genie
automagik-genie deleted the fix/release-manifest-app-token branch September 25, 2026 04:50
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