From 96212c230529579849c725f5292b21f14a3fa92f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Oct 2026 00:06:09 +0000 Subject: [PATCH 1/2] ci: pin the credential-holding third-party actions by commit sha docker/setup-qemu-action, docker/setup-buildx-action, docker/login-action, docker/metadata-action and docker/build-push-action in docker-publish.yml (a packages: write job), lycheeverse/lychee-action in check-links.yml and dorny/paths-filter in ci.yml each name the commit their floating major resolved to, with a trailing version comment, as release.yml already does for changesets/action. Claude-Session: https://claude.ai/code/session_01W9H2WdXx3kPkf6moDnRdRE Co-authored-by: Claude --- .github/workflows/check-links.yml | 4 ++-- .github/workflows/ci.yml | 2 +- .github/workflows/docker-publish.yml | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 8a6b2f207c5..24d2913e18e 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -144,7 +144,7 @@ jobs: # retry below; it does NOT let a failure through, because the retry # step carries no such escape and its failure fails the job. continue-on-error: true - uses: lycheeverse/lychee-action@v2 + uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 with: lycheeVersion: ${{ env.LYCHEE_VERSION }} args: ${{ env.LYCHEE_ARGS }} @@ -163,7 +163,7 @@ jobs: - name: Check links with lychee (retry) id: lychee-retry if: steps.lychee.outcome == 'failure' - uses: lycheeverse/lychee-action@v2 + uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 with: lycheeVersion: ${{ env.LYCHEE_VERSION }} args: ${{ env.LYCHEE_ARGS }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d64c774dde2..2146cba8097 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -200,7 +200,7 @@ jobs: # of nothing at all. An allow-list makes each new event fail toward # THE FILTER CONTRACT's half 1 instead: the step is skipped, its outputs # are the empty string, `|| 'true'` fills them in, and everything runs. - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 id: changes if: github.event_name == 'pull_request' || github.event_name == 'push' with: diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index c9edc62e200..412ddd0702d 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -57,13 +57,13 @@ jobs: echo "version=$VERSION" >> "$GITHUB_OUTPUT" - name: Set up QEMU (arm64 emulation) - uses: docker/setup-qemu-action@v4 + uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - name: Log in to ghcr.io - uses: docker/login-action@v4 + uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -71,7 +71,7 @@ jobs: - name: Compute image tags id: meta - uses: docker/metadata-action@v6 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ${{ env.IMAGE }} # Tag = CLI version. Rolling minor/major/latest tags move with every @@ -83,7 +83,7 @@ jobs: type=raw,value=latest,enable=${{ !contains(steps.version.outputs.version, '-') }} - name: Build and push - uses: docker/build-push-action@v7 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: docker platforms: linux/amd64,linux/arm64 From 7ea2af7e6a6baeb9401fcc7ff8a555e31a4e500c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Oct 2026 00:07:34 +0000 Subject: [PATCH 2/2] ci: pass the Turbo remote-cache credentials only to merge-queue and main runs TURBO_TOKEN and TURBO_REMOTE_CACHE_SIGNATURE_KEY now reach a carrier only on merge_group or a run on refs/heads/main, in all twelve carriers (ci.yml x7, lint.yml x5). A pull_request run builds from the restored Actions-cache seed; `remote:r` was a client setting, while the token can write and the key can sign. assert-turbo-remote-cache reports such a run as a notice (credentials withheld by design) instead of a warning, with a self-test battery for the condition. Claude-Session: https://claude.ai/code/session_01W9H2WdXx3kPkf6moDnRdRE Co-authored-by: Claude --- .github/workflows/ci.yml | 49 ++++++++++++++---------- .github/workflows/lint.yml | 20 +++++----- scripts/ci/assert-turbo-remote-cache.mjs | 35 +++++++++++++++-- 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2146cba8097..1ac9ce6a5f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -806,9 +806,9 @@ jobs: env: NODE_OPTIONS: --report-on-signal --report-signal=SIGUSR2 --report-directory=${{ runner.temp }}/stall-reports TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: | FILTERS="" if [ -s "$RUNNER_TEMP/shard-packages.txt" ]; then @@ -1870,9 +1870,9 @@ jobs: - name: Build driver-sql and its dependencies env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter=@objectstack/driver-sql... --concurrency=4 # The whole driver-sql suite runs under the skewed process zone — not @@ -1932,9 +1932,9 @@ jobs: - name: Build the non-SQL temporal backends env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: >- pnpm exec turbo run build --filter=@objectstack/service-analytics... @@ -2016,9 +2016,9 @@ jobs: - name: Build metadata-protocol and its dependencies env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter=@objectstack/metadata-protocol... --concurrency=4 - name: Run the metadata-protocol migration statements against live MySQL and PostgreSQL @@ -2078,9 +2078,9 @@ jobs: - name: Build runtime and its dependencies env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter=@objectstack/runtime... --concurrency=4 - name: Run the runtime cascade-delete matrix against live PostgreSQL @@ -2216,9 +2216,9 @@ jobs: env: NODE_OPTIONS: --report-on-signal --report-signal=SIGUSR2 --report-directory=${{ runner.temp }}/stall-reports TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: | mkdir -p "$RUNNER_TEMP/stall-reports" node scripts/run-with-stall-guard.mjs --log "$RUNNER_TEMP/dogfood-build.log" --stall-minutes 10 \ @@ -2640,12 +2640,21 @@ jobs: # `merge_group` and on `push` / `workflow_dispatch` against main; every # other event, `pull_request` and `schedule` included, only reads, # because read-only is the default branch of the expression. This is - # turbo configuration, not a property of the credential: a same-repo PR - # receives the secrets and runs its own copy of this file; fork PRs - # receive none. ⚠️ Never let it evaluate to '': turbo then disables the - # LOCAL cache too (`no caches are enabled`) and re-executes everything. - # - # Credentials: TURBO_TOKEN (secret) is passed only when the signing key + # turbo configuration, not a property of the credential: the token can + # write and the signing key can sign whatever holds them, which is why + # the two secrets below are scoped by event rather than trusted to it. + # ⚠️ Never let it evaluate to '': turbo then disables the LOCAL cache + # too (`no caches are enabled`) and re-executes everything. + # + # Credentials go only to runs whose code has landed or is landing: + # `merge_group`, and any run on refs/heads/main (push, the hourly + # schedule, workflow_dispatch on main). A `pull_request` run, and a + # dispatch on any other branch, receives neither TURBO_TOKEN nor the + # signing key, so code a PR adds can neither upload to the remote nor + # sign an artifact that a queue or main build would replay. Such a run + # builds from the restored Actions-cache seed (local:rw) and the + # assertion step reports the remote as withheld, never as broken. + # TURBO_TOKEN (secret) is further passed only when the signing key # is non-empty, because an empty key still "signs" with a zero-length # HMAC key; TURBO_TEAM is a repo VARIABLE so the slug is not masked out # of the log; TURBO_REMOTE_CACHE_SIGNATURE_KEY (secret) must equal @@ -2690,9 +2699,9 @@ jobs: - name: Build packages (excluding docs) env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm build --summarize --log-file=.turbo/remote-cache/build-core.json - name: The Turbo remote cache was on for the build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a9d7b751be3..af25dd272f0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5786,9 +5786,9 @@ jobs: - name: Build workspace packages env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter='./packages/*' --filter='./examples/*^...' --summarize --log-file=.turbo/remote-cache/typecheck-workspace.json # ci.yml Build Core's "Turbo remote cache (#21186)" comment, ASSERTED @@ -6049,9 +6049,9 @@ jobs: - name: Build workspace packages env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter='./packages/*' --filter='./examples/*^...' --summarize --log-file=.turbo/remote-cache/typecheck-debt.json # ci.yml Build Core's "Turbo remote cache (#21186)" comment, ASSERTED @@ -6124,9 +6124,9 @@ jobs: - name: Build the ledgered packages' dependencies env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' # [#15042] The closure-wide declaration re-check. `check-dts-emitted` runs @@ -6257,9 +6257,9 @@ jobs: - name: Build workspace packages env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter='./packages/*' --filter='./examples/*^...' --summarize --log-file=.turbo/remote-cache/typecheck-consumers.json # ci.yml Build Core's "Turbo remote cache (#21186)" comment, ASSERTED @@ -6290,9 +6290,9 @@ jobs: - name: Build the nested packages the consumer gates resolve through env: TURBO_CACHE: ${{ (github.event_name == 'merge_group' || ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main')) && 'local:rw,remote:rw' || 'local:rw,remote:r' }} - TURBO_TOKEN: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} + TURBO_TOKEN: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY != '' && secrets.TURBO_TOKEN || '' }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ (github.event_name == 'merge_group' || github.ref == 'refs/heads/main') && secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY || '' }} run: pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' # Same sweep as `typecheck-debt`'s step of this name (#15042, #7668, #12078). diff --git a/scripts/ci/assert-turbo-remote-cache.mjs b/scripts/ci/assert-turbo-remote-cache.mjs index 5cd821d81e5..2f4aed95a1c 100644 --- a/scripts/ci/assert-turbo-remote-cache.mjs +++ b/scripts/ci/assert-turbo-remote-cache.mjs @@ -48,9 +48,12 @@ // ## The verdict // // enabled green. -// disabled (any reason) red on a writing run, a warning otherwise: -// fork PRs receive no secrets, and a PR only -// reads. +// disabled (any reason) red on a writing run, a warning otherwise; +// a NOTICE on a run the credentials are +// withheld from by design (`pull_request`, or +// a dispatch off main -- see +// isCredentialedRun), since nothing there is +// broken. // unavailable, transient a warning on every run. `Could not connect` // (`Could not connect`, and `Unexpected server error` are Vercel's // `Unexpected server error`) side; the build is still correct, and a @@ -133,6 +136,15 @@ export function isWritingRun(eventName, ref) { return (eventName === 'push' || eventName === 'workflow_dispatch') && ref === 'refs/heads/main'; } +/** + * Whether this run is GIVEN the remote-cache credentials: `merge_group`, or any + * run on refs/heads/main. Every carrier spells the same condition on its + * TURBO_TOKEN and TURBO_REMOTE_CACHE_SIGNATURE_KEY lines; keep the two in step. + */ +export function isCredentialedRun(eventName, ref) { + return eventName === 'merge_group' || ref === 'refs/heads/main'; +} + /** `'ok' | 'warn' | 'fail' | 'refuse'` for one state on one kind of run. */ export function judge(state, reason, writing) { if (state === 'enabled') return 'ok'; @@ -249,6 +261,15 @@ function main() { if (verdict === 'ok') return; const title = `Turbo remote cache ${read.state} (${args.site})`; if (verdict === 'warn') { + if (read.state === 'disabled' && !isCredentialedRun(process.env.GITHUB_EVENT_NAME, process.env.GITHUB_REF)) { + annotate( + 'notice', + title, + `${read.sentence} -- expected: the remote-cache credentials are passed only to merge_group runs and ` + + 'runs on main, so this run built from the restored Actions-cache seed.', + ); + return; + } annotate('warning', title, read.sentence); return; } @@ -275,6 +296,7 @@ const SELF_TEST_BATTERIES = Object.freeze({ 'structured log parsing': 3, 'remote state': 7, 'writing run': 5, + 'credentialed run': 5, 'verdict table': 9, 'cache counts': 5, 'rendering': 3, @@ -337,6 +359,13 @@ function selfTest() { t('pull_request only reads', !isWritingRun('pull_request', 'refs/pull/1/merge')); t('schedule only reads', !isWritingRun('schedule', 'refs/heads/main')); + battery('credentialed run'); + t('merge_group is credentialed', isCredentialedRun('merge_group', 'refs/heads/gh-readonly-queue/main/pr-1-abc')); + t('push to main is credentialed', isCredentialedRun('push', 'refs/heads/main')); + t('the hourly schedule on main is credentialed', isCredentialedRun('schedule', 'refs/heads/main')); + t('pull_request is not', !isCredentialedRun('pull_request', 'refs/pull/1/merge')); + t('workflow_dispatch off main is not', !isCredentialedRun('workflow_dispatch', 'refs/heads/claude/some-branch')); + battery('verdict table'); t('enabled is green on a writing run', judge('enabled', '', true) === 'ok'); t('enabled is green on a read-only run', judge('enabled', '', false) === 'ok');