Skip to content

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

Draft
wan9chi wants to merge 1 commit into
claude/remote-cache-auth-hook-18e511from
claude/github-oidc-auth-headers-18e511
Draft

wan9chi wants to merge 1 commit 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 now resolves how requests authenticate, remote_cache.auth, along with the access mode and endpoint. It uses the envs visible at each vp run level, and the result holds everything needed to build the credentials. Nothing reads envs after planning.
    • anonymous: no credentials. This is the default.
    • github-oidc: chosen when ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN are set, which happens in jobs with permissions: id-token: write. 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.
    • Choosing the auth from cache.remote config later only changes this step.
  • vt turns the resolved auth into a vt_remote_cache auth with one match, and caches clients by endpoint and auth.
  • vt_remote_cache::auth::GithubOidc 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, because the server can take up to two minutes to finish a store.
    • 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.
  • 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.

🤖 Generated with Claude Code

@wan9chi
wan9chi added this pull request to stack #799 October 4, 2026 07:52
The plan now resolves how remote cache requests authenticate, alongside
the access mode and endpoint, into `ResolvedRemoteCacheConfig::auth`. It
holds everything needed to build the credentials, so nothing reads envs
after planning:

- `anonymous`: no credentials.
- `github-oidc`: chosen when `ACTIONS_ID_TOKEN_REQUEST_URL` and
  `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are set. Stores carry a GitHub Actions
  OIDC token whose audience is the endpoint without a trailing slash. The
  request token is a `Secret`, which debug output and serialized plans
  redact.

`vt` builds the `vt_remote_cache::auth::Auth` for a config with one match,
and caches clients by endpoint and auth. `GithubOidc` 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>
@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.86%  [ -6.04% ..  +8.67%]  overhead  +261.24%
dynamic/access             change  +0.00%  [ -1.50% ..  +1.47%]  overhead   +13.49%
dynamic/access-relative    change  +0.00%  [ -1.33% ..  +1.24%]  overhead   +61.27%
dynamic/access-contended   change  -0.12%  [ -2.50% ..  +2.28%]  overhead   +14.15%
static/launch              change  -0.07%  [ -5.24% ..  +6.19%]  overhead  +738.12%
static/access              change  -0.06%  [ -1.33% ..  +1.50%]  overhead  +811.19%
static/access-relative     change  +0.61%  [ -0.62% ..  +1.39%]  overhead +1405.65%
static/access-contended    change  -0.08%  [ -0.88% ..  +0.68%]  overhead +3197.72%

macos

dynamic/launch             change  +0.27%  [ -3.12% ..  +3.90%]  overhead  +219.69%
dynamic/access             change  -0.36%  [-10.34% ..  +7.39%]  overhead    +2.64%
dynamic/access-relative    change  -0.20%  [ -6.28% ..  +8.78%]  overhead  +259.98%
dynamic/access-contended   change  -1.09%  [ -8.25% ..  +2.26%]  overhead    +3.77%

windows

dynamic/launch             change  -0.36%  [ -2.68% ..  +2.70%]  overhead   +25.16%
dynamic/access             change  +0.38%  [ -0.92% ..  +1.31%]  overhead    +1.33%
dynamic/access-relative    change  +0.00%  [ -0.74% ..  +1.30%]  overhead    +1.33%
dynamic/access-contended   change  +0.53%  [ -4.99% ..  +4.94%]  overhead    +2.11%

This branch has not been deployed

No deployments
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