Repository navigation
git-remote-entire: migrate the ENTIRE_TOKEN (CI) path to jurisdiction tokens - #1622
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR migrates the ENTIRE_TOKEN (CI / workload identity) authentication path in git-remote-entire from per-(repo,action) repo-scoped token exchange to jurisdiction identity tokens, aligning it with the interactive auth model and removing the hot-path exchange cost in CI.
Changes:
- Switch the env-token (
ENTIRE_TOKEN) flow to mint jurisdiction identity tokens (in-process memo only; no keychain). - Simplify the credential plumbing by removing the
tokenSourceabstraction and dropping unused repo-scoped parameters. - Extend cluster discovery to return the full discovery entry (cores + jurisdiction audience/core) for the env-token trust gate.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/entireclient/clusterdiscovery/resolve.go | Updates ResolveClusterCores to return the full discovery entry needed by the env-token path. |
| cmd/git-remote-entire/main.go | Migrates env-token auth to identity tokens, removes repo-scoped plumbing, and adjusts credential attachment gating. |
| cmd/git-remote-entire/main_test.go | Updates the well-known stub and adds tests validating env-token identity token behavior and fail-closed upgrade hint. |
| cmd/git-remote-entire/identityauth.go | Adds the env-token identity-token source variant (pinned core, no persistence) and updates token acquisition API. |
| cmd/git-remote-entire/identityauth_test.go | Updates call sites for the new Token(ctx) signature and adds coverage for the env pinned-core path and non-persistence. |
Contributor
Author
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 17b1dcd. Configure here.
toothbrush
force-pushed
the
paul/cor-847-env-token-identity
branch
from
July 3, 2026 05:10
17b1dcd to
ebab5cf
Compare
… tokens The env-token path was the last client of the repo-scoped exchange, paying it per (repo, action) on every git command. It now mints one jurisdiction token at the token's own trust-gated core, using the cluster's advertised jurisdiction_audience — in-memory only, no keychain on CI runners; Invalidate (the 401 observer) drops just the memo (COR-847). Because clusters advertise every jurisdiction's cores, a token minted at a sibling core passes the trust gate but its exchange is refused with an opaque invalid_target. Pre-compute the actionable hint at resolve time — 'point your CI auth url at <jurisdiction core>' — and append it to the exchange failure. Hint, not a pre-flight error: clusters may advertise several same-jurisdiction core URLs, so URL inequality is a strong signal, not proof. With repocreds gone from this binary, the tokenSource seam collapses: both paths return *jurisdictionTokenSource and Token() drops its ignored (repo, action) params. ResolveClusterCores returns the full discovery entry and adopts the audience-requiring cache semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
toothbrush
force-pushed
the
paul/cor-847-env-token-identity
branch
from
July 4, 2026 02:13
ebab5cf to
f45fcb7
Compare
Soph
approved these changes
Jul 4, 2026
timothybrush
pushed a commit
to timothybrush/cli-2
that referenced
this pull request
Sep 15, 2026
fatalMessage special-cased an RFC 8693 invalid_target error whose description named the cluster actually serving the repo, turning it into "this repository is not hosted on X; it lives on Y" plus a corrected clone command. Nothing can produce that error any more, so the branch has never been reachable in main. It was added in entireio#1575 (2026-06-30), built on the repo-scoped token exchange the helper performed at the time. entireio#1621 removed that exchange for the interactive path — merged 2026-07-03 05:17, six hours BEFORE entireio#1575 merged at 11:22 — and entireio#1622 migrated the ENTIRE_TOKEN path the next morning. Both PRs were the same author's; neither conflicted with entireio#1575 in any file, so nothing flagged it. The helper now presents a jurisdiction token as a bearer and never exchanges, so no invalid_target is ever returned to it. Measured rather than reasoned. Cloning a single-placement repo from the wrong cluster, against a helper built from main: $ git clone entire://aws-eu-central-1.entire.io/gh/entireio/cli-perf-benchmarks fatal: stateless-connect v2 info/refs: Repository not found with ENTIRE_DEBUG showing the wire: GET /gh/entireio/cli-perf-benchmarks/info/refs?service=git-upload-pack HTTP/1.1 404 Not Found Repository not found A plain 404 with a four-word body: no invalid_target, no error_description, nothing naming the correct host. The same repo on its own cluster clones fine with the same credentials, so that 404 is the wrong-cluster response rather than an access failure. So this is not repairable here. The 404 carries no information about where the repo lives, and no client-side matcher can invent it. Restoring the UX needs the data plane to say so on that response — worth noting the helper already looks for an X-Entire-Replicas header there and logs its absence, so the mechanism may partly exist. Filed separately; this commit only removes code that cannot run. TestFatalMessage went with it. It passed throughout by constructing the invalid_target error itself, which verified the formatting and could never observe that the input had no producer — the reason a dead branch survived two years of green CI. fatalMessage reduced to a single Sprintf with one caller, so it is inlined rather than kept as a seam. If the hint returns it will match a 404 body, not an OAuth error, and would not reuse this shape. Verified: identical stderr before and after (the point of the change), lint clean, GOOS=windows vet clean, helper and remotehelper suites pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 01M2863QYHMEQG3P93TAGG0FGW
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Stacked on #1621. Fixes COR-847.
Why
The
ENTIRE_TOKEN(CI / Buildkite) path was the last client of the repo-scoped exchange, paying it per (repo, action) on every git command — that's also happening in CI.What
resolveEnvTokenCredsnow mints a jurisdiction access token instead of building arepocreds.Cache: audience = the cluster's advertisedjurisdiction_audience, exchanged at the core derived from the token'saudclaim (unchanged trust gate against the cluster's advertised core set). A cluster advertising nojurisdiction_audiencefails closed with the same upgrade hint as the interactive path (sharedmissingJurisdictionAudienceErr).home_jurisdictionclaim to route by) and never touches the OS keychain — in-process memo only;Invalidate()(the 401 observer) drops just the memo.*jurisdictionTokenSource, so thetokenSourceinterface, the repocreds dependency in git-remote-entire, and the unusedclusterBaseURLplumbing are gone.Token()drops its ignored (repo, action) params; the smart-HTTP endpoint classification stays as the credential-attachment gate.clusterdiscovery.ResolveClusterCoresreturns the full discovery entry and adopts the audience-requiring cache semantics (pre-audience entries refetched, no audience-less stale fallback) — its sole caller is now audience-requiring.Verified server-side that the exchange gates hold for CI subjects: sa-session tokens carry
LoginScopes⊇entire:session(passesvalidateIdentityExchange), haveaud == iss, and are explicitly carved out of the fid-liveness gate. No entiredb change needed.Follow-up
validateRepoExchangeserver-side once nothing mints repo-scoped tokens (needs a released helper + bumped Buildkite plugin pin).Tests
go test ./...green; new tests: env source pins the token's core, mints in-memory only (no token-store writes, memo-only Invalidate), missingjurisdiction_audiencefails closed.🤖 Generated with Claude Code
Note
Medium Risk
Changes authentication for all CI git operations and removes the repo-scoped fallback; clusters without jurisdiction_audience will fail until upgraded, but the existing ENTIRE_TOKEN trust gate and fail-closed behavior are preserved.
Overview
CI /
ENTIRE_TOKENauth now uses jurisdiction access tokens instead of per-(repo, action) repo-scoped exchanges, so Buildkite-style runners pay one exchange per process (memoized) rather than on every git command.resolveEnvTokenCredsbuildsnewEnvJurisdictionTokenSource: exchange at the trust-gated core from the token’saud, audience from clusterjurisdiction_audience, pinned core (nohome_jurisdictionon sa-session JWTs), and no OS keychain—only in-process cache;Invalidateon 401 clears the memo only. Missingjurisdiction_audiencefails closed via sharedmissingJurisdictionAudienceErr(no repo-scoped fallback).Both interactive and env paths return
*jurisdictionTokenSource;repocredsandtokenSourceare removed,Token(ctx)no longer takes repo/action (smart-HTTP classification still gates where Bearer is attached).ResolveClusterCoresreturns the full discovery entry and uses audience-required cache semantics for the env path.Tests cover pinned core routing, in-memory-only env minting, and missing-audience rejection.
Reviewed by Cursor Bugbot for commit 17b1dcd. Configure here.