Skip to content

refactor(cache): let remote cache requests carry auth headers - #797

Merged
wan9chi merged 1 commit into
mainfrom
claude/remote-cache-auth-hook-18e511
Oct 5, 2026
Merged

wan9chi merged 1 commit into
mainfrom
claude/remote-cache-auth-hook-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, serves reads to anyone but accepts a store only with a GitHub Actions OIDC token. Other servers will need other credentials. For example, a private cache behind Cloudflare Access could need headers on every request. This adds one general hook so each kind of credentials is a separate implementation, and the client doesn't need to know about any of them.

Changes

  • vt_remote_cache::auth::Auth supplies the headers for each request, given its operation: fetch, download, or store. It can use the client's HTTP client to get credentials, such as a token, and that client doesn't follow redirects. If it fails, the request isn't sent, and the operation fails with the new Error::Auth ("failed to authenticate").
  • Client::new(endpoint, auth) takes the auth. Anonymous adds no headers.
  • Planning resolves how requests authenticate into remote_cache.auth, next to the access mode and endpoint. The result holds everything needed to build the credentials, so nothing reads envs after planning. Choosing the auth from cache.remote config or envs later only changes this step. For now, the only kind is anonymous.
  • vt turns the resolved auth into a vt_remote_cache auth with build_auth, a single match, and caches clients by endpoint and auth.

Requests don't change. Plan snapshots gain "auth": {"kind": "anonymous"}. The next PR in this stack adds GitHub Actions OIDC as the first auth with credentials.

🤖 Generated with Claude Code

@wan9chi
wan9chi added this pull request to stack #799 October 4, 2026 07:52
@wan9chi wan9chi changed the title claude/remote cache auth hook 18e511 refactor(cache): let remote cache requests carry auth headers Oct 4, 2026
@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

fspy benchmark

linux

dynamic/launch             change  -0.45%  [-13.18% .. +10.59%]  overhead  +311.61%
dynamic/access             change  +2.45%  [-11.74% .. +20.73%]  overhead   +18.24%
dynamic/access-relative    change  +1.87%  [ -5.10% .. +25.80%]  overhead   +66.86%
dynamic/access-contended   change  +2.43%  [-12.39% .. +12.47%]  overhead    -0.06%
static/launch              change  +1.67%  [ -9.20% .. +13.16%]  overhead  +645.35%
static/access              change  -0.06%  [ -2.45% ..  +1.42%]  overhead +1445.06%
static/access-relative     change  -0.45%  [ -2.16% ..  +0.91%]  overhead +1882.99%
static/access-contended    change  -0.91%  [ -3.36% ..  +0.91%]  overhead +1599.27%

macos

dynamic/launch             change  -0.10%  [ -6.36% ..  +5.38%]  overhead  +232.73%
dynamic/access             change  -1.08%  [ -5.65% ..  +4.13%]  overhead    +4.19%
dynamic/access-relative    change  +0.60%  [-18.71% .. +33.08%]  overhead  +248.55%
dynamic/access-contended   change  -0.26%  [-20.47% .. +26.83%]  overhead    +3.12%

windows

dynamic/launch             change  -2.98%  [ -9.74% ..  +5.65%]  overhead   +23.50%
dynamic/access             change  +1.11%  [ -5.47% .. +20.42%]  overhead    +2.59%
dynamic/access-relative    change  +0.35%  [ -1.41% ..  +1.84%]  overhead    +1.66%
dynamic/access-contended   change  +0.00%  [ -1.59% ..  +2.14%]  overhead    +0.90%

@wan9chi
wan9chi force-pushed the claude/remote-cache-auth-hook-18e511 branch 3 times, most recently from 8d5ee03 to 4a5fbc9 Compare October 5, 2026 01:00
@wan9chi
wan9chi marked this pull request as ready for review October 5, 2026 01:00
`vt_remote_cache::Client::new` now takes an `Auth`, which supplies the
headers for each request by operation (fetch, download, or store). It can
use the client's HTTP client to get credentials, and when it fails, the
request isn't sent and the operation fails with `Error::Auth`.

The plan resolves how requests authenticate into
`ResolvedRemoteCacheConfig::auth`, which holds everything needed to build
the credentials, so nothing reads envs after planning. `vt` builds the
`Auth` for it with `build_auth` and caches clients by endpoint and auth.
The only kind is `anonymous`, which adds no headers, so requests are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wan9chi
wan9chi force-pushed the claude/remote-cache-auth-hook-18e511 branch from 4a5fbc9 to a7223e8 Compare October 5, 2026 02:09
@wan9chi
wan9chi merged commit f552002 into main Oct 5, 2026
19 checks passed
@wan9chi
wan9chi deleted the claude/remote-cache-auth-hook-18e511 branch October 5, 2026 02:14
wan9chi added a commit that referenced this pull request Oct 5, 2026
…DC (#798)

## 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 #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](https://claude.com/claude-code)

---------

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant