Skip to content

Add the openshell provider: sandboxes on an NVIDIA OpenShell gateway - #1293

Merged
cdalar merged 1 commit into
mainfrom
ai/openshell-provider
Nov 3, 2026
Merged

cdalar merged 1 commit into
mainfrom
ai/openshell-provider

Conversation

@cdalar

@cdalar cdalar commented Nov 3, 2026

Copy link
Copy Markdown
Owner

Adds -p openshell: onctl manages sandboxes on an NVIDIA OpenShell gateway through its Go SDK (sdk/go v0.1.6). The gateway enforces its policy: outbound connections are denied by default, and credentials stay out of the sandbox.

# a gateway on any VM (onctl-templates#46, merged)
onctl create -n openshell --image ubuntu-24.04 -a openshell/openshell.sh
# register it with the openshell CLI as the template prints, then
onctl create -p openshell -n my-sandbox
onctl ssh -p openshell my-sandbox

How it works

  • Gateway config: onctl has no gateway settings of its own. It uses the gateways the openshell CLI registered (openshell.gateway in onctl.yaml, or the CLI's active gateway). The SDK's loader (gateway.NewClient) doesn't support mTLS, which a self-hosted gateway uses by default, so internal/provideropenshell builds that client from the CLI's mtls/ bundle.
  • SSH: a sandbox has no address, so SSH goes through the gateway's relay. DialVM opens SSH().Tunnel (other ports use TCP().Forward) and wraps it in a net.Conn via net.Pipe, so the ssh handshake deadline works.
    • The stream outlives the dial's context. tools.Remote cancels that context as soon as the dial returns, and the SDK would otherwise close the stream with it.
    • onctl ssh's ProxyCommand passes the gateway and workspace to ssh-proxy (hidden flags), so the proxy reaches the same gateway as the command that started it.
  • Pause/resume: these are the sandbox's stop/start, and files are kept. ssh and DialVM start a stopped sandbox first.
  • Like boxes, it works without an onctl.yaml (configOptional).

What doesn't apply, and is refused up front with an explanation

  • -a, --upload/--download and cloud-init. Sandboxes run unprivileged (no root, no sudo), and the relay has no SFTP. Software comes from --image.
  • --domain. A sandbox has no address.
  • onctl claude. It needs root, file transfer, and a policy that lets Claude reach its API. That's a follow-up.

Tested

Against a gateway from the onctl-templates openshell template (Hetzner ccx13, Ubuntu 24.04, OpenShell 0.1.6):

  • create in about 2 s, including the SSH readiness check through the relay
  • ls, and ssh <name> -- cmd
  • system ssh with ssh-proxy as ProxyCommand
  • pause -f: the sandbox shows as paused, and ssh starts it again
  • a file kept across pause/resume
  • destroy
  • -a refused before anything is created
  • the claude guard fires before the provider connects

Unit tests use in-memory fakes: deploy image fallback, list order and status mapping, pause/resume calls, DialVM routing (22 → SSH relay, others → TCP forward), the stream outliving a cancelled dial context, auto-start of a stopped sandbox, ProxyCommand quoting, gateway-loading errors and the create/ssh checks. go test ./... passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ba6Vc6jJ1yfnNCkExeDWHh

onctl create/ls/ssh/pause/resume/destroy -p openshell now manage sandboxes
on an OpenShell gateway (https://github.com/NVIDIA/OpenShell) through its
Go SDK (sdk/go v0.1.6), with the gateway's policy enforced: outbound
connections are denied by default.

- No gateway settings of onctl's own: it uses the gateways the openshell
  CLI registered (openshell.gateway in onctl.yaml, or the CLI's active
  one). The SDK's loader doesn't do mTLS, the default for a self-hosted
  gateway, so that mode is built here from the CLI's client bundle.
- A sandbox has no address, so ssh goes through the gateway's ssh relay:
  DialVM opens SSH().Tunnel (other ports: TCP().Forward) and presents it
  as a net.Conn through a net.Pipe, so ssh handshake deadlines work. The
  stream outlives the dial's context, which tools.Remote cancels as soon
  as the dial returns. onctl ssh's ProxyCommand passes the gateway and
  workspace to ssh-proxy (hidden flags), so it reaches the same gateway.
- Pause/resume are the sandbox's stop/start (files kept); ssh and
  DialVM start a stopped sandbox first.
- Sandboxes run unprivileged and the relay has no sftp, so create and ssh
  refuse apply files, uploads, downloads and cloud-init up front with an
  explanation, and onctl claude says it doesn't run there yet.
- Like boxes, it works without an onctl.yaml (configOptional).

Tested against a gateway from the onctl-templates openshell template
(Hetzner, Ubuntu 24.04, OpenShell 0.1.6): create in ~2s, ls, ssh with
a command, system ssh via ssh-proxy, pause -> paused, ssh auto-starts
it, a file kept across pause/resume, destroy, -a refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ba6Vc6jJ1yfnNCkExeDWHh
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgolang/​github.com/​NVIDIA/​OpenShell/​sdk/​go@​v0.1.680100100100100

View full report

@cdalar
cdalar merged commit bf34e53 into main Nov 3, 2026
12 checks passed
@cdalar
cdalar deleted the ai/openshell-provider branch November 3, 2026 08:14
@codecov

codecov Bot commented Nov 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.19214% with 82 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.28%. Comparing base (851bd17) to head (79241b4).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/cloud/openshell.go 71.33% 43 Missing ⚠️
cmd/root.go 8.00% 23 Missing ⚠️
cmd/create.go 0.00% 9 Missing ⚠️
internal/provideropenshell/client.go 85.18% 4 Missing ⚠️
cmd/ssh.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1293      +/-   ##
==========================================
+ Coverage   50.97%   51.28%   +0.31%     
==========================================
  Files          83       86       +3     
  Lines        9943    10165     +222     
==========================================
+ Hits         5068     5213     +145     
- Misses       4875     4952      +77     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant

⌂ 换网址