From ab2c60b3d0bacd2973f11e5db8b3d2d816becd6a Mon Sep 17 00:00:00 2001 From: Jamie Holding Date: Tue, 8 Sep 2026 14:12:55 +0100 Subject: [PATCH] ci(drift): open the PR as a GitHub App so its checks actually run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drift job opened its PR with GITHUB_TOKEN. GitHub does not start workflow runs from GITHUB_TOKEN-raised events, so the required Test (Node ...) checks never reported and the PR was blocked on a report it could not receive. #34 has sat that way since 2026-09-02 while its body said 'build: 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. 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. Also corrects the comment left on ci.yml's workflow_dispatch trigger by the previous attempt. workflow_dispatch is genuinely a documented exception to the no-runs rule, and it does start a run — but that run's check runs do not satisfy branch protection. Measured, not assumed: on one 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 for two minutes, while a push-event run on the next commit cleared it at once. The trigger is kept because re-running CI against a ref by hand is useful; the claim that it fixes drift is removed. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 15 +++++++++------ .github/workflows/spec-drift.yml | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1eff46c..928a1de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,13 +5,16 @@ on: branches: [main, v7] pull_request: branches: [main, v7] - # Lets another workflow start this one against a specific ref. + # Re-run CI against a ref by hand. Convenience only. # - # The spec-drift job opens its PR with GITHUB_TOKEN, and GitHub does not - # start workflow runs from GITHUB_TOKEN-raised events — so the required - # checks never report and the PR is blocked on a report it can never get. - # workflow_dispatch and repository_dispatch are the two documented - # exceptions to that rule, so drift can dispatch this run itself. + # This was added to let the spec-drift job start its own CI, on the reasoning + # that workflow_dispatch is a documented exception to "GITHUB_TOKEN-raised + # events do not start workflow runs". The run does start — but measured + # against a real PR, its check runs do not satisfy branch protection, even + # sitting on the PR head SHA with the exact required names and a check suite + # reporting as linked to the PR. A push-event run on the next commit cleared + # the same PR immediately. Drift therefore pushes as a GitHub App instead; + # see spec-drift.yml. Kept because dispatching CI by hand is still useful. workflow_dispatch: jobs: diff --git a/.github/workflows/spec-drift.yml b/.github/workflows/spec-drift.yml index b1f4ca8..fef6331 100644 --- a/.github/workflows/spec-drift.yml +++ b/.github/workflows/spec-drift.yml @@ -37,9 +37,27 @@ jobs: continue-on-error: true run: npm run test:live + # The PR must not be opened with GITHUB_TOKEN. GitHub does not start + # workflow runs from GITHUB_TOKEN-raised events, so a PR opened that way + # never gets its required checks and can never be merged, however good + # the diff is. Both drift PRs sat blocked for days on exactly that. + # + # workflow_dispatch is documented as an exception to the no-runs rule and + # does start a run — but measured against a real PR, those check runs do + # not satisfy branch protection even on the right SHA under the right + # names. A push-event run does. So the push has to come from an identity + # that is not GITHUB_TOKEN, and this app is that identity. + - 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 schema changed uses: peter-evans/create-pull-request@v8 with: + token: ${{ steps.app-token.outputs.token }} add-paths: src/_generated/schema.ts branch: automated/spec-drift commit-message: 'chore: regenerate schema from upstream spec'