[16.3.x] Authenticate Turborepo remote caching with OIDC instead of a static PAT - #97603
Merged
Merged
Conversation
CI authenticated to Vercel Remote Cache with a long-lived Personal Access
Token in the `TURBO_TOKEN` repository secret, wired into six workflows and
passed separately into `.github/actions/sccache` as a `turbo-token` input.
That token never expires, is scoped to a team member rather than the team,
and is readable by every job that inherits secrets. Each job now mints its
own short-lived, cache-only token instead, using
`vercel/setup-turborepo-remote-cache-action` against a Turborepo CLI OIDC
policy configured on the Vercel team.
The exchange step runs in `build_reusable.yml` and in the jobs that invoke
`turbo` or `sccache` directly, and writes `TURBO_TOKEN` and `TURBO_TEAM` for
the steps that follow. It is gated on the `TURBO_TEAM` repository variable,
which serves as both the team slug and the switch. Fork pull requests are not
given repository variables, so they skip the step instead of failing on an
OIDC token they cannot mint, and clearing the variable disables remote caching
through a longer Vercel outage without touching the workflows. The slug also
now lives in that one place rather than repeated across five workflows and the
`sccache` action. The workflow-level `env: TURBO_TOKEN` entries are deleted
rather than left in place, since precedence between an `env:` key and a
`$GITHUB_ENV` write is not documented by GitHub.
A failed exchange costs the job its remote cache rather than failing the job,
so the step carries `continue-on-error: true` and every copy of it uses the
same name.
Dropping those `env:` entries means `TURBO_TOKEN` can now be genuinely unset
rather than set-but-empty, which `.github/actions/sccache/start.sh` was not
written for: `${TURBO_TOKEN:0:3}` in its diagnostics is a substring expansion,
and `set -u` rejects those for an unset name even though it tolerates an empty
one. The script now binds `TURBO_TOKEN` and `TURBO_TEAM` to empty defaults up
front, so a skipped or failed exchange leaves sccache on disk-only caching
instead of aborting the step.
Because a called workflow can only downgrade the permissions it is handed,
`id-token: write` is granted on each job that calls `build_reusable.yml`
rather than inside it, matching how `test-new-tests-deploy` already mints an
OIDC token from within that workflow. For the integration test suites the
grant is declared at both hops of the chain. A blanket workflow-level grant
would have been shorter but would silently downgrade `validate-docs-links`,
which comments on pull requests and creates checks, and
`pr_stack_optimizer.yml`, which declares no permissions at all.
Every `secrets.TURBO_TOKEN` reference is gone, along with the now-dead
`turbo-token` input on the `sccache` action and the team slug it hardcoded as
a fallback. `test_e2e_project_reset_cron.yml` never invoked `turbo`, so its
`TURBO_TEAM`, `TURBO_CACHE` and `TURBO_TOKEN` entries are dropped rather than
migrated. `turbo.json` needs no change: no task hashes a `TURBO_*` variable,
so a token that rotates every run does not invalidate the cache.
(cherry picked from commit 1cdbd64)
Contributor
Stats from current PR🟢 1 improvement
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
Build Cache
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (33 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsfailed to diffapp-page-exp..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsfailed to diffapp-page.runtime.dev.jsfailed to diffapp-page.runtime.prod.jsfailed to diffapp-route-ex..ntime.dev.jsDiff too large to display app-route-ex..time.prod.jsDiff too large to display app-route-tu..ntime.dev.jsDiff too large to display app-route-tu..time.prod.jsDiff too large to display app-route-tu..ntime.dev.jsDiff too large to display app-route-tu..time.prod.jsDiff too large to display app-route.runtime.dev.jsDiff too large to display app-route.ru..time.prod.jsDiff too large to display dev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffpages-api-tu..ntime.dev.jsDiff too large to display pages-api-tu..time.prod.jsDiff too large to display pages-api.runtime.dev.jsDiff too large to display pages-api.ru..time.prod.jsDiff too large to display pages-turbo...ntime.dev.jsDiff too large to display pages-turbo...time.prod.jsDiff too large to display pages.runtime.dev.jsDiff too large to display pages.runtime.prod.jsDiff too large to display server.runtime.prod.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display 📎 Tarball URLCommit: 17f6509 |
Contributor
Tests PassedCommit: 17f6509 |
eps1lon
marked this pull request as ready for review
August 20, 2026 11:35
eps1lon
enabled auto-merge (squash)
August 20, 2026 11:57
bgw
approved these changes
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backports #97590