Document the shared inline and reusable-template resource model, driver behavior, migration from legacy template resource sections, and updated SDK examples.
Part of #2838
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Use the shared generated ResourceRequirements shape for reusable workload templates and update the curated exports and tests.
BREAKING CHANGE: SandboxResources is no longer exported, and reusable-template CPU and memory values use typed limit objects.
Part of #2838
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Make allow and deny appends identify a rule and endpoint and declare every
affected binary and port. Reject incomplete, stale, ambiguous, and provider
targets atomically so a small append cannot silently change a broader scope.
Update CLI previews, wire requests, Go types and generated bindings, SDK
regressions, operator documentation, and live policy-update coverage.
BREAKING CHANGE: AddAllowRules and AddDenyRules require L7RuleTarget instead
of host and port. CLI appends require a rule name and explicit binary scope.
Signed-off-by: Shiju <shiju@nvidia.com>
* feat(api): return typed deletion outcomes with explicit missing-target semantics
Implement phase 2 of #3051 across the public gateway API and first-party SDKs. Preserve asynchronous sandbox deletion and observed resource identities, reserve legacy wire fields, and document the coordinated migration.
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
* fix(sdk): bind deletion waits to sandbox identity
Track accepted deletions by original sandbox identity in Rust and TypeScript. Preserve name-only waits and cover replacement races and lookup failures.
Merge the phase-one cleanup fix and adapt its interceptor regressions to typed deletion outcomes.
Refs #3051.
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
* test(e2e): accept asynchronous stopped sandbox deletion
Allow either completed or accepted deletion output, then continue polling for actual sandbox absence. This preserves the lifecycle assertion under the phase-two deletion contract.
Refs #3051.
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
---------
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
* feat(api): expose structured gateway errors across SDKs
Refs #3051. Add standard validation, conflict, and retry details; preserve raw transport status in Rust, Go, TypeScript, and Python; document status and recovery guidance.
This is the structured-error foundation only. Mutation result shapes, allow_missing, durable request deduplication, and exec retry semantics remain follow-up work.
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
* fix(python): preserve wrapped RPC cleanup handling
Inspect the original gRPC call when handling missing sandboxes during deletion waits and managed cleanup. Add intercepted cleanup regressions and clarify the error-wrapper migration contract.
Addresses the cleanup review on #3313; part of #3051.
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
---------
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
Show configured tool server addresses and their last observed connection
results together in sandbox status. Keep sandbox lifecycle readiness
separate so an external connection failure does not mark the sandbox unready.
Expose direct endpoint records through the CLI and SDKs, with plain-language
failure explanations and gateway acceptance times. Keep observation tracking,
runtime reporting, and gateway validation in dedicated endpoint status modules.
Preserve bounded reporting, request attribution, retry ordering, and
configuration and supervisor authority checks. Clear obsolete observations
while retaining the configured addresses, and document the distinction
between an observed HTTP response, current availability, and tool success.
Signed-off-by: Shiju <shiju@nvidia.com>
* refactor(inference): remove managed inference routes
Closes#3172
Remove the inference route control plane, inference.local data path, built-in router crate, and SDK surface. Move inference workloads to explicitly imported provider profiles and native endpoints, with migration cleanup and updated tests and documentation.
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* fix(policy): preserve alternate upstream isolation
Restore the provider policy activation guard so legacy OpenAI and Anthropic providers configured for alternate base URLs do not grant egress to the built-in public vendor endpoints.
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
---------
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* feat(server): add sandbox workload templates
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(go-sdk): add sandbox workload template support
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(rust-sdk): add sandbox workload template support
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(python-sdk): add sandbox workload template support
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(typescript-sdk): add sandbox workload template support
Signed-off-by: Gordon Sim <gsim@redhat.com>
* docs(agents): document sandbox workload templates
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(cli): support default GPU requests in sandbox templates
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(server): cap sandbox templates per workspace
Signed-off-by: Gordon Sim <gsim@redhat.com>
* docs(architecture): document sandbox workload template boundaries
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(cli+sdk): expose sandbox workload template provenance
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(cli): include sandbox template annotations in output
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(sandbox): add label selectors to template listing
Signed-off-by: Gordon Sim <gsim@redhat.com>
* test(e2e): cover sandbox template failure paths
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(server): preserve command and ttl when creating sandbox from template
Signed-off-by: Gordon Sim <gsim@redhat.com>
* test(server): add field coverage test for template merge
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(go-sdk): add pagination support to fake client
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(cli): warn on env vars that looks like secrets
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(sdk-ts): propagate sandbox workspace through lifecycle calls
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(docs): update workspace management docs
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(ts-sdk): support command and tty when creating from template
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(go-sdk): support command and tty when creating from template
Signed-off-by: Gordon Sim <gsim@redhat.com>
* test(python-sdk): verify command and tty handling when creating from template
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(go-sdk): update docs and ClientInterface
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(server): validate sandbox create specs before I/O
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(go-sdk): guard empty DNS-1123 label validation
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(python-sdk): allow empty template builder mappings
Signed-off-by: Gordon Sim <gsim@redhat.com>
* fix(cli): align template GPU JSON default output
Signed-off-by: Gordon Sim <gsim@redhat.com>
---------
Signed-off-by: Gordon Sim <gsim@redhat.com>
* feat(sdk): add TypeScript SDK (@nvidia/openshell-sdk)
First native, per-language SDK for the OpenShell gateway: a thin, idiomatic
TypeScript client over proto-generated gRPC stubs (connect-es), no FFI. Covers
the v0.1 surface — sandbox lifecycle (create/get/list/delete + waitReady/
waitDeleted), health, and streamed exec.
- sdk/typescript/: package, client/transport/errors, protoc + protoc-gen-es
codegen (gen/ gitignored, absorbed into dist/ at build), committed lockfile.
- tasks/typescript.toml: sdk:ts install/proto/typecheck/build/ci/publish;
sdk:ts:typecheck wired into `check`; sdk-typescript job in branch-checks
(typecheck, build, and a --dry-run publish that validates the release path).
- Enforce SPDX headers on .ts/.tsx/.mts/.cts (skip node_modules and gen/);
back-fill docs/_components/jsx.d.ts and fern/components/CustomFooter.tsx.
- release.py gains an npm version format; release-tag.yml publishes to
GitHub Packages on tag, stamping the version (0.0.0 placeholder in git);
prerelease builds publish under the `next` dist-tag, not `latest`.
Ships as @nvidia/openshell-sdk on GitHub Packages pre-GA; public npm
(@openshell/sdk) follows at GA with an unchanged public API.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* chore(sdk): adopt TypeScript 6, tidy @types/node range
- typescript ^5.7.2 -> ^6.0.3 (6.0 is now `latest`; the old caret capped at 5.x)
- @types/node ^24.0.0 -> ^24 (same range, tidier)
No source changes; codegen, typecheck, and build pass on 6.0.3. Verified the
emitted d.ts still type-check for downstream consumers on TypeScript 5.0.4
through 5.9.3, so this does not raise the SDK's consumer TS floor.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* refactor(sdk): group operations under a composable SandboxClient
Reshape the client from flat methods (createSandbox, listSandboxes, exec) to a
scoped SandboxClient reached as `client.sandbox.create/get/list/delete/exec`
(+ waitReady/waitDeleted), mirroring the CLI's noun-verb model and the Python
SDK's SandboxClient.
SandboxClient is also usable standalone via SandboxClient.connect();
OpenShellClient composes it over a single shared transport, so future
service/provider clients reuse one connection. health() stays top-level as a
gateway call. No behavior change; types are unchanged.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* chore(sdk): generate TypeScript SDK stubs with buf
Replace the protoc gen.sh with `buf generate` + buf.gen.yaml. `buf`
(@bufbuild/buf) is a package devDependency and self-compiles the protos, so
the TS SDK no longer depends on the mise-pinned protoc; it drives the same
connect-es plugin. Generation stays limited to the client-surface closure
(openshell/sandbox/datamodel) via the input paths.
Output is byte-identical to the previous protoc + protoc-gen-es pipeline. Lays
the groundwork for a shared buf.yaml (lint/breaking/LSP) as a follow-up.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* build(proto): add repo-level buf module with lint
Declare proto/ as a single buf v2 module in a root buf.yaml so buf
generate, lint, breaking, and the editor LSP resolve imports the same
way. Lint uses STANDARD with six documented exceptions for deviations
the current protos intentionally make: the flat proto/ layout with
nested packages (DIRECTORY_SAME_PACKAGE, PACKAGE_DIRECTORY_MATCH) and
the established API shape with unsuffixed services and reused
request/response messages (RPC_REQUEST_RESPONSE_UNIQUE,
RPC_REQUEST_STANDARD_NAME, RPC_RESPONSE_STANDARD_NAME, SERVICE_SUFFIX).
Every other STANDARD rule now enforces on future protos. Breaking uses
FILE.
Code generation stays package-scoped in sdk/typescript/buf.gen.yaml
since it binds to that package's connect-es plugin and output dir;
its inputs are unchanged and regeneration is byte-identical.
Wire the check in via a proto:lint mise task that runs buf from the
SDK devDependencies. It is a dependency of both sdk:ts:ci (so the
TypeScript SDK CI job enforces it) and the top-level lint aggregate
(so local pre-commit covers it).
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* chore(sdk): publish as unscoped openshell-sdk on public npm
Rename the package from @nvidia/openshell-sdk to the unscoped
openshell-sdk and target public npm (registry.npmjs.org) instead of
GitHub Packages. GitHub Packages requires a scope matching the owning
org, and the @openshell scope is blocked by an unrelated existing
package, so an unscoped name on public npm is the lowest-friction
distribution path and needs no org approval.
Rework the release-tag publish job to auth against registry.npmjs.org
with NPM_TOKEN (the job now only needs packages: read to pull the CI
image). Update the README install instructions and usage imports.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* chore(sdk): publish @nvidia/openshell-sdk to GitHub Packages
Revert the unscoped-name switch. GitHub Packages only accepts scoped
names matching the owning org, so shipping there first (which needs no
external npm org or NPM_TOKEN, just the repo's GITHUB_TOKEN) requires
the @nvidia scope. Keeping the @nvidia/openshell-sdk name also lets a
later public-npm release use the same install specifier, so adding
public npm becomes a second publish step rather than a rename.
Restore the GitHub Packages publish auth in the release-tag job and the
scoped install instructions in the README (keeping the buf codegen
note).
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* feat(sdk-ts): add streaming exec, forward, ssh, provider, and config methods
Grow SandboxClient to the surface the first two consumers need. execStream
yields stdout/stderr chunks as they arrive and exec now drains it, keeping its
buffered ExecResult and signature unchanged. execInteractive is the TTY + stdin
transport primitive (start-first framing, output/write/resize/close/done, no
terminal glue). forward binds a local TCP listener that tunnels each accepted
connection into the sandbox for the process lifetime, minting and revoking a
per-socket SSH session token around a forwardTcp bidi. Adds createSshSession /
revokeSshSession, attach/detach/listProviders, and getConfig / setPolicy /
setSetting (sandbox-scoped, network-policy-only, with an optional wait poll).
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* build(sdk-ts): add Biome and Vitest tooling
The TypeScript SDK had no formatter or linter and no test runner. Add Biome
(format + lint, generated src/gen excluded) enforcing 2-space indent, single
quotes, semicolons, and a 120-column width, and reformat the existing
hand-written sources accordingly. Add Vitest for unit tests. Wire sdk:ts:format,
sdk:ts:lint, and sdk:ts:test mise tasks into the fmt/lint aggregates, the root
test suite, and sdk:ts:ci so they run in CI.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* test(sdk-ts): cover the sandbox surface with in-memory transport tests
Exercise SandboxClient against an in-memory OpenShell service built with
createRouterTransport: request assembly and id resolution, u64/int64 rendered as
strings, enum lowercasing, fromConnect code mapping, the exec/execStream drain
plus a backward-compat check on exec, execInteractive start-first ordering and
done resolution, and a forward() byte relay against a loopback echo with close()
teardown.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* docs(sdk-ts): document the new surface and connect/upload/download boundaries
Document execStream, execInteractive, forward, ssh sessions, providers, and
config/policy in the SDK README, and record the intentional boundaries:
interactive connect / PTY ownership, upload/download (no file-transfer RPC), and
detached forwards stay out of scope. Note the Biome/Vitest dev commands.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* feat(sdk-ts): support mTLS client authentication
Add clientCert and clientKey to ConnectOptions so the SDK can
authenticate to the default local gateway, which uses mTLS user
authentication. Without a client certificate and key the SDK could
verify the server but never authenticate the caller, so it could not
connect to the standard Docker, VM, Homebrew, or Linux-package gateway.
Validate the pair as both-or-neither and pass cert and key through to
the Node TLS options for https gateways. The h2c path is unchanged.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* chore(sdk-ts): drop the demo script and its tsx dependency
Remove src/demo.ts, the demo npm script, the tsx devDependency, and the
tsconfig build exclude for the demo. The demo was never part of the
published package, and dropping it also removes the only place that
logged part of an SSH session token.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* fix(sdk-ts)!: harden exec streaming, waits, SSH, and forwarding
Address review feedback on the sandbox surface.
- Make the streamed command exit code observable from idiomatic
for-await: the terminal exit is now an in-band ExecStreamEvent
({ type: 'exit', exitCode }) rather than the async generator return
value, which for-await discards. A stream that ends without an exit
event now throws instead of reporting success.
- Bound waitReady, waitDeleted, and the setPolicy wait by their timeout:
each poll RPC carries a per-iteration deadline and the waits accept an
AbortSignal, so a stalled call can no longer leave a wait pending
forever. Add waitTimeoutSecs to SetPolicyOptions.
- Validate the CreateSshSession response against the proto charset and
range contract before returning it or using its token, since the
values feed an OpenSSH ProxyCommand.
- Respect socket backpressure when relaying forwarded responses: pause
reading the gRPC stream when the local socket buffer is full and
resume on drain so memory stays bounded.
- Expose create-time sandbox policy: add policy and an advanced rawSpec
passthrough to SandboxSpec so the safety boundary is expressible at
creation and new spec fields do not require an SDK change.
BREAKING CHANGE: execStream and the interactive exec output now yield a
terminal { type: 'exit', exitCode } event; consumers iterating the
stream must handle that arm. The exit code is no longer the async
generator return value.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* feat(sdk-ts): export error contract, enum unions, and caller cancellation
Address Tier-1 review feedback on the TypeScript SDK public surface (PR #2122).
- Errors: export SdkError and SdkErrorCode so callers can use instanceof and
exhaustively switch on .code. fromConnect preserves the originating
ConnectError as .cause and its status as .connectCode, maps Aborted to a new
'aborted' code for optimistic-concurrency conflicts, and maps Canceled and
DeadlineExceeded to 'canceled'. errorCode() behavior is unchanged.
- Enums: replace the string-typed phase, status, scope, and policySource fields
with lowercase literal unions (SandboxPhaseName, HealthStatus,
SettingScopeName, PolicySourceName) backed by exhaustive Record maps. The
unions are a hand-maintained mirror of the generated proto enums; a new drift
test pins each literal to its generated member name.
- Cancellation: accept an optional AbortSignal on exec, execInteractive, and
forward, threaded into both sandbox resolution and the streaming RPC. forward
tears down its local listener on abort.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* feat(sdk-ts): add raw escape hatch for uncurated gateway RPCs
The curated sub-clients reduce proto messages to ergonomic subsets (for
example get() drops created_at_ms, the full spec, conditions, runtime
endpoints, and current_policy_version), and not every gateway RPC has a
typed helper yet. Rather than ship methods that exist but throw, expose a
generated client for the full surface.
OpenShellClient.raw and SandboxClient.raw are generated clients covering
every gateway RPC, returning the verbatim wire messages so proto
distinctions the curated types smooth over are preserved. .transport
exposes the shared connection for building extra clients over one socket.
Generated request/response types are published at the new
@nvidia/openshell-sdk/raw subpath. Curated methods stay the default;
raw is the always-available floor.
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* fix(sdk-ts): address review feedback on exec, forward, and auth transport
Settle exec's `done` promise before yielding the exit event so a consumer
that breaks on exit no longer leaves it pending forever, and give it a lone
rejection handler plus a finally-settle so a stream error or early abandon
can never surface as an unhandled rejection or a hang.
Attach an 'error' listener to each accepted forward socket synchronously,
before forwardConnection awaits CreateSshSession; a peer reset in that
window previously emitted an unhandled 'error' and crashed the process.
Reject ambiguous or unsafe transport configs at buildTransport: oidcToken
and edgeToken together (silently OIDC-only), and any auth token sent over
plaintext http:// to a non-loopback host unless allowInsecureAuth is set.
Wrap versionPin so a non-u64 expectedResourceVersion raises
SdkError('invalid_config') instead of a raw BigInt SyntaxError, and raise
the Node engine floor to >=20.3 for AbortSignal.any().
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
* fix(sdk-ts): address review feedback
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* docs(sdk-ts): defer published sdk guide
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
---------
Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
Co-authored-by: Drew Newberry <anewberry@nvidia.com>