@@ -60,7 +60,9 @@ identifies the calling binary, checks trust-on-first-use binary identity, reject
6060unsafe internal destinations, and evaluates the active policy. On Linux, it
6161maps an accepted proxy connection back to the workload socket by matching the
6262complete local-to-remote TCP tuple before resolving every process that owns the
63- socket inode.
63+ socket inode. If fork or descriptor passing creates multiple owners, they must
64+ have compatible policy identities; the proxy denies ambiguous shared ownership
65+ before middleware evaluation or upstream connection.
6466
6567CONNECT and absolute-form forward HTTP are explicit-proxy adapters over the same
6668egress pipeline. Each adapter normalizes its request into an egress intent, and
@@ -374,20 +376,69 @@ Provider profiles can also declare dynamic token grants. For matching HTTP
374376endpoints, the supervisor obtains or exchanges OAuth2 access tokens, caches
375377them, and injects them before forwarding the request. ` client_credentials `
376378grants use the supervisor SPIFFE JWT-SVID directly as the client assertion.
377- ` token_exchange ` grants ask the gateway to broker an intermediate token using a
378- stored provider subject credential and the gateway's own SPIFFE JWT-SVID; the
379- supervisor then exchanges that intermediate token for the final upstream token
380- using its own JWT-SVID. The gateway validates that its own JWT-SVID has the
379+ ` token_exchange ` grants ask the gateway to broker an intermediate token using
380+ either a stored provider subject credential or the sandbox creator's delegated
381+ OIDC identity, plus the gateway's own SPIFFE JWT-SVID; the supervisor then
382+ exchanges that intermediate token for the final upstream token using its own
383+ JWT-SVID. Delegated identity is opt-in at sandbox creation. The CLI first checks
384+ for a usable gateway-owned credential for the authenticated user. When one is
385+ missing, revoked, or no longer refreshable, the CLI runs a separate device
386+ authorization and transfers its token bundle to the gateway without replacing
387+ the normal CLI login. Sandbox create and extend then send only a per-sandbox
388+ duration; the gateway derives the absolute authorization window from its own
389+ clock. Delegated access and refresh tokens live behind opaque
390+ handles in the gateway's active credential driver; the generic credential and
391+ sandbox records never contain their bytes. Rotation stages replacement handles
392+ before updating metadata and uses a shared-store CAS lease so gateway replicas
393+ cannot submit the same refresh token concurrently. Revocation disables
394+ resolution before cleanup, and deletion retains a disabled tombstone until
395+ cleanup completes. Within one gateway process, sandbox creation and delegation
396+ extension share the gateway-wide state guard with credential deletion so a
397+ credential cannot be deleted between its active-reference check and a new
398+ delegation write. Like the gateway's other cross-object state guards, this
399+ coordination is process-local pending DB-backed multi-writer synchronization.
400+ Only the delegating user can
401+ extend or withdraw that window. Only the delegator can start or interact with
402+ the sandbox. Workspace and platform admins can stop it for containment or
403+ delete it to recover resources, but cannot start it. Other workspace users
404+ cannot start, stop, delete, or interact with it. Ordinary sandboxes retain the
405+ workspace role model. These ownership restrictions govern direct sandbox access,
406+ not confidentiality against configuration administrators. Exchanges load the
407+ current provider profile; delegation does not pin its exchange configuration.
408+ Workspace admins can change workspace-scoped custom profiles, including the
409+ token endpoint, and redirect a subsequent exchange. The gateway sends the raw
410+ delegated access token as the subject token, not the delegated refresh token or
411+ normal CLI login credentials. Both provider-credential and delegated-identity
412+ subject-token paths therefore trust administrators who control exchange
413+ configuration with their subject tokens.
414+ The gateway rejects requests whose authorization checks
415+ observe delegation expiry, withdrawal, missing credential state, or credential
416+ revocation. Withdrawal is not instantaneous containment. Already-authorized
417+ refreshes or exchanges may finish and populate token caches. Provider profile
418+ lowering trims surrounding whitespace from subject-token source and credential
419+ identifiers before the gateway resolves them with exact matching.
420+ The gateway validates that its own JWT-SVID has the
381421requested audience, a SPIFFE subject, and a non-expired ` exp ` claim when
382- present. It also validates that the stored subject credential is declared by the
383- provider profile, and that the supervisor JWT-SVID is a well-formed
422+ present. For provider-credential subject tokens, it also validates that the
423+ stored subject credential is declared by the provider profile. For delegated
424+ identity subject tokens, it validates that the sandbox was created with active
425+ delegation for the stored credential principal. The gateway also verifies that
426+ the supervisor JWT-SVID is a well-formed
384427three-segment JWT with a SPIFFE subject in the same trust domain as the gateway
385428SVID. The gateway verifies the supervisor JWT-SVID signature with JWT bundles
386429fetched from its SPIFFE Workload API. Token grant endpoints are HTTPS-only
387430except for loopback and Kubernetes service DNS hosts, and returned access tokens
388- must be bearer-compatible before they are cached or injected. Token response
431+ must be bearer-compatible before they are cached or injected. Delegated OIDC
432+ discovery and refresh use a dedicated 30-second HTTP client that ignores ambient
433+ proxy settings and rejects redirects. Token response
389434lifetimes are capped and cached with an expiry margin unless a profile supplies
390- an explicit cache TTL override. Cache entries are scoped by the sandbox provider
435+ an explicit cache TTL override. Every ` token_exchange ` cache entry, including
436+ an override, is capped at five minutes from insertion. This limits reuse of each
437+ entry, not elapsed time from delegation withdrawal or credential revocation;
438+ in-flight exchanges can populate caches afterward. Response-derived entries
439+ apply the 30-second margin after that cap and therefore live for at most four
440+ minutes and 30 seconds. This bound does not invalidate an access token that an upstream
441+ service has already received. Cache entries are scoped by the sandbox provider
391442environment revision so provider credential updates miss the old token cache
392443without changing endpoint matching semantics. Gateway-brokered intermediate
393444tokens are cached separately by provider resource version, supervisor SPIFFE
0 commit comments