package sandbox import ( "context" "encoding/json" "fmt" "os" "os/exec" "github.com/coze-dev/coze-studio/backend/infra/contract/coderunner" "github.com/coze-dev/coze-studio/backend/pkg/goutil" "github.com/coze-dev/coze-studio/backend/pkg/logs" ) func NewRunner(config *Config) coderunner.Runner { return &runner{ pyPath: goutil.GetPython3Path(), scriptPath: goutil.GetPythonFilePath("sandbox.py"), config: config, } } type Config struct { AllowEnv []string `json:"allow_env,omitempty"` AllowRead []string `json:"allow_read,omitempty"` AllowWrite []string `json:"allow_write,omitempty"` AllowNet []string `json:"allow_net,omitempty"` AllowRun []string `json:"allow_run,omitempty"` AllowFFI []string `json:"allow_ffi,omitempty"` NodeModulesDir string `json:"node_modules_dir,omitempty"` TimeoutSeconds float64 `json:"timeout_seconds,omitempty"` MemoryLimitMB int64 `json:"memory_limit_mb,omitempty"` } type runner struct { pyPath, scriptPath string config *Config } func (runner *runner) Run(ctx context.Context, request *coderunner.RunRequest) (*coderunner.RunResponse, error) { if request.Language == coderunner.JavaScript { return nil, fmt.Errorf("js not supported yet") } b, err := json.Marshal(req{ Config: runner.config, Code: request.Code, Params: request.Params, }) if err != nil { return nil, err } pr, pw, err := os.Pipe() if err != nil { return nil, err } r, w, err := os.Pipe() if err != nil { return nil, err } if _, err = pw.Write(b); err != nil { return nil, err } if err = pw.Close(); err != nil { return nil, err } cmd := exec.Command(runner.pyPath, runner.scriptPath) cmd.ExtraFiles = []*os.File{w, pr} if err = cmd.Start(); err != nil { return nil, err } if err = w.Close(); err != nil { return nil, err } result := &resp{} d := json.NewDecoder(r) d.UseNumber() if err = d.Decode(result); err != nil { return nil, err } if err = cmd.Wait(); err != nil { return nil, err } logs.CtxDebugf(ctx, "resp=%v\n", result) if result.Status != "success" { return nil, fmt.Errorf("exec failed, stdout=%s, stderr=%s, sandbox_err=%s", result.Stdout, result.Stderr, result.SandboxError) } return &coderunner.RunResponse{Result: result.Result}, nil } type req struct { Config *Config `json:"config"` Code string `json:"code"` Params map[string]any `json:"params"` } type resp struct { Result map[string]any `json:"result"` Stdout string `json:"stdout"` Stderr string `json:"stderr"` Status string `json:"status"` ExecutionTime float64 `json:"execution_time"` SandboxError string `json:"sandbox_error"` }