28 Commits
Author SHA1 Message Date
Drew Newberry ddb85b1704 feat(vm): add openshell-vm crate with libkrun microVM gateway (#611) 2026-04-08 22:00:01 -07:00
Drew Newberry 13262e1cfa feat(cli): add sandbox exec subcommand with TTY support (#752) 2026-04-04 21:43:52 -07:00
Drew Newberry e837849009 feat(bootstrap): resume gateway from existing state and persist SSH handshake secret (#488) 2026-04-02 09:50:10 -07:00
Drew Newberry 7eb1df64bf fix(cli): sandbox upload overwrites files instead of creating directories (#694)
* fix(cli): sandbox upload overwrites files instead of creating directories

When uploading a single file to an existing file path, sandbox_sync_up
unconditionally ran mkdir -p on the destination, turning it into a
directory. Split the destination into parent + basename for single-file
uploads so tar extracts with the correct filename, matching cp/scp
semantics.

Consolidates duplicated SSH/tar boilerplate from sandbox_sync_up and
sandbox_sync_up_files into a shared ssh_tar_upload helper.

Closes #667

* better path defaults
2026-04-02 08:42:05 -07:00
John T. MyersandJohn Myers d9e8fe55a3 fix(cli): add missing Copilot variant to CliProviderType enum (#713)
PR #476 added Copilot as a supported provider but missed adding the
Copilot variant to the CliProviderType enum, causing --provider copilot
to fail at CLI argument parsing. Also adds a parity test to prevent
future drift between CliProviderType and ProviderRegistry.

Closes #707

Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-04-01 17:11:47 -07:00
Drew Newberry 151fca9dc5 fix(server): return already_exists for duplicate sandbox names (#695)
Check for existing sandbox name before persisting, matching the
provider-creation pattern. The CLI now surfaces a clear hint instead
of a raw UNIQUE constraint error.

Closes #691
2026-03-31 11:37:20 -07:00
Evan LezarandPiotr Mlocek 047de66b22 feat(bootstrap,cli): switch GPU injection to CDI where supported (#495)
* feat(bootstrap): switch GPU injection to CDI where supported

Use an explicit CDI device request (driver="cdi", device_ids=["nvidia.com/gpu=all"])
when the Docker daemon reports CDI spec directories via GET /info (SystemInfo.CDISpecDirs).
This makes device injection declarative and decouples spec generation from consumption.

When the daemon reports no CDI spec directories, fall back to the legacy NVIDIA device
request (driver="nvidia", count=-1) which relies on the NVIDIA Container Runtime hook.
Failure modes for both paths are equivalent: a missing or stale NVIDIA Container Toolkit
installation will cause container start to fail.

CDI spec generation is out of scope for this change; specs are expected to be
pre-generated out-of-band, for example by the NVIDIA Container Toolkit.

---------

Signed-off-by: Evan Lezar <elezar@nvidia.com>
Co-authored-by: Piotr Mlocek <pmlocek@nvidia.com>
2026-03-31 08:23:52 -07:00
Peter Andreas Entschev 36329a1059 feat(inference): allow setting custom inference timeout (#672)
* feat(inference): add timeout

* feat(inference): fix dynamic timeout change

* feat(inference): update docs

* feat(inference): fix formatting
2026-03-30 15:02:30 -07:00
Serge PanevandJohn Myers 1f2a85e873 fix(cli): clear stale last-used sandbox on deletion (#510)
* fix(cli): clear stale last-used sandbox on deletion

When a sandbox is deleted, the locally stored last-used record now gets
cleared if it matches the deleted sandbox name. This prevents subsequent
commands from falling back to a sandbox that no longer exists, which
previously caused confusing gRPC errors.

Adds clear_last_sandbox_if_matches() to openshell-bootstrap and calls
it from sandbox_delete() after each successful deletion.

Closes #172

Signed-off-by: Serge Panev <spanev@nvidia.com>

* style: fix rustfmt import ordering and line wrapping

Signed-off-by: Serge Panev <spanev@nvidia.com>

* fix(cli): pass gateway to sandbox_delete in finalize_sandbox_create_session

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-03-23 15:54:01 -07:00
John T. Myers 834f8aa184 fix: security hardening batch 1 (SEC-002 through SEC-010) (#548)
* fix(l7): reject ambiguous HTTP framing in REST proxy (SEC-009)

Harden the L7 REST proxy HTTP parser against request smuggling:

- Reject requests containing both Content-Length and Transfer-Encoding
  headers per RFC 7230 Section 3.3.3 (CL/TE ambiguity)
- Replace String::from_utf8_lossy with strict UTF-8 validation to
  prevent interpretation gaps with upstream servers
- Reject bare LF line endings (require CRLF per HTTP spec)
- Validate HTTP version string (HTTP/1.0 or HTTP/1.1 only)

* fix(server): harden shell_escape and command construction (SEC-002)

Harden the gRPC exec handler against command injection via the
structured-to-shell-string conversion:

- Reject null bytes and newlines/carriage returns in shell_escape()
- Add input validation in exec_sandbox: reject control characters in
  command args, env values, and workdir
- Enforce size limits: max 1024 args, 32 KiB per arg/value, 4 KiB
  workdir, 256 KiB total assembled command string
- Change shell_escape and build_remote_exec_command to return Result
  so callers must handle validation failures

* fix(server): add command validation at SSH transport boundary (SEC-003)

Add defense-in-depth validation in run_exec_with_russh before sending
the command to the sandbox SSH server:

- Reject null bytes in command string at transport boundary
- Enforce max command length (256 KiB) at transport boundary
- Enhance stream_exec_over_ssh logging with command length, stdin
  length, and truncated command preview for audit trail

* fix(sandbox): validate port range and extend loopback check in SSH (SEC-007)

Harden the SSH direct-tcpip channel handler:

- Validate port_to_connect <= 65535 before u32-to-u16 cast to prevent
  port truncation (e.g., 65537 becoming port 1)
- Replace string-literal loopback check with is_loopback_host() that
  covers the full 127.0.0.0/8 range, IPv4-mapped IPv6 (::ffff:127.x),
  bracketed IPv6, and case-insensitive localhost
- Remove #[allow(clippy::cast_possible_truncation)] since the cast is
  now proven safe by the preceding range check

* fix(sandbox): sanitize inference error messages returned to sandbox (SEC-008)

Replace verbatim internal error strings in router_error_to_http with
generic messages to prevent information leakage to sandboxed code.
Upstream URLs, internal hostnames, TLS details, and file paths are no
longer exposed. Full error context is still logged server-side at warn
level by the caller for debugging.

* fix(server): block internal IPs in SSH proxy target validation (SEC-006)

Add IP validation in start_single_use_ssh_proxy to prevent SSRF if a
sandbox status record were poisoned:

- Resolve DNS before connecting and validate the resolved IP
- Block loopback (127.0.0.0/8) and link-local (169.254.0.0/16, covers
  cloud metadata endpoint) addresses
- Block IPv4-mapped IPv6 variants of the same ranges
- Connect to the validated SocketAddr directly to prevent TOCTOU
- Add debug logging of resolved target IP for audit

* fix(sandbox): add resource limits to chunked body parser (SEC-010)

Harden parse_chunked_body in the inference interception path:

- Replace all unchecked +2 additions with checked_add for consistent
  overflow safety across all target architectures
- Add MAX_CHUNKED_BODY (10 MiB) to cap decoded body size
- Add MAX_CHUNK_COUNT (4096) to prevent CPU exhaustion via tiny chunks
- Early-reject chunk sizes larger than remaining buffer space

* fix(cli): double-escape command for SSH path, validate host and name (SEC-004)

Harden doctor_exec against command injection in the SSH remote path:

- Apply shell_escape to inner_cmd in the SSH path so it survives the
  double shell interpretation (SSH remote shell + sh -lc). This also
  fixes a correctness bug where multi-word commands were silently
  broken in the SSH path.
- Add validate_gateway_name to reject shell metacharacters in gateway
  names before use in container_name
- Add validate_ssh_host to reject metacharacters in remote_host loaded
  from metadata.json

* fix(sandbox): add CIDR breadth warning and control-plane port blocklist (SEC-005)

Defense-in-depth for the allowed_ips feature:

- Log a warning when a CIDR entry has a prefix length < /16, as overly
  broad ranges may unintentionally expose control-plane services
- Block K8s API (6443), etcd (2379/2380), and kubelet (10250/10255)
  ports unconditionally in resolve_and_check_allowed_ips, even when
  the resolved IP matches an allowed_ips entry

* test(e2e): update assertion for sanitized inference error message (SEC-008)

The SEC-008 fix changed the error message from 'no compatible route
for source protocol ...' to 'no compatible inference route available'.
Update the E2E assertion substring to match.
2026-03-23 14:41:03 -07:00
John T. Myers bbcaed2ea7 refactor(proto): rename UpdateSettings to UpdateConfig for consistency with read path (#515) 2026-03-20 16:45:59 -07:00
John T. Myers a831a8921b feat(settings): gateway-to-sandbox runtime settings channel (#474)
* feat(gateway/sandbox): add global and sandbox runtime settings flow
2026-03-20 14:08:57 -07:00
Drew Newberry a4883d8286 fix(bootstrap): surface diagnostics for K8s namespace not ready failures (#466) 2026-03-19 09:13:11 -07:00
Drew Newberry 5565a8bba3 fix(cli): suppress browser popup during auth via OPENSHELL_NO_BROWSER env var (#419) 2026-03-18 09:38:51 -07:00
Drew Newberry 085b131aef fix(cli): use --name flag in gateway destroy help messages (#368)
Error messages and recovery hints were showing 'openshell gateway destroy <name>'
as a positional argument, but the CLI defines name as a --name flag. This caused
'unexpected argument' errors when users copied the suggested commands.
2026-03-16 12:48:56 -07:00
Drew Newberry 079c8f8d51 chore: pre-release readiness (#313) 2026-03-16 06:27:27 -07:00
Piotr Mlocek 3a328be853 feat(inference): verify endpoints before saving routes (#291)
Closes #273

Verify inference endpoints synchronously on the server during set/update, expose a --no-verify escape hatch in the CLI and Python helper, and return actionable failures when validation does not pass.
2026-03-15 19:36:23 -07:00
Drew Newberry 53b7ce7112 fix(core): harden file permissions for user config directory (#328) 2026-03-15 15:55:41 -07:00
Drew Newberry 9fdffc72b2 feat(bootstrap): add Docker preflight check before gateway startup (#321) 2026-03-15 09:45:19 -07:00
Drew Newberry 0a7ffe1669 ci(release): gate python wheels on e2e for tagged releases (#319) 2026-03-15 00:39:00 -07:00
Drew Newberry 847bf4438c fix(cli): check port availability before starting SSH forward (#309) 2026-03-14 21:27:17 -07:00
John T. Myers 97bad8b7d0 chore: derive build version from git tags for all components (#305)
Compute version strings from git describe in openshell-core's build.rs
using the guess-next-dev scheme (e.g. 0.0.4-dev.6+g2bf9969). All binary
crates and the TUI splash screen now use the shared openshell_core::VERSION
constant instead of CARGO_PKG_VERSION.

In Docker/CI builds where .git is absent, falls back to CARGO_PKG_VERSION
which is already set correctly by the sed-patch pipeline. Also adds
OPENSHELL_CARGO_VERSION support to the cluster image and fast-deploy
supervisor builds for parity with the gateway.
2026-03-14 14:58:33 -07:00
Piotr Mlocek 05eade959c feat(cli): add no-verify inference flag (#302) 2026-03-14 14:02:36 -07:00
Piotr Mlocek 26e540d8d6 fix(cli): show startup feedback for foreground forwards (#296) 2026-03-13 21:51:08 -07:00
Drew Newberry 2858bd662f fix(cli): use line-based stdin read for gateway recreate prompt (#292) 2026-03-13 15:51:09 -07:00
Drew Newberry 20c32716ad fix(bootstrap): detect missing sandbox supervisor binary during gateway health check (#281) 2026-03-13 15:07:50 -07:00
Piotr Mlocek 72e0268028 feat(sandbox): add gpu sandbox scheduling support (#257)
* feat(sandbox): add gpu sandbox scheduling support

Allow sandbox creation to request GPU resources explicitly or infer them from GPU image names. This wires GPU intent through bootstrap, validates gateway support, and adds dedicated GPU E2E coverage for follow-up cluster testing.
2026-03-13 11:32:43 -07:00
Drew Newberry fbd93a4632 refactor: rename navigator- crate prefix to openshell- (#277) 2026-03-13 02:02:18 -07:00