Uh oh!
There was an error while loading. Please reload this page.
feat(2036): fr-gate authenticates as the App - #280
Conversation
The gate that blocks every promotion, moved off one human's PAT. After this, only
`add-to-kanban` remains -- and `caller-drift`, which keeps the PAT by decision.
WHY IT COULD MOVE, when caller-drift could not: fr-gate is READ-ONLY. It reads
`commits/{sha}/pulls` for authoritative commit->PR attribution, `compare/{base}...{head}`
for the range, and the ProjectV2 graphql for each item's Status. Every one is covered
by permissions the App already holds. It writes no card, no label, no comment -- its
only output is its own conclusion. caller-drift is blocked because it asserts ruleset
`bypass_actors`, which GitHub returns only to a WRITE-access caller; nothing fr-gate
reads has that property.
`owner:` makes the installation token ORG-scoped, which this gate specifically needs:
it queries the org project, and a repo-scoped token cannot see it at all.
The mint is behind the same `if:` as the steps that consume it, so a PR the gate skips
-- not promoting, or carrying `skip-fr-gate` -- mints nothing.
NO FALLBACK TO THE PAT. Standard for this migration, and the argument is stronger
here: this gate blocking wrongly costs a re-run, while it passing wrongly ships
un-FR'd code to production. A silent degrade to a working credential is the one
outcome worth refusing outright.
Also re-points the unreadable-board diagnostic, which told the reader to check
`PROJECTS_KANBAN_TOKEN` -- a credential this gate no longer uses. It now names the
App installation and the organization Projects permission, which is where the fix
actually is. Same true-count-false-name defect the audits' decomposition kept
surfacing (.github#278): a real failure under the wrong remedy.
TIMING, deliberately noted rather than assumed safe: this is a required check on
every promotion branch in the fleet, and callers pin `@main`, so merging here is inert
until `.github` is promoted. It goes live at that promotion, not at this merge -- and
`.github#279` is the currently-open one, so this rides the next.
Verified: `make selftests` 41 passed; actionlint clean; no PROJECTS_KANBAN_TOKEN
reference left in fr-gate.yml.
Refs backend#2036
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>LukasWodka
commented
Aug 18, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d7f8d25. Configure here.
saadqbal
left a comment
There was a problem hiding this comment.
Clean, and on the right side of the #278 lesson. fr-gate is read-only (commits/{sha}/pulls, compare, the ProjectV2 Status query) and every permission it needs — contents:read, pull_requests:read, org projects:read — is already proven in prod: ~11 sibling workflows mint this same App token against project #2, and set-pr-status/fr-pass-comment/advance-deploy-env even write it. That's the opposite of caller-drift, which genuinely needed administration:read the App lacks and correctly kept the PAT.
Mint is fail-closed (no continue-on-error, no PAT fallback), SHA-pinned to the same v3.2.0 as the rest of the fleet, key not logged, and checkout runs before the mint so the token is never persisted. Old PAT wiring and its error text removed cleanly.
One note, not blocking: this PR targets develop, so required is empty and the mint step's if: skips — the green gate check here never exercised the token path. The permission is established by the sibling workflows, not by this PR's CI; first real proof is the next promotion PR.
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Aug 19, 2026
/fr-pass Best-effort FR passed (triage; behavioral evidence limited while e2e journey red — backend#2206). Advancing to Ready for prod. |
Refs #2036. The gate that blocks every promotion, moved off one human's PAT.
After this, only
add-to-kanbanremains — pluscaller-drift, which keeps the PAT by decision.Why this one could move, when
caller-driftcouldn'tfr-gateis read-only:commits/{sha}/pullscompare/{base}...{head}All three are covered by permissions the App already holds. It writes no card, no label, no comment — its only output is its own conclusion.
caller-driftis blocked because it asserts rulesetbypass_actors, which GitHub returns only to a write-access caller. Nothingfr-gatereads has that property.owner:makes the token org-scoped, which this gate specifically needs — it queries the org project, and a repo-scoped token cannot see it at all.Two deliberate details
The mint is behind the same
if:as the steps that consume it, so a PR the gate skips (not promoting, or carryingskip-fr-gate) mints nothing.No fallback to the PAT, and the argument is stronger here than elsewhere in this migration: the gate blocking wrongly costs a re-run; the gate passing wrongly ships un-FR'd code to production. A silent degrade to a working credential is the one outcome worth refusing outright.
Also fixed
The unreadable-board diagnostic told the reader to check
PROJECTS_KANBAN_TOKEN— a credential this gate no longer uses. It now names the App installation and the organization Projects permission, which is where the fix actually is. Same true-count-false-name defect the audits' decomposition kept surfacing in #278: a real failure pointing at the wrong remedy.Timing
This is a required check on every promotion branch in the fleet, and callers pin
@main— so merging here is inert until.githubis promoted. It goes live at that promotion, not at this merge.#279is the currently-open promotion, so this rides the next one, which is the right shape: a quiet window rather than mid-hop.Verification
make selftests41 passed · actionlint clean · zeroPROJECTS_KANBAN_TOKENreferences left infr-gate.yml.Note
Medium Risk
This changes credentials for a required promotion gate; misconfigured App permissions could block merges or (without the deliberate no-fallback policy) risk silent mis-auth, but scope is read-only API access only.
Overview
The FR gate workflow (
fr-gate.yml) stops usingPROJECTS_KANBAN_TOKENand instead mints an org-scoped installation token for the tracebloc-release-train App (owner:so it can read the org Project). A new step runs only when the gate actually enforces (sameif:as discovery and verification); skipped PRs mint nothing.Discover items and Verify each item is in required Status both set
GH_TOKENfrom that App token forcommits/{sha}/pulls, compare API, and ProjectV2 GraphQL reads. Comments document that the gate is read-only, so App permissions suffice, and that there is no PAT fallback—a broken App path should block rather than silently keep passing.When kanban Status is unreadable after retries, the error text now tells operators to check the App installation and organization Projects permission instead of the retired PAT secret.
Reviewed by Cursor Bugbot for commit d7f8d25. Bugbot is set up for automated code reviews on this repo. Configure here.