Skip to content

feat(2036): fr-gate authenticates as the App - #280

Merged
LukasWodka merged 1 commit into
developfrom
feat/2036-app-token-fr-gate
Aug 18, 2026
Merged

feat(2036): fr-gate authenticates as the App#280
LukasWodka merged 1 commit into
developfrom
feat/2036-app-token-fr-gate

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Refs #2036. The gate that blocks every promotion, moved off one human's PAT.

After this, only add-to-kanban remains — plus caller-drift, which keeps the PAT by decision.

Why this one could move, when caller-drift couldn't

fr-gate is read-only:

readsfor
commits/{sha}/pullsauthoritative commit→PR attribution
compare/{base}...{head}the promotion range
ProjectV2 graphqleach item's Status

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-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 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 carrying skip-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 .github is promoted. It goes live at that promotion, not at this merge. #279 is the currently-open promotion, so this rides the next one, which is the right shape: a quiet window rather than mid-hop.

Verification

make selftests 41 passed · actionlint clean · zero PROJECTS_KANBAN_TOKEN references left in fr-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 using PROJECTS_KANBAN_TOKEN and 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 (same if: as discovery and verification); skipped PRs mint nothing.

Discover items and Verify each item is in required Status both set GH_TOKEN from that App token for commits/{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.

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

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@cursorcursorBot 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.

✅ 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.

@saadqbalsaadqbal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

@LukasWodka
LukasWodka merged commit 525ba00 into developAug 18, 2026
12 checks passed
@LukasWodka
LukasWodka deleted the feat/2036-app-token-fr-gate branch August 18, 2026 10:23
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

/fr-pass

Best-effort FR passed (triage; behavioral evidence limited while e2e journey red — backend#2206). Advancing to Ready for prod.

Sign up for freeto 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.

2 participants

@LukasWodka@saadqbal