Skip to content

Wait for complete sandbox credentials before connecting - #332455

Merged
Osvaldo Ortega (osortega) merged 3 commits into
mainfrom
osortega/sandbox-await-sealed-token
Aug 25, 2026
Merged

Wait for complete sandbox credentials before connecting#332455
Osvaldo Ortega (osortega) merged 3 commits into
mainfrom
osortega/sandbox-await-sealed-token

Conversation

@osortega

@osortega Osvaldo Ortega (osortega) commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Connecting to a freshly provisioned sandbox could leave the session unable to make authenticated requests. Nothing about it looked like a failure — the relay opened, the handshake completed, the connection registered — but every session request against it then failed.

The credentials a new environment returns can be incomplete for a short window after it comes up.

What this does

Re-mints credentials until they are complete.

The bound is derived, not guessed. It is sized to cover the backend's own registration retry cycle, so a warm environment succeeds on the first mint and never enters the loop.

It degrades rather than failing. An environment may legitimately never return the missing piece, and a session with reduced capability beats refusing to connect at all. The last credentials are used either way, and the degraded case is logged so the cause is visible rather than leaving only downstream symptoms to puzzle over.

If the environment drops back to "waking" mid-wait, the loop stops rather than re-entering the wake path; the handshake watchdog already covers a host that has gone away. A transient failure while re-minting is also non-fatal — the credentials already in hand are used instead of discarding them.

Risk

Only reachable when the initial credentials are incomplete, which is the broken case today. A warm environment takes the same path it always did.

Validation

  • npm run typecheck-client, eslint on both changed files
  • ./scripts/test.sh --glob "**/cloudSandboxAgentHostService.test.js" — 7 passing, covering: re-mint until complete, give up and connect anyway, no re-mint when the first mint is already complete, a value that is present but unusable, a failed re-mint, and the environment returning to waking mid-wait.

Each behavioural change was checked against the case it is meant to handle by reverting it and confirming the matching test fails.

Copilot AI balanced review requested due to automatic review settings August 25, 2026 00:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds bounded credential re-minting while waiting for a sealed GitHub token.

Changes:

  • Retries /connect up to 12 times.
  • Falls back to the latest credentials.
  • Adds focused unit tests.
Show a summary per file
File Description
cloudSandboxAgentHostService.ts Implements sealed-token waiting and diagnostics.
cloudSandboxAgentHostService.test.ts Tests successful, exhausted, and unnecessary retries.

Review details

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (2)

src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxAgentHostService.ts:248

  • This method JSDoc repeats implementation and failure history rather than concisely documenting the contract. Reduce it to 1–2 sentences per the repository comment guidelines.
	/**
	 * Re-mint credentials until they carry a sealed GitHub token.
	 *
	 * A newly provisioned environment answers `/connect` as soon as the compute is up, which can be
	 * before Mission Control has learned the host's sealing key. The credentials are valid, but

src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/cloudSandboxAgentHostService.test.ts:115

  • This inline comment also exceeds the one-line limit. Keep only the non-obvious reason for the + 1 expectation.
		// Bounded rather than an unbounded loop, and the connection still proceeds without a
		// sealed token. The initial mint plus one re-mint per retry.
  • Files reviewed: 2/2 changed files
  • Comments generated: 5
  • Review effort level: Balanced

Mission Control seals the user's GitHub token to a key the host generates at
startup and advertises on `register` and every heartbeat. A freshly
provisioned environment can answer `/connect` before that key has propagated,
returning credentials with no `encrypted_github_token`.

Nothing about that looks like a failure: the relay opens and the AHP
handshake completes. But without the sealed envelope the client never sends
`authenticate`, so nothing establishes who the agent acts as and the host
rejects every session request with `-32007 AuthRequired`.

Credentials are now re-minted until they carry the envelope. The bound is
sized against the daemon's own timings rather than guessed: `copilotd`
heartbeats every 30s and backs off register attempts up to 60s, so 12
attempts at 5s spans a full register backoff and two heartbeats. A warm
environment seals on the first mint and never enters the loop.

An environment may legitimately never seal a token, so this degrades rather
than failing: the last credentials are returned either way, and the degraded
case is logged where the cause is visible rather than leaving only the
downstream `AuthRequired` symptoms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The re-mint loop tested truthiness while `_establish` refuses anything that
is not a `copilot-sealed.v1.` envelope, so a non-empty plaintext value ended
the loop and left the connection unauthenticated — the state this is meant to
avoid. Both now use the same predicate.

A transient failure from the re-mint also rejected `connect()`, discarding
initial credentials that already work and contradicting the documented
degraded fallback. Non-cancellation failures are now logged and the last
token is used; only caller cancellation aborts.

Adds coverage for the unsealed value, the failed re-mint, and the
environment returning to waking mid-wait, which had no test. Trims comments
to the repository's limits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@osortega
Osvaldo Ortega (osortega) force-pushed the osortega/sandbox-await-sealed-token branch from a5d10cd to c782de0 Compare August 25, 2026 02:53
@osortega Osvaldo Ortega (osortega) changed the title Wait for the sealed GitHub token before using sandbox credentials Wait for complete sandbox credentials before connecting Aug 25, 2026
The constant documented the exact backend retry and heartbeat intervals it
was sized against, and nearby comments described how credentials become
complete. Say what the client does and why the bound is derived rather than
guessed, without publishing service internals in shipped source.

Behaviour is unchanged; comments and one log message only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@osortega
Osvaldo Ortega (osortega) marked this pull request as ready for review August 25, 2026 03:27
@osortega
Osvaldo Ortega (osortega) merged commit 15a102b into main Aug 25, 2026
27 checks passed
@osortega
Osvaldo Ortega (osortega) deleted the osortega/sandbox-await-sealed-token branch August 25, 2026 03:40
@vs-code-engineering vs-code-engineering Bot added this to the 1.136.0 milestone Aug 25, 2026
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.

3 participants