Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenShell SDK for Go

CI Docs Go Reference Coverage License

Important

Read the full documentation for guides, API reference with gRPC mapping, and testing patterns.

A Go SDK for interacting with OpenShell servers, providing idiomatic Go bindings for shell session management, command execution, provider configuration, and service exposure.

Why a Go SDK?

Go is the language of the Kubernetes ecosystem. If you want to build an operator, controller, or any automation that manages OpenShell resources as native Kubernetes objects, you need a Go client.

This SDK is modeled after k8s.io/client-go, the standard Kubernetes client library that every Go operator developer already knows. The patterns will look familiar:

  • Typed sub-clients per resource: client.Sandboxes(), client.Providers(), client.Exec(), just like clientset.CoreV1().Pods()
  • Domain types separated from wire formats: clean Go structs in a types package, no proto leakage into the public API (like k8s.io/api)
  • Watch primitives: channel-based watchers with ResultChan() and Stop(), identical to watch.Interface in client-go
  • Functional options: variadic option patterns for list filtering, pagination, and watch configuration
  • Composable auth with token refresh: wraps oauth2.TokenSource for automatic token caching and coalesced refresh, following the k8s client-go cachingTokenSource pattern
  • Fake client for testing: an in-memory implementation of the full client interface (like k8s.io/client-go/kubernetes/fake), so operators can be tested without a real gateway

Quick Start

import v1 "github.com/rhuss/openshell-sdk-go/openshell/v1"

// Connect to a gateway
client, err := v1.NewClient(v1.Config{
    Address: "gateway.example.com:443",
    Auth:    v1.StaticToken("my-token"),
})
if err != nil {
    log.Fatal(err)
}
defer client.Close()

// Create a sandbox and wait until it's ready
sandbox, err := client.Sandboxes().Create(ctx, "my-sandbox", &v1.SandboxSpec{
    Template: &v1.SandboxTemplate{Image: "python:3.12"},
}, nil)
if err != nil {
    log.Fatal(err)
}
sandbox, err = client.Sandboxes().WaitReady(ctx, sandbox.Name)
if err != nil {
    log.Fatal(err)
}

// Run a command
result, err := client.Exec().Run(ctx, sandbox.Name,
    []string{"python3", "-c", "print('hello from sandbox')"},
    v1.ExecOptions{},
)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(result.Stdout))

With automatic token refresh

For OIDC gateways, use RefreshableToken to wrap any oauth2.TokenSource with automatic caching and coalesced refresh:

import "golang.org/x/oauth2"

tokenSource := oauth2Config.TokenSource(ctx, initialToken)
auth, err := v1.RefreshableToken(tokenSource,
    v1.WithLeeway(30*time.Second),
)
if err != nil {
    log.Fatal(err)
}
client, err := v1.NewClient(v1.Config{
    Address: "gateway.example.com:443",
    Auth:    auth,
})
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Concurrent callers share a single refresh call. If the token source fails, the SDK falls back to the cached token with a logged warning. See the Auth docs for details.

With edge proxy headers

When a gateway sits behind a zero-trust reverse proxy, use WithExtraHeaders to attach proxy-specific headers alongside standard auth:

base := v1.StaticToken("my-gateway-token")
auth, err := v1.WithExtraHeaders(base, map[string]string{
    "x-proxy-auth": "proxy-secret",
})
if err != nil {
    log.Fatal(err)
}
client, err := v1.NewClient(v1.Config{
    Address: "gateway.example.com:443",
    Auth:    auth,
})

For Cloudflare Access, use the convenience constructor in the edge package:

import "github.com/rhuss/openshell-sdk-go/openshell/v1/edge"

auth, err := edge.CloudflareAccess(base, os.Getenv("CF_ACCESS_TOKEN"))

For gRPC behind edge proxies that reject HTTP/2, use the WebSocket tunnel:

tunnel, err := edge.NewTunnelProxy(
    "wss://gateway.example.com/ws",
    os.Getenv("CF_ACCESS_TOKEN"),
)
if err != nil {
    log.Fatal(err)
}
defer tunnel.Close()

client, err := v1.NewClient(v1.Config{
    Address: tunnel.Addr(),
    Auth:    v1.StaticToken("my-token"),
    TLS:     &v1.TLSConfig{Insecure: true}, // local tunnel, no TLS
})

OIDC Login

The oidc package provides gateway-aware OIDC authentication with browser, keyboard, device code, and client credentials flows:

import "github.com/rhuss/openshell-sdk-go/openshell/v1/oidc"

// Gateway-aware login: reads OIDC config from gateway metadata
token, err := oidc.Login(ctx, "my-gateway")
if err != nil {
    log.Fatal(err)
}

// Use the token with the SDK client
client, err := v1.NewClient(v1.Config{
    Address: "gateway.example.com:443",
    Auth:    v1.StaticToken(token.AccessToken),
})

For headless environments, use the device code flow:

token, err := oidc.DeviceLogin(ctx,
    oidc.WithIssuer("https://auth.example.com"),
    oidc.WithClientID("my-app"),
)

For service accounts, use client credentials:

token, err := oidc.ClientCredentials(ctx,
    oidc.WithGateway("my-gateway"),
    oidc.WithClientSecret("service-secret"),
)

See the oidc package docs for all options and flows.

See the Getting Started guide for the full walkthrough.

Inference Route Management

Configure how inference requests are routed for a workspace:

// Set an inference route
route, err := client.Inference().SetRoute(ctx, "my-workspace", &v1.InferenceRouteConfig{
    ProviderName: "openai",
    ModelID:      "gpt-4",
    RouteName:    "",        // empty string = default route
    TimeoutSecs:  120,
})
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Route v%d: %s/%s\n", route.Version, route.ProviderName, route.ModelID)

// Retrieve the route
route, err = client.Inference().GetRoute(ctx, "my-workspace", "")
if err != nil {
    log.Fatal(err)
}

// Delete the route
err = client.Inference().DeleteRoute(ctx, "my-workspace", "")
if err != nil {
    log.Fatal(err)
}

Architecture

Client
  ├── Sandboxes()   → SandboxInterface    (create, get, list, delete, watch, wait, logs)
  ├── Exec()        → ExecInterface       (run, stream, interactive)
  ├── Files()       → FileInterface       (upload, download)
  ├── Health()      → HealthInterface     (health check, gateway info, current user)
  ├── Services()    → ServiceInterface    (expose, get, list, delete)
  ├── Providers()   → ProviderInterface   (CRUD + ensure)
  │     ├── Profiles() → ProfileInterface (list, get, import, update, lint, delete)
  │     └── Refresh()  → RefreshInterface (configure, status, rotate, delete)
  ├── Workspaces()  → WorkspaceInterface  (create, get, list, delete, members)
  ├── Inference()   → InferenceInterface  (set, get, delete inference routes)
  └── Policy()      → PolicyInterface     (draft review, approve, reject, merge, status)

All domain types live in openshell/v1/types/. Proto-to-Go conversions happen in an internal converter layer. The public API surface uses type aliases so consumers import a single package. See the Architecture overview for details.

Features

Feature Interface Docs
Sandbox lifecycle (create, get, list, delete, watch, wait) SandboxInterface Sandboxes
Command execution (collected, streamed, interactive PTY) ExecInterface Exec
Provider management (CRUD + idempotent ensure) ProviderInterface Providers
Provider profiles (list, import, lint, update) ProfileInterface Profiles
Credential refresh (configure, rotate, status) RefreshInterface Refresh
Service exposure (expose, list, delete) ServiceInterface Services
File transfer (upload, download) FileInterface Files
Policy management (draft review, approve, reject, merge, global policy) PolicyInterface Policy
Sandbox logs (streaming retrieval) SandboxInterface Sandboxes
Workspace management (create, get, list, delete, members) WorkspaceInterface Workspaces
Inference route management (set, get, delete) InferenceInterface Inference
Gateway info and current user identity HealthInterface Health
Health checking HealthInterface Health
SSH tunneling and TCP forwarding SSHInterface, TCPInterface SSH, TCP
Auth: static token, refreshable token (oauth2.TokenSource) AuthProvider Auth
Edge auth: extra headers, Cloudflare Access, WebSocket tunnel AuthProvider, edge.TunnelProxy Edge
Typed errors (IsNotFound, IsAlreadyExists, IsConflict, ...) StatusError Error Handling
Real-time watch with auto-stop on terminal phase WatchInterface[T] Sandboxes
Fake client for testing (no gRPC server needed) fake.Client Testing
OIDC login (browser, keyboard, device code, client credentials) oidc.Login, oidc.DeviceLogin, oidc.ClientCredentials OIDC
Gateway config convenience (load CLI gateway configs, auto-wire auth) gateway.NewClient, gateway.LoadConfig Gateway

Prerequisites

  • Go 1.23 or later
  • mise (recommended for reproducible builds)

Build and Test

git clone https://github.com/rhuss/openshell-sdk-go.git
cd openshell-sdk-go

make test    # Run tests with coverage
make lint    # Run golangci-lint
make ci      # Full CI pipeline (lint + build + test)

If you don't have mise installed, make will print installation instructions.

Documentation

Full API documentation is available at the OpenShell Go SDK Docs site.

To build the docs locally:

cargo install mdbook
mdbook serve docs

Contributing

See CONTRIBUTING.md for development setup, build commands, and contribution guidelines.

License

Apache-2.0. See LICENSE for details.

Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

About

Go SDK for OpenShell

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages