Skip to content

feat(sandbox): add OpenShell sandbox provider - #2013

Merged
bxyu-nvidia merged 4 commits into
mainfrom
hemil/openshell-sandbox-provider
Jul 29, 2026
Merged

feat(sandbox): add OpenShell sandbox provider#2013
bxyu-nvidia merged 4 commits into
mainfrom
hemil/openshell-sandbox-provider

Conversation

@hemildesai

Copy link
Copy Markdown
Contributor

Summary

Adds a built-in sandbox provider for OpenShell, a policy-enforced sandbox runtime for autonomous agents. The provider drives an OpenShell gateway's gRPC control plane through the synchronous openshell SDK (new optional dep in the sandbox extra), running blocking SDK calls on a thread pool bounded by exec.concurrency.

Provider mapping

SandboxProvider method OpenShell
create CreateSandbox + async READY-phase poll + exec readiness probe; metadata → gateway labels, resources.gpu → GPU requirements, provider_options.providers → OpenShell credential providers
exec streaming ExecSandbox as <shell> -c <cmd> with server-enforced timeout; DEADLINE_EXCEEDEDerror_type=timeout, other RPC/SDK failures → error_type=sandbox
upload_file / download_file the SDK has no file-transfer API: upload streams bytes via exec stdin (mkdir -p && cat), download round-trips through base64 stdout (binary-safe)
status GetSandbox phase mapping (NOT_FOUNDSTOPPED)
close / aclose DeleteSandbox + poll until gone / close channel + shut down pool

Documented caveats (see the provider README): no ttl_s enforcement (warns), no entrypoint (raises), exec(user=...) ignored with a warning (no user field in the exec API; sandboxes run as a non-root user).

Testing

  • tests/unit_tests/test_openshell_provider.py: 60 tests against a fake SDK client (spec/label mapping, ready polling, probe retry/cleanup, exec error taxonomy, upload/download round-trip, phase mapping, close/wait-deleted, config validation). All pass; guarded by pytest.importorskip('openshell').
  • Live end-to-end against a local gateway (ghcr.io/nvidia/openshell/gateway:latest, docker compute driver on colima), exercising the full AsyncSandbox surface: create/READY/probe, exec stdout + exit codes, spec.env / per-exec env / workdir / cwd override, spec.files upload at start, 256 KiB binary upload→sha256→download round-trip, server-enforced exec timeout (exit 124), status, delete cleanup — 11/11 checks pass.
  • Note: the gateway latest image requires [openshell.gateway.gateway_jwt] signing keys plus [openshell.gateway.auth] allow_unauthenticated_users = true for local plaintext use — the compose gateway.toml in the OpenShell repo doesn't include these yet; the provider README's quickstart points at OpenShell's deploy docs.
  • Full core unit suite: 1202 passed; the 6 failures (test_benchmarks/test_cli_utils/test_config_types_help) are pre-existing ANSI/terminal-formatting assertions that fail identically on main.

🤖 Generated with Claude Code

Adds a built-in sandbox provider for OpenShell (github.com/NVIDIA/OpenShell),
a policy-enforced sandbox runtime for autonomous agents. The provider drives
an OpenShell gateway's gRPC control plane through the synchronous openshell
SDK, running blocking calls on a bounded thread pool.

- create: CreateSandbox + async READY-phase poll + exec readiness probe;
  spec.metadata maps to gateway labels, resources.gpu to GPU requirements,
  provider_options.providers to OpenShell credential providers
- exec: streaming ExecSandbox as '<shell> -c <cmd>' with server-enforced
  timeout; gRPC DEADLINE_EXCEEDED -> error_type=timeout, other RPC/SDK
  failures -> error_type=sandbox (never raises for command failure)
- upload/download: the SDK has no file-transfer API, so uploads stream
  bytes through exec stdin (mkdir -p && cat) and downloads round-trip
  through base64 on stdout (binary-safe)
- status: sandbox phase mapping (NOT_FOUND -> STOPPED)
- close: DeleteSandbox + poll until gone; aclose closes the channel

Verified end-to-end against a local gateway (ghcr.io gateway image, docker
compute driver, colima): create/ready/probe, exec stdout/exit codes/env/
workdir/timeout, spec.files upload, binary upload/download round-trip,
status, and delete cleanup all pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Hemil Desai <hemild@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@cwing-nvidia cwing-nvidia linked an issue Jul 17, 2026 that may be closed by this pull request
5 tasks
@hemildesai
hemildesai marked this pull request as ready for review July 29, 2026 05:55
@hemildesai
hemildesai requested a review from a team as a code owner July 29, 2026 05:55
@anwithk
anwithk requested a review from ananthsub July 29, 2026 15:58
Comment thread pyproject.toml Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py
Comment thread nemo_gym/sandbox/providers/openshell/provider.py
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py Outdated
Comment thread nemo_gym/sandbox/providers/openshell/provider.py
hemildesai and others added 2 commits July 29, 2026 11:17
…ed client/pool, policy passthrough

Addresses ananthsub's review on #2013:

- openshell>=0.0.92,<0.1: pass the now-required 'workspace' kwarg on every
  lifecycle call (configurable via connection.workspace, default 'default');
  upper bound because the alpha SDK and its private _proto are load-bearing.
  A new SDK-conformance test binds the provider's exact call shapes against
  the installed SDK so signature drift fails unit CI even with fakes; the
  fakes now enforce 0.0.92 signatures and return real SandboxRef objects.
- share one SandboxClient + worker pool per connection config at module
  scope (refcounted; released on the last aclose), so per-sandbox provider
  instances no longer allocate a 32-thread pool and gRPC channel each.
  aclose stops workers (cancel_futures) before closing the channel.
- create: only runtime failures are wrapped as OpenShellCreateError
  (programming errors like TypeError propagate); transient RPC failures
  (UNAVAILABLE/RESOURCE_EXHAUSTED/ABORTED/DEADLINE_EXCEEDED) retried with
  backoff reusing the sandbox name, ALREADY_EXISTS recovered via GetSandbox;
  _wait_ready treats DELETING as terminal; failed cleanup logs a leak
  warning; marker label applied last so user metadata cannot clobber it.
- provider_options validated via OpenShellProviderOptions (unknown keys
  raise); new escape hatches: policy (SandboxPolicy mapping or YAML path),
  template_resources / driver_config (SandboxTemplate Struct passthroughs);
  resources warning reworded to point at template_resources.
- close gates the deletion wait on DeleteSandbox's returned bool.
- uploads chunked at exec.upload_chunk_bytes (512 KiB default — live gateway
  rejects gRPC messages over 1 MiB; verified with a 5 MiB upload); download
  buffering documented. Exec env values coerced to str at the boundary.
- probe backoff stable_delay_s defaults to 1.0 and is set in the shipped
  YAML; exec.concurrency semantics (shared pool, unbounded queue) documented;
  missing SDK raises ModuleNotFoundError matching other providers; phase
  mapping built from openshell_pb2 constants instead of hardcoded ints.

Verified live against a local gateway: 11/11 smoke checks plus a 5 MiB
chunked upload round-trip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Hemil Desai <hemild@nvidia.com>
Signed-off-by: Hemil Desai <hemild@nvidia.com>
@bxyu-nvidia
bxyu-nvidia merged commit 242433e into main Jul 29, 2026
16 checks passed
@bxyu-nvidia
bxyu-nvidia deleted the hemil/openshell-sandbox-provider branch July 29, 2026 22:35
OlegSudakov pushed a commit to OlegSudakov/Gym that referenced this pull request Aug 7, 2026
## Summary

Adds a built-in sandbox provider for
[OpenShell](https://github.com/NVIDIA/OpenShell), a policy-enforced
sandbox runtime for autonomous agents. The provider drives an OpenShell
gateway's gRPC control plane through the synchronous `openshell` SDK
(new optional dep in the `sandbox` extra), running blocking SDK calls on
a thread pool bounded by `exec.concurrency`.

### Provider mapping

| `SandboxProvider` method | OpenShell |
|---|---|
| `create` | `CreateSandbox` + async READY-phase poll + exec readiness
probe; `metadata` → gateway labels, `resources.gpu` → GPU requirements,
`provider_options.providers` → OpenShell credential providers |
| `exec` | streaming `ExecSandbox` as `<shell> -c <cmd>` with
server-enforced timeout; `DEADLINE_EXCEEDED` → `error_type=timeout`,
other RPC/SDK failures → `error_type=sandbox` |
| `upload_file` / `download_file` | the SDK has no file-transfer API:
upload streams bytes via exec stdin (`mkdir -p && cat`), download
round-trips through `base64` stdout (binary-safe) |
| `status` | `GetSandbox` phase mapping (`NOT_FOUND` → `STOPPED`) |
| `close` / `aclose` | `DeleteSandbox` + poll until gone / close channel
+ shut down pool |

Documented caveats (see the provider README): no `ttl_s` enforcement
(warns), no `entrypoint` (raises), `exec(user=...)` ignored with a
warning (no user field in the exec API; sandboxes run as a non-root
user).

## Testing

- `tests/unit_tests/test_openshell_provider.py`: 60 tests against a fake
SDK client (spec/label mapping, ready polling, probe retry/cleanup, exec
error taxonomy, upload/download round-trip, phase mapping,
close/wait-deleted, config validation). All pass; guarded by
`pytest.importorskip('openshell')`.
- Live end-to-end against a local gateway
(`ghcr.io/nvidia/openshell/gateway:latest`, docker compute driver on
colima), exercising the full `AsyncSandbox` surface: create/READY/probe,
exec stdout + exit codes, `spec.env` / per-exec env / `workdir` / cwd
override, `spec.files` upload at start, 256 KiB binary
upload→sha256→download round-trip, server-enforced exec timeout (exit
124), status, delete cleanup — **11/11 checks pass**.
- Note: the gateway `latest` image requires
`[openshell.gateway.gateway_jwt]` signing keys plus
`[openshell.gateway.auth] allow_unauthenticated_users = true` for local
plaintext use — the compose `gateway.toml` in the OpenShell repo doesn't
include these yet; the provider README's quickstart points at
OpenShell's deploy docs.
- Full core unit suite: 1202 passed; the 6 failures
(`test_benchmarks`/`test_cli_utils`/`test_config_types_help`) are
pre-existing ANSI/terminal-formatting assertions that fail identically
on `main`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Hemil Desai <hemild@nvidia.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

feat(sandbox): OpenShell sandbox provider

3 participants