Skip to content

feat(cache): authenticate remote cache uploads with GitHub Actions OIDC - #798

Merged
wan9chi merged 2 commits into
claude/remote-cache-auth-hook-18e511from
claude/github-oidc-auth-headers-18e511
Oct 5, 2026
Merged

wan9chi merged 2 commits into
claude/remote-cache-auth-hook-18e511from
claude/github-oidc-auth-headers-18e511

Conversation

@wan9chi

@wan9chi wan9chi commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Motivation

The self-hosted remote cache server in #718, designed in #716, accepts uploads only with a GitHub Actions OIDC token. The token's audience must be the namespace endpoint, and it must come from a push job on the main branch. vp run sends stores without credentials today, so that server rejects every upload with 401.

Changes

  • Planning resolves remote_cache.auth to github-oidc when ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN are set in the envs visible at the vp run level. That happens in jobs with permissions: id-token: write; otherwise the auth stays anonymous.
    • It holds the request URL, the request token, and the audience, which is the endpoint without a trailing slash.
    • The request token is a Secret, which debug output and serialized plans redact.
  • build_auth turns github-oidc into vt_remote_cache::auth::GithubOidc, which adds Authorization: Bearer <token> to stores only. Fetches and downloads stay anonymous.
    • It requests a token when the first store needs one.
    • Later stores reuse the token until two minutes before its exp. Cloudflare receives a store's whole body before the Worker checks the token, so the token has to outlast the upload. A token without exp is a malformed response.
    • Concurrent stores wait for the same request.
    • A failed request is remembered, so later stores fail right away without making more requests. Each task with a failed upload shows the existing "Not uploaded to the remote cache" warning.
    • Neither token appears in debug output or errors.
    • Its state is a single enum: ready with a request and an optional cached token, or failed. A token can't stay cached after a failure.
  • Tasks still receive the two env vars as untracked envs, as in fix(env): pass through GitHub Actions OIDC variables #691, so npm trusted publishing through vp run keeps working.

Stacked on #797, which adds the Auth hook and the resolved auth config.

🤖 Generated with Claude Code

@wan9chi
wan9chi added this pull request to stack #799 October 4, 2026 07:52
@wan9chi
wan9chi force-pushed the claude/github-oidc-auth-headers-18e511 branch from 3f44ec4 to 64b0977 Compare October 4, 2026 07:52
@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

fspy benchmark

linux

dynamic/launch             change  -0.24%  [ -3.88% ..  +4.89%]  overhead  +296.90%
dynamic/access             change  -0.13%  [ -2.32% ..  +1.32%]  overhead   +13.05%
dynamic/access-relative    change  -0.10%  [ -1.47% ..  +1.86%]  overhead   +57.85%
dynamic/access-contended   change  +1.81%  [ -1.31% .. +12.97%]  overhead   +15.10%
static/launch              change  -0.39%  [ -5.23% ..  +5.47%]  overhead  +730.44%
static/access              change  +0.39%  [ -2.42% ..  +3.35%]  overhead  +783.37%
static/access-relative     change  +0.40%  [ -2.40% ..  +3.25%]  overhead +1326.76%
static/access-contended    change  -0.01%  [ -0.96% ..  +1.01%]  overhead +3125.75%

macos

dynamic/launch             change  -0.85%  [ -6.34% ..  +5.29%]  overhead  +237.14%
dynamic/access             change  +0.00%  [ -6.34% ..  +8.82%]  overhead    +3.74%
dynamic/access-relative    change  +1.38%  [-20.43% .. +103.91%]  overhead  +259.56%
dynamic/access-contended   change  +2.24%  [ -4.54% .. +13.02%]  overhead    +3.99%

windows

dynamic/launch             change  -0.31%  [ -3.57% ..  +2.76%]  overhead   +24.00%
dynamic/access             change  +0.00%  [ -1.10% ..  +1.87%]  overhead    +0.94%
dynamic/access-relative    change  +0.18%  [ -1.08% ..  +1.20%]  overhead    +1.47%
dynamic/access-contended   change  +0.00%  [ -1.37% ..  +1.76%]  overhead    +1.25%

@wan9chi
wan9chi force-pushed the claude/github-oidc-auth-headers-18e511 branch 2 times, most recently from e00a71b to 0c99de0 Compare October 4, 2026 12:42
@wan9chi
wan9chi force-pushed the claude/github-oidc-auth-headers-18e511 branch 2 times, most recently from 86869ae to 9c13e94 Compare October 5, 2026 00:51
@wan9chi
wan9chi force-pushed the claude/github-oidc-auth-headers-18e511 branch from 9c13e94 to c724b54 Compare October 5, 2026 01:00
@wan9chi
wan9chi marked this pull request as ready for review October 5, 2026 01:01
wan9chi and others added 2 commits October 5, 2026 10:09
Planning resolves `ResolvedRemoteCacheConfig::auth` to `github-oidc` when
`ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are
set. It holds the request URL, the request token, and the audience,
which is the endpoint without a trailing slash. The request token is a
`Secret`, which debug output and serialized plans redact.

`build_auth` turns it into `vt_remote_cache::auth::GithubOidc`, which adds
a GitHub Actions OIDC token to stores only. It requests a token when the
first store needs it, reuses it until two minutes before it expires,
shares one request between concurrent stores, and remembers a failed
request, so later stores fail without another one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`GithubOidc` keeps its state in one enum, so a token can't stay cached
after a failure, and invalid settings start out failed. A token without
an `exp` claim is now a malformed response, rather than being used once:
the server rejects such tokens anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wan9chi
wan9chi force-pushed the claude/github-oidc-auth-headers-18e511 branch from c724b54 to 238a29c Compare October 5, 2026 02:09
@wan9chi
wan9chi merged commit 8ecec9a into main Oct 5, 2026
19 checks passed
@wan9chi
wan9chi deleted the claude/github-oidc-auth-headers-18e511 branch October 5, 2026 02:14
@wan9chi wan9chi added the remote cache Remote caching label Nov 4, 2026
wan9chi added a commit that referenced this pull request Nov 7, 2026
…ons stand-in (#809)

## Motivation

[Vite+'s Cloudflare remote
cache](https://github.com/voidzero-dev/vite-plus-remote-cache-cloudflare)
only accepts uploads with a GitHub Actions OIDC token. The token has to
come from a push to the registered repository's main branch, and its
audience has to be the endpoint. The file backend accepted any upload,
so the e2e cases never sent a token and never exercised the client's
OIDC support from #798.

## Changes

- **GitHub Actions stand-in.** The backend process stands in for
GitHub's token service. `remote-cache-server run --github-actions` runs
a command as if in a job with `id-token: write`: it sets
`ACTIONS_ID_TOKEN_REQUEST_URL`, and `ACTIONS_ID_TOKEN_REQUEST_TOKEN`
defaults to `main-push`. The request token picks the workflow run the
token is for: `main-push` or `pull-request`.
- **Write policy.** Like the Worker, the file backend checks each
store's token: its RS256 signature against the stand-in's key, its time
bounds, its audience, and its claims. It answers other stores as the
Worker does, with `401 Invalid credentials` or `403 Write not
permitted`.
- **Uploading steps** run with `--github-actions`. The only snapshot
changes are those command lines.

Stacked on #808.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Changes are limited to test tooling (`remote-cache-server`) and e2e
fixtures; production cache client code is only invoked more
realistically in tests.
> 
> **Overview**
> Aligns the **remote-cache test backend** with production by requiring
a **GitHub Actions OIDC token** on `POST /store` (401/403 otherwise),
while **fetch/read stays unauthenticated**.
> 
> A new **`--github-actions`** flag on `remote-cache-server run`
simulates a job with `id-token: write` (`ACTIONS_ID_TOKEN_REQUEST_URL` /
default `main-push` request token). The daemon’s control server exposes
a **`/token`** endpoint that mints RS256 JWTs; **`backend.ts`** verifies
signature, time bounds, audience (endpoint), and push-to-`main` claims
before accepting stores. E2E **upload steps** and snapshot command lines
now pass **`--github-actions`** so tests exercise the client OIDC path.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a31b6bf. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

remote cache Remote caching

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant