Skip to content

ci(drift): open the PR as a GitHub App so its checks actually run - #20

Merged
cubehouse merged 1 commit into
mainfrom
ci/drift-app-token
Sep 8, 2026
Merged

cubehouse merged 1 commit into
mainfrom
ci/drift-app-token

Conversation

@cubehouse

Copy link
Copy Markdown
Member

The drift job opened its PR with GITHUB_TOKEN. GitHub does not start workflow runs from GITHUB_TOKEN-raised events, so the required test (3.x) checks never reported and the PR was blocked on a report it could not receive. #19 has sat that way since 2026-09-02, its body reporting regenerate: success the whole time.

Now the job mints a short-lived installation token from the tpw-drift GitHub App and hands it to create-pull-request. The push comes from the app's identity, pull_request fires normally, CI reports.

- name: Mint an installation token for the drift bot
  id: app-token
  uses: actions/create-github-app-token@v2
  with:
    app-id: ${{ secrets.DRIFT_APP_ID }}
    private-key: ${{ secrets.DRIFT_APP_PRIVATE_KEY }}

- name: Open PR if models changed
  uses: peter-evans/create-pull-request@v8
  with:
    token: ${{ steps.app-token.outputs.token }}   # the only functional change

The app holds contents:write, pull_requests:write, metadata:read on two repos and nothing else — notably not workflows:write, so it cannot alter CI. The token is minted per run and expires in an hour; the only stored credential is the app private key, revocable independently of any human account.

The create-an-issue steps keep GITHUB_TOKEN deliberately. They open issues on failure, an issue doesn't need to trigger anything, and there's no reason to widen the app's reach.

Why not workflow_dispatch

Tried first, rejected on evidence. workflow_dispatch is documented as one of two exceptions to the no-runs rule, and the exception is real — the dispatch does start a run. It just doesn't satisfy branch protection.

Measured on a throwaway PR in the JavaScript client with push/pull_request stripped from its CI workflow, so the only checks it could get were ones deliberately given to it:

event run outcome PR state
workflow_dispatch success, 3 check runs with the exact required names on the PR head SHA BLOCKED, rollup empty
push success CLEAN

The dispatched run's check runs were verifiably present on the SHA (total_count=3, all completed/success, check suite reporting linkedPRs=1), and the PR still read mergeable_state=blocked across six polls over two minutes. Protection counts check runs by the event that produced their suite, not by SHA and name.

The equivalent change for the JavaScript client is ThemeParks/ThemeParks_JavaScript#38.

Verifying it

The mechanism can't be proven by this PR's own CI, only by a drift run. After merge the job gets triggered manually. Two plausible first-run failures worth naming: a malformed private key fails at create-github-app-token, and a repo missing from the app installation fails with "Resource not accessible by integration".

That run also regenerates against a corrected upstream spec — the schedule-entry and price schemas were fixed server-side after #19 was generated, so #19 is now stale as well as unmergeable.

🤖 Generated with Claude Code

The drift job opened its PR with GITHUB_TOKEN. GitHub does not start workflow
runs from GITHUB_TOKEN-raised events, so the required test (3.x) checks never
reported and the PR was blocked on a report it could not receive. #19 has sat
that way since 2026-09-02 while its body said 'regenerate: success'.

Fixed by minting a short-lived installation token from the tpw-drift app and
handing it to create-pull-request. The push then comes from the app's identity
rather than GITHUB_TOKEN, pull_request fires normally, and CI reports. The app
holds contents:write and pull_requests:write on two repos and nothing else —
notably not workflows:write, so it cannot alter CI.

workflow_dispatch was tried first and rejected on evidence. It is a documented
exception to the no-runs rule and does start a run, but that run's check runs
do not satisfy branch protection: on a test PR a dispatched run put three
successful check runs with the exact required names on the head SHA and left
it BLOCKED with an empty rollup, while a push-event run on the next commit
cleared it at once.

The create-an-issue steps keep GITHUB_TOKEN deliberately. They open issues on
failure, an issue does not need to trigger anything, and there is no reason to
widen the app's reach.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cubehouse
cubehouse merged commit 719925a into main Sep 8, 2026
5 checks passed
@cubehouse
cubehouse deleted the ci/drift-app-token branch September 8, 2026 13:16
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