Repository navigation
Add sandbox secrets - #129
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NhbFMc29f5JN5JxCciajJV
AHarmlessPyro
marked this pull request as ready for review
October 12, 2026 02:43
- A sandbox create with secrets whose outcome is unknown throws a non-retryable secret_process_outcome_unknown: a sandbox may be running its startup command with the secrets. - Normalize the server's SECRET_PROCESS_OUTCOME_UNKNOWN to the documented code, keeping the server body in details. - Add the sandbox and secret context to control error messages, as the CLI does. - Without a server retryable flag, SECRETS_NOT_CONFIGURED is not retryable. - Send secret process timeouts as whole milliseconds within the server's 24-hour limit. - containsSecrets is always a boolean on sandboxes and snapshots. - Check secret names, versions, list bounds and gvisor-cpu with secrets locally. - Document SECRETS_FEATURE_DISABLED, SECRETS_NOT_CONFIGURED and SECRET_STARTUP_UNSUPPORTED. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 357b0d4. Configure here.
AHarmlessPyro
enabled auto-merge
October 12, 2026 08:42
AHarmlessPyro
disabled auto-merge
October 12, 2026 08:43
NikhilShahi
approved these changes
Oct 12, 2026
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.

Adds sandbox secrets to the SDK, mirroring the
hx vm secretsCLI in metlo-labs/browserctrl#1519. Only API-key routes are used. This needs the server's secrets stack, which ends in that PR.client.secretssecrets.readalongsidesecrets.manage, even for known IDs, because the SDK resolves metadata and encryption context. Creation needs onlysecrets.manage.encryptionContext, and the API only receives the envelope.kid, or the SDK refuses to encrypt.crypto, with no new dependencies.createwith a value checks the value and the key before creating the secret, so a bad value or an unusable key never leaves an empty secret behind. If the upload fails after the create, the error has codesecret_value_not_stored, carries the secret indetails, and says to useaddVersion. Retryingcreatewould fail with "name taken".Delivering secrets
processes.start/execwithsecretscallPOST /api/sandbox/:id/processes, so the sandbox service decrypts the values. They send only the fields that endpoint accepts:timeoutSecbecomestimeoutMs, andrunAsis passed through.execcloses stdin, ignoring a 409 from a command that already exited. Secret-started handles andexecwait through the runtime in chunks below the request timeout, including sub-second client budgets. An expired receiver wait (408) means the command is still running.wait()/result()have no default local deadline; an explicit wait timeout bounds the whole local wait, closes its active request, and leaves the handle usable. Existing reattached-handle behavior is preserved. Output comes from retained output, somaxOutputBytesdoes not apply.timeoutSectakes precedence overtimeoutMs, matching ordinary process starts.secret_process_outcome_unknownwithretryable: false, because the command may be running. So does a start response without a process ID. Connection failures and API errors pass through unchanged. A failure after the start givessecret_process_failed, with theprocessIdindetails.envandsecrets.secretsgo to the image's startup command. They're allowed only for image launches, both in the type and at runtime.containsSecretshas been added to sandboxes and snapshots.Control API errors (all requests)
retryableflag in an error body overrides the status-based default. For example, an ambiguous secret process start is a 502 withretryable: false.errornext to amessage(for exampleAPI_KEY_SCOPE_DENIED) becomeserror.code. The full body, includingrequiredScopes,sandboxId,causeCode,exitCodeand the secretdetails, stays inerror.detailsas before.Testing
kid, 2048-bit keys, the wrong exponent and the wrong algorithm are refused.create, and a partial create.secretsserialize, and snapshot rejection.retryableand the code inerror.🤖 Generated with Claude Code
https://claude.ai/code/session_01NhbFMc29f5JN5JxCciajJV
Note
High Risk
Introduces secret storage encryption, delivery into sandbox processes, and subtle non-retry error semantics where duplicate starts could leak credentials or leave orphan workloads.
Overview
Adds
client.secretsfor team secret lifecycle (create, versions, list/get metadata, delete) with client-side JWE encryption to the platform public key so plaintext values never hit the API.Sandboxes can receive secrets as env vars via
secretsonsandboxes.create(image startup only) and onprocesses.exec/processes.start, which route starts through the control API instead of the runtime SSE path. Handles expose delivered versions onhandle.secrets; sandboxes/snapshots gaincontainsSecrets.Secret starts change wait/exec semantics: output comes from retained runtime waits (chunked, no
maxOutputBytes), with explicit handling for non-retryablesecret_process_outcome_unknownwhen creates/starts may have succeeded anyway. Control-layer errors gainResponseDecodingError, serverretryableoverrides, and richer messages for sandbox/secret context.README documents usage, limits, and scopes; unit and HTTP integration tests cover envelopes, resolution, and recovery paths.
Reviewed by Cursor Bugbot for commit 3a60a56. Bugbot is set up for automated code reviews on this repo. Configure here.