Skip to content

Commit 50d4fff

Browse files
committed
ci(shard-timings-refresh): push and open the refresh PR as the fleet App so it runs CI
The weekly refresh pushed its branch and opened its PR with the run's own GITHUB_TOKEN (no RELEASE_PUSH_TOKEN is configured), and GitHub starts no workflow for an event that token raised: #24467 waited ten days, #25960 got CI only after a relay pr_update_branch. The write step now runs on a fleet App token minted on the runner from OS_FLEET_APP_ID / OS_FLEET_PRIVATE_KEY (the pair fleet-write.yml mints with, and the route ui/'s refresh took in objectui#13362), narrowed to this repository and to contents + pull-requests. The job's own token drops to contents/actions read, the checkout persists no credential, a missing credential is a named red, and a pull_request run still mints nothing and stays a dry run. The PR body's "no checks will start" paragraph is replaced by a line saying the PR runs its own CI. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GRKsjPHqpppQDE1LMetJX
1 parent 05f7758 commit 50d4fff

1 file changed

Lines changed: 78 additions & 24 deletions

File tree

‎.github/workflows/shard-timings-refresh.yml‎

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -256,24 +256,19 @@ jobs:
256256
name: Regenerate the shard-timings dataset
257257
runs-on: ubuntu-latest
258258
timeout-minutes: 30
259+
# Reads only. The push, the PR and its label go out on the fleet App token
260+
# the write step mints (see "WHOSE IDENTITY OPENS THE PR" at that step),
261+
# never on this run's own `GITHUB_TOKEN`.
259262
permissions:
260-
# Declaring any `permissions:` block drops every scope not listed, so all
261-
# three are spelled even though only two are writes.
262-
contents: write # push the bot branch
263-
pull-requests: write # open the PR and add its label
263+
contents: read # the checkout, and `git show HEAD:` of the committed dataset
264264
actions: read # list runs, read jobs, download run-summary artifacts
265265
steps:
266+
# No persisted credential: the one push goes out on the fleet token
267+
# (`gh auth setup-git` in the write step), never on `GITHUB_TOKEN`.
266268
- name: Checkout repository
267269
uses: actions/checkout@v7
268270
with:
269-
# A PAT when one exists, the Actions token otherwise — the same choice
270-
# cut-rc.yml makes, for the same reason, and the difference is stated
271-
# in the PR body rather than left to be discovered: a PR opened with
272-
# the Actions `GITHUB_TOKEN` starts NO workflow runs (GitHub's
273-
# recursion guard), so with the fallback credential the refresh PR
274-
# arrives with no CI of its own until someone pushes to it or reopens
275-
# it. With the PAT its checks run immediately.
276-
token: ${{ secrets.RELEASE_PUSH_TOKEN || github.token }}
271+
persist-credentials: false
277272

278273
- name: Setup Node.js
279274
uses: actions/setup-node@v7
@@ -710,7 +705,6 @@ jobs:
710705
RUN_COUNT: ${{ steps.generate.outputs.run_count }}
711706
HEAD_SHA: ${{ steps.generate.outputs.head_sha }}
712707
PARTITIONER_EXIT: ${{ steps.bins.outputs.partitioner_exit }}
713-
USED_PAT: ${{ secrets.RELEASE_PUSH_TOKEN != '' }}
714708
run: |
715709
set -euo pipefail
716710
@@ -907,14 +901,9 @@ jobs:
907901
echo "reports and stops, because both are decisions."
908902
echo
909903
fi
910-
if [ "$USED_PAT" != "true" ]; then
911-
echo "## No checks will start on this PR by themselves"
912-
echo
913-
echo "It was opened with the Actions \`GITHUB_TOKEN\`, and GitHub's recursion guard means a"
914-
echo "PR opened that way triggers no workflow runs. Push any commit to the branch, or close"
915-
echo "and reopen the PR, to start CI."
916-
echo
917-
fi
904+
echo "Pushed and opened as the fleet App (\`objectstack-fleet[bot]\`, #25936), so this PR's"
905+
echo "own events start CI: no push or reopen is needed to get its checks."
906+
echo
918907
# ⛔ No closing keyword is emitted here, in any form. GitHub's
919908
# parser matches `fixes`/`closes`/`resolves` plus a number and
920909
# ignores every negation around them, so even a sentence saying a
@@ -924,6 +913,64 @@ jobs:
924913
} > "$RUNNER_TEMP/pr-body.md"
925914
echo "Composed a $(wc -l < "$RUNNER_TEMP/pr-body.md")-line pull request body."
926915
916+
# WHOSE IDENTITY OPENS THE PR (#25936)
917+
# ------------------------------------
918+
# GitHub starts no workflow run for an event raised by a run's own
919+
# `GITHUB_TOKEN` (its recursion guard). This lane used to push and open
920+
# with that token whenever no PAT was configured, and none was: every
921+
# refresh PR arrived with no CI and sat until a seat pushed to it (#24467,
922+
# 2026-10-19, ten days; #25960, 2026-10-26, started only by a relay
923+
# `pr_update_branch`). A refresh can move pin 3c's slice count, so a PR
924+
# nobody's CI reads is exactly the one that needs reading.
925+
#
926+
# So the acts that leave the runner are done as the fleet App
927+
# (`objectstack-fleet[bot]`), whose events DO start workflows: the two
928+
# steps below mint a token from the organization variable
929+
# `OS_FLEET_APP_ID` and secret `OS_FLEET_PRIVATE_KEY` with
930+
# `actions/create-github-app-token`, the pair and action
931+
# fleet-write.yml mints with, and the one ui/'s refresh already took
932+
# (objectui#13362). The token is narrowed to this repository and to
933+
# contents (push the bot branch) + pull-requests (open the PR, add its
934+
# label), exists only in the write step's `env:`, and is revoked by the
935+
# action's post step. No `workflows` grant: the branch is cut from the
936+
# checked-out `main` and adds one commit that touches only the dataset,
937+
# so the push carries no workflow-file change.
938+
#
939+
# ⛔ No fallback to `GITHUB_TOKEN` and no PAT. A missing credential is a
940+
# red run that names it, never a quiet return to a PR with no CI.
941+
# ⛔ A `pull_request` run mints nothing and never reads the App secret:
942+
# its write step is the dry run, and nothing it does leaves the
943+
# runner.
944+
- name: Check the fleet App credential is visible to this repository
945+
id: credential
946+
if: steps.compare.outputs.changed == 'true' && github.event_name != 'pull_request'
947+
env:
948+
HAS_APP_ID: ${{ vars.OS_FLEET_APP_ID != '' }}
949+
HAS_PRIVATE_KEY: ${{ secrets.OS_FLEET_PRIVATE_KEY != '' }}
950+
run: |
951+
# Read as booleans, never printed: a red that names the missing half
952+
# beats create-github-app-token's own error, which does not.
953+
if [ "$HAS_APP_ID" != 'true' ] || [ "$HAS_PRIVATE_KEY" != 'true' ]; then
954+
echo "::error title=Shard timings refresh::The fleet App credential is not visible to this repository (OS_FLEET_APP_ID set: $HAS_APP_ID; OS_FLEET_PRIVATE_KEY set: $HAS_PRIVATE_KEY). Nothing was pushed (#25936)."
955+
exit 1
956+
fi
957+
# The token's one repository, by name: the action takes names
958+
# without the owner, and an empty list would widen it to every
959+
# repository the installation covers.
960+
echo "repository=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"
961+
962+
- name: Mint the fleet App token, narrowed to this repository
963+
id: fleet
964+
if: steps.compare.outputs.changed == 'true' && github.event_name != 'pull_request'
965+
uses: actions/create-github-app-token@v3
966+
with:
967+
app-id: ${{ vars.OS_FLEET_APP_ID }}
968+
private-key: ${{ secrets.OS_FLEET_PRIVATE_KEY }}
969+
owner: ${{ github.repository_owner }}
970+
repositories: ${{ steps.credential.outputs.repository }}
971+
permission-contents: write # push the bot branch
972+
permission-pull-requests: write # open the PR and add its label
973+
927974
# The WRITE — and, on a `pull_request` run of this lane, its rehearsal.
928975
#
929976
# ONE STEP, ONE `env:`, ONE SCRIPT, ON EVERY EVENT (#18341). The write and
@@ -956,7 +1003,11 @@ jobs:
9561003
# refuses any other spelling, and refuses 'false' on a `pull_request`
9571004
# run, so no edit to this line can make a pull request push.
9581005
DRY_RUN: ${{ github.event_name == 'pull_request' }}
959-
GH_TOKEN: ${{ secrets.RELEASE_PUSH_TOKEN || github.token }}
1006+
# The fleet App token on every live run. A dry run mints none, so it
1007+
# holds the run's own read-only token as a stand-in that `outward`
1008+
# never hands to a network act; a live run with no minted token is
1009+
# empty here and the guard below reds it.
1010+
GH_TOKEN: ${{ github.event_name == 'pull_request' && github.token || steps.fleet.outputs.token }}
9601011
# Every variable the script expands that the runner does not provide.
9611012
# The commit message is the dataset's provenance and names all four:
9621013
# ⛔ never drop one from the message to get a green run.
@@ -1004,8 +1055,11 @@ jobs:
10041055
}
10051056
10061057
BRANCH="claude/shard-timings-refresh-$RUN_ID"
1007-
git config user.name 'github-actions[bot]'
1008-
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
1058+
# The checkout persisted no credential; this points git's helper at
1059+
# GH_TOKEN, the fleet token, for the one push below.
1060+
outward gh auth setup-git
1061+
git config user.name 'objectstack-fleet[bot]'
1062+
git config user.email '332303061+objectstack-fleet[bot]@users.noreply.github.com'
10091063
git switch -c "$BRANCH"
10101064
git add scripts/test-shard-timings.json
10111065
# Separate -m flags rather than one embedded newline: a YAML-indented

0 commit comments

Comments
 (0)