feat: py sandbox for workflow
* chore: update Dockerfile and sandbox.py * feat: py sandbox for workflow * feat: py sandbox for workflow See merge request: !885
This commit is contained in:
103
backend/infra/impl/coderunner/sandbox/runner.go
Normal file
103
backend/infra/impl/coderunner/sandbox/runner.go
Normal file
@@ -0,0 +1,103 @@
|
||||
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"`
|
||||
}
|
||||
Reference in New Issue
Block a user