Skip to content

Add Go SDK#254

Open
nemo1105 wants to merge 2 commits into
TencentCloud:masterfrom
nemo1105:codex-add-go-sdk
Open

Add Go SDK#254
nemo1105 wants to merge 2 commits into
TencentCloud:masterfrom
nemo1105:codex-add-go-sdk

Conversation

@nemo1105
Copy link
Copy Markdown

Add a standalone standard-library Go SDK for CubeSandbox with lifecycle, execution, command, file read, proxy transport, README, unit tests, and opt-in integration tests.

Autonomously-by: Codex:GPT-5

Add a standalone standard-library Go SDK for CubeSandbox with lifecycle, execution, command, file read, proxy transport, README, unit tests, and opt-in integration tests.

Autonomously-by: Codex:GPT-5
@fslongjin
Copy link
Copy Markdown
Member

/cubebot review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

Claude finished @fslongjin's task in 1m 44s —— View job


Go SDK Code Review

Overall the Go SDK is well-structured with clean API design, comprehensive test coverage (including edge cases), and thorough documentation. Below are specific findings organized by severity.


Bugs / Correctness Issues

1. Fragile exit code parsing in Commands.Run (sdk/go/commands.go:43-56)

The exit code is parsed from the last line of stdout output. If a command's output happens to end with a line containing only an integer, that line will be silently consumed as the exit code rather than returned as output.

// If a user runs: echo 42
// result.Stdout will be "" (empty) and result.ExitCode will be 42
// even though the actual exit code was 0

This is a known pattern carried over from the E2B Python SDK design, but it's worth documenting this limitation. Consider evaluating whether a different encoding scheme (e.g., a delimiter or separate file descriptor) would be more robust for production use.

2. Silent JSON marshal error discard (sdk/go/sandbox.go:150)

raw, _ := json.Marshal(payload)

This silently discards a marshaling error. While payload only contains simple types (making failure unlikely), a json.Marshal error would produce a nil/empty byte slice which then gets sent as an empty request body, causing a confusing failure downstream. Should at minimum log or document why the error is safe to ignore.


Design / API Concerns

3. Hardcoded HTTP scheme for data-plane requests (sdk/go/sandbox.go:152)

req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://"+s.GetHost(JupyterPort)+"/execute", bytes.NewReader(raw))

The http:// scheme is hardcoded. If the proxy or sandbox data-plane endpoint ever requires HTTPS, this would break. Consider making the scheme configurable or deriving it from the control-plane API URL.

4. Commands.Run uses shell=True (sdk/go/commands.go:22)

Python subprocess.run with shell=True is inherently risky. The input is properly quoted with strconv.Quote, but this should be clearly documented in a security consideration section since this API accepts arbitrary command strings from callers.


Minor (Style / Conventions)

5. Error message capitalization (sdk/go/files.go:23)

return "", fmt.Errorf("Failed to read %s: %s", path, execution.Error.Value)

Go convention requires error messages to start with lowercase. Should be "failed to read %s: %s".

6. coverage_test.go:570 — Helper function name is misleading

func errorFromRunCode(_ *Execution, err error) error {
    return err
}

This discards the *Execution return value. The name errorFromRunCode suggests it's extracting an error from Execution, but it's actually a multi-value adapter. A more descriptive name or inline handling would improve readability.


Strengths

  • Excellent test coverage: Unit tests cover config parsing edges, stream parsing (including malformed input), API error mapping, pause wait loops, context cancellation, transport failures, and nil receiver protection.
  • Well-structured error handling: APIError.Is implements proper errors.Is compatibility, including distinction between template-not-found and sandbox-not-found via message heuristics.
  • Good use of strconv.Quote: Safely escapes file paths and shell commands for embedding in generated Python code, preventing injection.
  • Proper context propagation: Timeouts, cancellation, and deadlines flow correctly through all operations.
  • Clean separation of concerns: codeRunner interface cleanly decouples Commands and Files from Sandbox.
  • Comprehensive README with working examples for all key features.
  • Proxy transport design is clean — preserving the virtual host header while routing to the proxy node.
  • Integration tests are well-structured with auto-discovery of templates, proper cleanup via t.Cleanup, and are gated behind a build tag.

Summary

The SDK is production-quality in its structure and testing rigor. The exit code parsing fragility in Commands.Run is the most notable concern and warrants either documentation or a more robust encoding approach. Other findings are minor style improvements or design tradeoffs worth considering.

Return command exit codes through execution results instead of parsing stdout, add configurable data-plane proxy scheme support, and document shell command security considerations.

Autonomously-by: Codex:GPT-5
@tinklone
Copy link
Copy Markdown
Collaborator

Commands.Run should use envd Process API instead of Python code execution

The current Commands.Run implementation wraps shell commands in Python code (subprocess.run(...)) and executes them via the /execute endpoint. This is architecturally wrong — it should call envd's process.Process/Start (Connect Protocol) interface directly.

How E2B does it (the correct approach)

E2B's official SDK calls:

POST http://49999-{sandboxID}.{domain}/process.Process/Start

With payload:

{
  "process": {
    "cmd": "/bin/bash",
    "args": ["-l", "-c", "<user-command>"],
    "envs": {},
    "cwd": "<optional>"
  }
}

The response is a server-stream of ProcessEvent messages:

  • StartEvent → gives PID
  • DataEvent → stdout/stderr bytes
  • EndEvent → exit_code, exited status

Why the current approach is problematic

  1. Requires Python in the sandbox — breaks for Go/Rust/C-only templates
  2. Performance overhead — spawns a Python interpreter just to call subprocess.run
  3. Fragile exit code handling — parsing return code from expression result text vs getting EndEvent.exit_code directly
  4. Inconsistent with E2B SDK — the Go SDK should behave the same as the Python/JS SDKs

Suggested fix

Implement a Connect Protocol (gRPC over HTTP/JSON) client for process.Process/Start in the Go SDK. The proto definition is at spec/envd/process/process.proto. The wire format is simple HTTP POST with JSON body + server-sent streaming response.

This also enables implementing Commands.List, Commands.Kill, Commands.SendStdin, and Commands.Connect — all available via the same envd process service.

Similarly, Files.Read should use the envd HTTP file API (GET /files?path=...) instead of generating Python open() code through /execute.

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.

4 participants