Skip to content

OpenSandbox Go SDK ​

Go client library for the OpenSandbox API.

Provides high-level sandbox helpers and low-level clients for these API areas:

  • Lifecycle -- Create, manage, and destroy sandbox instances
  • Execd -- Execute commands, manage files, monitor metrics inside sandboxes
  • Egress -- Inspect and mutate sandbox network policy at runtime

Installation ​

bash
# go 1.20+
go get github.com/alibaba/OpenSandbox/sdks/sandbox/go

Quick Start ​

Create and manage a sandbox ​

Use the high-level helper to create a sandbox, resolve its endpoint, and wait for readiness before running commands:

go
package main

import (
    "context"
    "fmt"
    "log"

    opensandbox "github.com/alibaba/OpenSandbox/sdks/sandbox/go"
)

func run() error {
    ctx := context.Background()
    ttl := 600
    config := opensandbox.ConnectionConfig{
        Domain: "localhost:8080",
        Protocol: "http",
        UseServerProxy: true,
    }
    sandbox, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
        Image: "python:3.12",
        TimeoutSeconds: &ttl,
    })
    if err != nil {
        return err
    }
    defer sandbox.Close()
    defer sandbox.Kill(context.Background())

    result, err := sandbox.RunCommand(ctx, "echo sandbox-ready", nil)
    if err != nil {
        return err
    }
    fmt.Println(result.Text())
    return nil
}

func main() {
    if err := run(); err != nil {
        log.Fatal(err)
    }
}

ConnectSandbox and ResumeSandbox check health only when you pass the optional ReadyOptions argument (an empty ReadyOptions{} uses the default check). Omitting it resolves the endpoint without a health check. Pause is asynchronous: wait until sandbox info reports Paused before resuming.

The following snippets go inside a function returning error, with the live sandbox, config, and ctx above. Add standard-library imports used by each snippet. Creation examples are alternatives; terminate sandboxes with Kill when done. Close currently does not terminate the sandbox.

Run a command with streaming output ​

Use structured callbacks for normal command output:

go
result, err := sandbox.RunCommand(ctx, "echo 'Hello from sandbox!'", &opensandbox.ExecutionHandlers{
    OnStdout: func(message opensandbox.OutputMessage) error {
        fmt.Println(message.Text)
        return nil
    },
})
if err != nil {
    return err
}
if result.ExitCode == nil || *result.ExitCode != 0 {
    return fmt.Errorf("command failed: %v", result.Error)
}

Use the low-level client when you need raw SSE events or command status/log APIs. event.Data contains JSON; import encoding/json and os for this example:

go
endpoint, err := sandbox.GetEndpoint(ctx, 44772)
if err != nil {
    return err
}
exec := opensandbox.NewExecdClient(
    config.Protocol + "://" + endpoint.Endpoint, "",
    opensandbox.WithHeaders(endpoint.Headers),
)

err = exec.RunCommand(ctx, opensandbox.RunCommandRequest{
    Command: "echo 'Hello from sandbox!'",
    Timeout: 30000,
}, func(event opensandbox.StreamEvent) error {
    var message struct{ Type, Text string }
    if err := json.Unmarshal([]byte(event.Data), &message); err != nil {
        return err
    }
    switch message.Type {
    case "stdout":
        fmt.Println(message.Text)
    case "stderr":
        fmt.Fprintln(os.Stderr, message.Text)
    case "execution_complete":
        fmt.Println("[done]")
    }
    return nil
})
if err != nil {
    return err
}

RunCommandRequest.Timeout is in milliseconds. Use this low-level client for InterruptCommand, GetCommandStatus, and GetCommandLogs, which are not exposed as high-level Sandbox methods.

For native execution, replace the request above with the following. On Linux, it prints literal $HOME and keeps hello world as one argument:

go
_, err = sandbox.RunCommandWithOpts(ctx, opensandbox.RunCommandRequest{
    Argv:    []string{"printf", "%s\n", "$HOME", "hello world"},
    Timeout: 30000,
}, nil)
if err != nil {
    return err
}

Native argv execution requires an updated execd. See command execution modes for executable lookup and platform behavior.

Background commands ​

Reuse the exec client from the streaming example to poll status and incremental logs. Command timeout is in milliseconds and is separate from sandbox TTL.

go
execution, err := sandbox.RunCommandWithOpts(ctx, opensandbox.RunCommandRequest{
    Command: "for i in 1 2 3; do echo step-$i; sleep 1; done",
    Background: true,
    Timeout: 30_000,
}, nil)
if err != nil {
    return err
}
if execution.ID == "" {
    return fmt.Errorf("no command ID returned")
}
cursor := int64(0)
deadline := time.Now().Add(45 * time.Second)
for {
    if time.Now().After(deadline) {
        if err := exec.InterruptCommand(ctx, execution.ID); err != nil {
            return err
        }
        return fmt.Errorf("command did not finish")
    }
    status, err := exec.GetCommandStatus(ctx, execution.ID)
    if err != nil {
        return err
    }
    logs, err := exec.GetCommandLogs(ctx, execution.ID, &cursor)
    if err != nil {
        return err
    }
    fmt.Print(logs.Output)
    cursor = logs.Cursor
    if !status.Running {
        if status.ExitCode == nil || *status.ExitCode != 0 {
            return fmt.Errorf("command failed: %s", status.Error)
        }
        break
    }
    select {
    case <-ctx.Done():
        return ctx.Err()
    case <-time.After(500 * time.Millisecond):
    }
}

Persistent shell sessions ​

A Bash session preserves shell variables and the working directory across commands.

go
session, err := sandbox.CreateSession(ctx)
if err != nil {
    return err
}
defer sandbox.DeleteSession(context.Background(), session.ID)
_, err = sandbox.RunInSession(ctx, session.ID, opensandbox.RunInSessionRequest{
    Command: "cd /tmp; export DEMO=hello",
    Timeout: 30_000,
}, nil)
if err != nil {
    return err
}
result, err := sandbox.RunInSession(ctx, session.ID, opensandbox.RunInSessionRequest{
    Command: "echo \"$DEMO\"; pwd",
    Timeout: 30_000,
}, nil)
if err != nil {
    return err
}
fmt.Println(result.Text())

Persistent environment variables ​

Set environment variables that the runtime injects into every subsequent command and session — without hand-writing shell escaping against the sandbox env file.

go
err := sandbox.SetEnv(ctx, "MY_TOKEN", "it's a safe value")

Keys must match [A-Za-z_][A-Za-z0-9_]*. Values without a single quote are stored verbatim; values containing a single quote use the env file's double-quoted form, in which shell-style $NAME sequences may be expanded when the runtime loads the file. The env file is append-only: the last write for a key wins. Returns an error if the sandbox fails to persist the variable.

For filesystem/process isolation within a sandbox, see Isolation Sessions. These are separate from Bash sessions.

File operations ​

Upload from an io.Reader and close download streams after use. This example uses strings, io, and os from the standard library:

go
err := sandbox.UploadFile(ctx, strings.NewReader("Hello Sandbox!"), opensandbox.UploadFileOptions{
    Metadata: opensandbox.FileMetadata{Path: "/tmp/demo.txt", Mode: 644},
})
if err != nil {
    return err
}
body, err := sandbox.DownloadFile(ctx, "/tmp/demo.txt", "")
if err != nil {
    return err
}
_, copyErr := io.Copy(os.Stdout, body)
closeErr := body.Close()
if copyErr != nil {
    return copyErr
}
if closeErr != nil {
    return closeErr
}
entries, err := sandbox.ListDirectory(ctx, "/tmp")
if err != nil {
    return err
}
for _, entry := range entries {
    fmt.Println(entry.Path)
}
if err := sandbox.DeleteFiles(ctx, []string{"/tmp/demo.txt"}); err != nil {
    return err
}

The same upload/download methods support binary files. Pass a Range header such as "bytes=0-1023" to DownloadFile for a partial download.

File operations with an explicit identity ​

Bind a filesystem client to a Linux UID and GID:

go
files, err := sandbox.FilesWithIdentity(1001, 2000)
if err != nil {
    return err
}

The bound client exposes the usual file operations and shares the sandbox connection, authentication, and endpoint routing headers. The existing file client retains its default identity. Select the UID/GID separately for command execution.

This requires Linux and an Execd version that supports filesystem execution identity. Unsupported servers return an error; requests never fall back to the default filesystem routes. Keep sandbox credentials and identity selection in the trusted backend. Linux filesystem permissions apply; this feature does not create a tenant isolation boundary. See Execd for permission and workspace provisioning details.

Pause and reconnect ​

Pause is asynchronous and runtime-dependent. Use a deadline before resuming:

go
pauseCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
if err := sandbox.Pause(pauseCtx); err != nil {
    return err
}
for {
    info, err := sandbox.GetInfo(pauseCtx)
    if err != nil {
        return err
    }
    if info.Status.State == "Paused" {
        break
    }
    if info.Status.State == "Failed" {
        return fmt.Errorf("pause failed: %s", info.Status.Message)
    }
    select {
    case <-pauseCtx.Done():
        return pauseCtx.Err()
    case <-time.After(time.Second):
    }
}
resumed, err := opensandbox.ResumeSandbox(ctx, config, sandbox.ID(), opensandbox.ReadyOptions{})
if err != nil {
    return err
}
defer resumed.Close()
if _, err := resumed.Renew(ctx, 30*time.Minute); err != nil {
    return err
}

Use ConnectSandbox(ctx, config, id, opensandbox.ReadyOptions{}) to attach to an already running sandbox with a readiness check. See Pause and Resume.

Resource metrics ​

Use metrics, err := sandbox.GetMetrics(ctx) to read current sandbox resource usage. This is separate from SDK creation telemetry.

Check egress policy ​

Runtime egress reads and patches go directly to the sandbox egress sidecar. The SDK first resolves the sandbox endpoint on port 18080, then calls the sidecar /policy API.

go
policy, err := sandbox.GetEgressPolicy(ctx)
if err != nil {
    return err
}
fmt.Printf("Mode: %s, Default: %s\n", policy.Mode, policy.Policy.DefaultAction)

_, err = sandbox.PatchEgressRules(ctx, []opensandbox.NetworkRule{
    {Action: "allow", Target: "api.example.com"},
})
if err != nil {
    return err
}

Template-backed sandboxes have no sandbox-side egress sidecar: the SDK detects them via the server's OPEN-SANDBOX-ORIGIN response header (see Fsb Template Management) and routes the same GetEgressPolicy / PatchEgressRules / DeleteEgressRules calls through the lifecycle control plane (/sandboxes/{sandboxId}/networkpolicy) instead.

Patch uses merge semantics:

  • Incoming rules take priority over existing rules with the same target.
  • Existing rules for other targets remain unchanged.

Use Credential Vault ​

Credential Vault injects outbound credentials from the egress sidecar while keeping real secrets out of sandbox environment variables, commands, files, and logs. Create the sandbox with CredentialProxy enabled, then write credentials and bindings through the sandbox helpers or EgressClient.

go
config := opensandbox.ConnectionConfig{
    Domain:   "localhost:8080",
    Protocol: "http",
    APIKey:   "your-api-key",
}

sandbox, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
    Image: "python:3.11",
    NetworkPolicy: &opensandbox.NetworkPolicy{
        DefaultAction: "deny",
        Egress: []opensandbox.NetworkRule{
            {Action: "allow", Target: "api.example.com"},
        },
    },
    CredentialProxy: &opensandbox.CredentialProxyConfig{Enabled: true},
})
if err != nil {
    return err
}

_, err = sandbox.CreateCredentialVault(ctx, opensandbox.CredentialVaultCreateRequest{
    Credentials: []opensandbox.Credential{
        {
            Name: "api-token",
            Source: opensandbox.InlineCredentialSource{
                Type:  opensandbox.CredentialSourceInline,
                Value: "<token>",
            },
        },
    },
    Bindings: []opensandbox.CredentialBinding{
        {
            Name: "api-token",
            Match: opensandbox.CredentialMatch{
                Schemes: []opensandbox.CredentialScheme{opensandbox.CredentialSchemeHTTPS},
                Ports:   []int{443},
                Hosts:   []string{"api.example.com"},
                Paths:   []string{"/v1/*"},
            },
            Auth: opensandbox.CredentialAuth{
                Type:       opensandbox.CredentialAuthAPIKey,
                Name:       "x-api-key",
                Credential: "api-token",
            },
        },
    },
})

See Credential Vault for auth types, binding guidance, and Git/curl examples.

WARNING

Credential Vault is unavailable for template-backed sandboxes: they have no sandbox-side egress sidecar. sandbox.CredentialVault(ctx) returns an error for them.

Client Pool ​

Use NewSandboxPoolBuilder with an in-memory store or the Redis adapter in github.com/alibaba/OpenSandbox/sdks/sandbox/go/poolredis. Go supports all four acquire policies, namespace retirement, and per-acquire TTL/health-check overrides.

Go uses ReconcileInterval and WarmupConcurrency; it does not expose the Python/JVM/JavaScript create-QPS, initial-delay, or post-prepare-check settings. See Client Pool for defaults, examples, and cleanup. Go does not currently emit built-in pool warmup traces or expose stable remote diagnostics; use CLI or HTTP diagnostics.

Lifecycle Hooks ​

Set Lifecycle in SandboxCreateOptions. PreStart completes before the entrypoint starts, while Periodic hooks run on their schedules after startup.

go
hookTimeout := 120
sandbox, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
    Image: "ubuntu:24.04",
    Lifecycle: &opensandbox.SandboxLifecycle{
        PreStart: &opensandbox.LifecycleHook{
            Command:        []string{"sh", "-c", "echo ready > /tmp/prestart.done"},
            TimeoutSeconds: &hookTimeout,
        },
        Periodic: []opensandbox.PeriodicLifecycleHook{
            {
                Name:           "checkpoint",
                Schedule:       "@every 5m",
                Command:        []string{"sh", "-c", "date -u >> /tmp/checkpoints.log"},
                TimeoutSeconds: &hookTimeout,
            },
        },
    },
})
if err != nil {
    return err
}
defer sandbox.Close()
defer sandbox.Kill(context.Background())
fmt.Println(sandbox.ID())

The Server validates TimeoutSeconds; PreStart accepts 1–10800 seconds, while Periodic accepts 1–300 seconds. Both default to 60 seconds when omitted. See Lifecycle Hooks for timing, failure behavior, and provider limitations.

Idle policy (auto-pause and wake-on-access) ​

SandboxLifecycle.IdlePolicy (OSEP-0024, fast-sandbox only) tells the control plane to auto-pause the sandbox after IdleTimeoutSeconds (30–86400) of continuously idle ingress-observed traffic, and to wake it on the next request. It is control-plane state: it never reaches the guest, is accepted in template mode (SandboxFromTemplateOptions.IdlePolicy), and is rejected by non-fast-sandbox backends. Omitting it preserves non-automated behavior exactly.

go
idleTimeout := 300
wakeOnAccess := true
sandbox, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
    Image: "ubuntu:24.04",
    Lifecycle: &opensandbox.SandboxLifecycle{
        IdlePolicy: &opensandbox.IdlePolicy{
            IdleTimeoutSeconds: &idleTimeout,
            OnIdle:             opensandbox.OnIdlePause,
            WakeOnAccess:       &wakeOnAccess,
        },
    },
})

ActiveProbe lets the application veto a pause while real work runs without producing ingress traffic: declare an endpoint answering {"active": bool, "message"?: string} and the server polls it when the sandbox is otherwise idle; a busy answer resets the idle clock. Invalid policies fail fast client-side through IdlePolicy.Validate().

Wake retry ​

A request to a paused sandbox may arrive while its restore is still in progress. The gateway answers 503 with the OpenSandbox-Wake: expired marker; the client recognizes it and resends the original request after the Retry-After delay (safe for any method — the marker proves the request was never forwarded). The wake budget defaults to 5 attempts / 60 seconds across all wake cycles; when it is exhausted the client returns a *SandboxWakeTimeoutError (carrying Attempts and Waited) while the server-side resume continues in the background. Bare 503 responses follow the existing retry rules untouched. Wake retry is active whenever a WithRetry config is set (WakeRetryEnabled defaults to enabled even for hand-built configs; pass WakeRetryDisabled() to opt out); streaming connections bypass wake retry — a waking sandbox fails fast with the marked 503 instead of parking the connect — matching the other official SDKs, and established streams are never re-executed.

Fsb Template Management ​

fsb (fast-sandbox microVM) golden-image templates are managed through SandboxManager. Template builds are asynchronous: CreateTemplate returns with Status.Phase set to Pending; poll GetTemplate until the phase reaches Succeeded or Failed. Only a Succeeded template can create sandboxes. Template management requires a configured Fsb provider on Kubernetes. Replace the publish URI with a location configured for your server.

go
manager := opensandbox.NewSandboxManager(config)

buildCtx, cancel := context.WithTimeout(ctx, 15*time.Minute)
defer cancel()

// Start the async build (starts at TemplatePhasePending)
template, err := manager.CreateTemplate(buildCtx, opensandbox.CreateTemplateRequest{
    Image:          "alpine:3.19",
    Publish:        "s3://bucket/publish",
    ResourceLimits: opensandbox.ResourceLimits{"cpu": "1", "memory": "512Mi", "disk": "2Gi"},
    Readiness:      &opensandbox.TemplateReadiness{Probe: "tcp://127.0.0.1:44772"},
    Metadata:       map[string]string{"team": "backend"},
})
if err != nil {
    return err
}

// Poll until the build finishes
for template.Status.Phase != opensandbox.TemplatePhaseSucceeded &&
    template.Status.Phase != opensandbox.TemplatePhaseFailed {
    select {
    case <-buildCtx.Done():
        return buildCtx.Err()
    case <-time.After(2 * time.Second):
    }
    template, err = manager.GetTemplate(buildCtx, template.TemplateID)
    if err != nil {
        return err
    }
}
if template.Status.Phase == opensandbox.TemplatePhaseFailed {
    return fmt.Errorf("template build failed: %s", template.TemplateID)
}

// List with metadata filters (1-indexed paging)
listed, err := manager.ListTemplates(ctx, opensandbox.ListTemplatesOptions{
    Metadata: map[string]string{"team": "backend"},
    Page:     1,
    PageSize: 20,
})
if err != nil {
    return err
}
fmt.Println(listed)

// When no longer needed: manager.DeleteTemplate(ctx, template.TemplateID)

Creating a Sandbox from a Template ​

Use CreateSandboxFromTemplate to create a sandbox from a Succeeded template. Template mode fixes the workload shape on the server: only Metadata, NetworkPolicy and Extensions may accompany the template ID, and TimeoutSeconds is required.

go
sandbox, err := opensandbox.CreateSandboxFromTemplate(ctx, config, "tpl-abc",
    opensandbox.SandboxFromTemplateOptions{
        TimeoutSeconds: 600,
        NetworkPolicy: &opensandbox.NetworkPolicy{
            DefaultAction: "deny",
            Egress: []opensandbox.NetworkRule{
                {Action: "allow", Target: "api.example.com"},
            },
        },
    })
if err != nil {
    return err
}

fmt.Println(sandbox.Origin()) // "template"

Snapshots and metadata ​

Sandbox.CreateSnapshot and SandboxManager.CreateSnapshot start snapshot creation. Use manager GetSnapshot, ListSnapshots, and DeleteSnapshot to manage snapshots, then pass SnapshotID to SandboxCreateOptions to restore. Poll snapshot status before restore. Use Sandbox.PatchMetadata or SandboxManager.PatchSandboxMetadata to add/replace keys; nil values remove keys.

Snapshot support depends on the runtime and server configuration. Renew the source sandbox first if its remaining TTL may expire during snapshot creation. Wait for Ready before restoring. This example retains the snapshot for reuse:

go
manager := opensandbox.NewSandboxManager(config)
snapshot, err := sandbox.CreateSnapshot(ctx, opensandbox.CreateSnapshotRequest{Name: "demo"})
if err != nil {
    return err
}
fmt.Println("Snapshot:", snapshot.ID)
snapshotCtx, cancel := context.WithTimeout(ctx, 15*time.Minute)
defer cancel()
for {
    snapshot, err = manager.GetSnapshot(snapshotCtx, snapshot.ID)
    if err != nil {
        return err
    }
    if snapshot.Status.State == opensandbox.SnapshotStateReady {
        break
    }
    if snapshot.Status.State == opensandbox.SnapshotStateFailed {
        return fmt.Errorf("snapshot failed: %s", snapshot.Status.Message)
    }
    select {
    case <-snapshotCtx.Done():
        return snapshotCtx.Err()
    case <-time.After(2 * time.Second):
    }
}
restored, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
    SnapshotID: snapshot.ID,
})
if err != nil {
    return err
}
defer restored.Close()
defer restored.Kill(context.Background())
fmt.Println(restored.ID())
// When no longer needed: manager.DeleteSnapshot(ctx, snapshot.ID)

Add/replace a metadata key and remove another:

go
project := "demo"
if _, err := sandbox.PatchMetadata(ctx, opensandbox.MetadataPatch{
    "project": &project, "obsolete-key": nil,
}); err != nil {
    return err
}

API Reference ​

LifecycleClient ​

Created with NewLifecycleClient(baseURL, apiKey string, opts ...Option).

MethodDescription
CreateSandbox(ctx, req)Create a new sandbox from a container image
GetSandbox(ctx, id)Get sandbox details by ID
ListSandboxes(ctx, opts)List sandboxes with filtering and pagination
DeleteSandbox(ctx, id)Delete a sandbox
PauseSandbox(ctx, id)Pause a running sandbox
ResumeSandbox(ctx, id)Resume a paused sandbox
RenewExpiration(ctx, id, expiresAt)Set sandbox expiration to a future timestamp (may shorten or extend)
GetEndpoint(ctx, sandboxID, port, useServerProxy)Get public endpoint for a sandbox port
GetSignedEndpoint(ctx, sandboxID, port, expires)Get signed endpoint URL with a signed route token
CreateTemplate(ctx, req)Declare a fsb template (async golden-image build)
GetTemplate(ctx, templateID)Get a template with its latest build status
ListTemplates(ctx, opts)List templates with metadata filtering and pagination
DeleteTemplate(ctx, templateID)Delete a template
GetNetworkPolicy(ctx, sandboxID)Get a sandbox's egress policy from the control plane
PatchNetworkPolicy(ctx, sandboxID, rules)Merge egress rules into a sandbox's policy
DeleteNetworkPolicyRules(ctx, sandboxID, targets)Remove a sandbox's egress rules by target

ExecdClient ​

Created with NewExecdClient(baseURL, accessToken string, opts ...Option).

Health:

MethodDescription
Ping(ctx)Check server health

Code Execution:

MethodDescription
ListContexts(ctx, language)List active code execution contexts
CreateContext(ctx, req)Create a code execution context
GetContext(ctx, contextID)Get context details
DeleteContext(ctx, contextID)Delete a context
DeleteContextsByLanguage(ctx, language)Delete all contexts for a language
ExecuteCode(ctx, req, handler)Execute code with SSE streaming
InterruptCode(ctx, sessionID)Interrupt running code

Command Execution:

MethodDescription
CreateSession(ctx)Create a bash session
RunInSession(ctx, sessionID, req, handler)Run command in session with SSE
DeleteSession(ctx, sessionID)Delete a bash session
RunCommand(ctx, req, handler)Run a command with SSE streaming
InterruptCommand(ctx, sessionID)Interrupt running command
GetCommandStatus(ctx, commandID)Get command execution status
GetCommandLogs(ctx, commandID, cursor)Get command stdout/stderr

File Operations:

MethodDescription
GetFileInfo(ctx, path)Get file metadata
DeleteFiles(ctx, paths)Delete files
SetPermissions(ctx, req)Change file permissions
MoveFiles(ctx, req)Move/rename files
SearchFiles(ctx, dir, pattern)Search files by glob pattern
ListDirectory(ctx, path)List immediate directory contents (server-side default depth)
ListDirectoryWithDepth(ctx, path, depth)List directory contents up to the given depth (0 returns empty)
ReplaceInFiles(ctx, req)Text replacement in files
UploadFile(ctx, file, opts)Upload a file to the sandbox
UploadFiles(ctx, entries)Upload multiple files to the sandbox
DownloadFile(ctx, remotePath, rangeHeader)Download a file from the sandbox

Directory Operations:

MethodDescription
CreateDirectory(ctx, path, mode)Create a directory (mkdir -p)
DeleteDirectory(ctx, path)Delete a directory recursively

Metrics:

MethodDescription
GetMetrics(ctx)Get system resource metrics
WatchMetrics(ctx, handler)Stream metrics via SSE

EgressClient ​

Created with NewEgressClient(baseURL, authToken string, opts ...Option).

MethodDescription
GetPolicy(ctx)Get current egress policy
PatchPolicy(ctx, rules)Merge rules into current policy
CreateCredentialVault(ctx, req)Create sandbox-local Credential Vault state
GetCredentialVault(ctx)Get sanitized Credential Vault state
PatchCredentialVault(ctx, req)Atomically mutate credentials and bindings
DeleteCredentialVault(ctx)Delete sandbox-local Credential Vault state
ListCredentialVaultCredentials(ctx)List sanitized credential metadata
GetCredentialVaultCredential(ctx, name)Get sanitized metadata for one credential
ListCredentialVaultBindings(ctx)List sanitized binding metadata
GetCredentialVaultBinding(ctx, name)Get sanitized metadata for one binding

SSE Streaming ​

Methods that stream output (RunCommand, ExecuteCode, RunInSession, WatchMetrics) accept an EventHandler callback:

go
type EventHandler func(event opensandbox.StreamEvent) error

Each StreamEvent contains:

  • Event -- the event type (e.g. "stdout", "stderr", "result", "execution_complete"). For NDJSON streams, this is extracted from the JSON type field automatically.
  • Data -- the raw event payload (JSON string for NDJSON streams).
  • ID -- optional event identifier

Return a non-nil error from the handler to stop processing the stream early.

Client Options ​

All client constructors accept optional Option functions. Custom HTTP clients and health checks must honor context cancellation for timeouts to take effect:

go
// Reuse the resolved endpoint from the streaming example.
execClient := opensandbox.NewExecdClient(
    config.Protocol + "://" + endpoint.Endpoint, "",
    opensandbox.WithHeaders(endpoint.Headers),
    opensandbox.WithHTTPClient(&http.Client{Timeout: 60 * time.Second}),
)
if err := execClient.Ping(ctx); err != nil {
    return err
}

TLS Certificate Strength

SDK-created HTTP clients enforce NIST 2030 minimum TLS certificate strength by default (RSA >= 2048, EC >= 224, DSA P >= 2048/Q >= 224, hash >= 224). If you must interoperate with legacy endpoints, set AllowWeakServerCertKeyLengths: true in TransportConfig.

SDK Telemetry

CreateSandbox reports create latency to POST /v1/metrics/events by default. Set ConnectionConfig.DisableMetrics or OPENSANDBOX_DISABLE_METRICS=1 to opt out. See SDK Telemetry.

Follow redirects ​

The Go SDK retains Go's standard redirect behavior, including for file uploads and downloads. On redirects to a different origin (scheme, hostname, or effective port), it removes the client's default and configured authentication headers (including X-EXECD-ACCESS-TOKEN, X-API-Key, or a custom WithAuthHeader name), as well as all headers whose names start with OPEN-SANDBOX- or OPENSANDBOX-, case-insensitively. Each redirect destination is compared with the initial request's origin, so subsequent hops on another origin remain protected. Same-origin redirects retain these headers. Unrelated custom headers continue to follow Go's standard forwarding rules.

This protection applies to lifecycle (including creation metrics), execd, egress, file transfers, and SSE requests. A custom http.Client.CheckRedirect supplied through WithHTTPClient or ConnectionConfig.HTTPClient still controls whether redirects are followed; the SDK removes protected headers after that callback runs, even if the callback adds them again. The SDK copies the supplied HTTP client rather than modifying it. HTTP and HTTPS default ports are treated as equivalent to explicit ports 80 and 443 respectively. Upload method conversion and body replay follow Go's existing rules; this protection does not enable replay of streaming multipart bodies.

Error Handling ​

Non-2xx responses are returned as *opensandbox.APIError:

go
_, err := sandbox.GetInfo(ctx)
if err != nil {
    var apiErr *opensandbox.APIError
    if errors.As(err, &apiErr) {
        fmt.Printf("HTTP %d: %s — %s\n", apiErr.StatusCode, apiErr.Response.Code, apiErr.Response.Message)
    }
    return err
}

License ​

Apache 2.0

Released under the Apache 2.0 License.