feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
97
backend/infra/impl/coderunner/runner.go
Normal file
97
backend/infra/impl/coderunner/runner.go
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package coderunner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/crossdomain/code"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/goutil"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
)
|
||||
|
||||
var pythonCode = `
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
|
||||
class Args:
|
||||
def __init__(self, params):
|
||||
self.params = params
|
||||
|
||||
class Output(dict):
|
||||
pass
|
||||
|
||||
%s
|
||||
|
||||
try:
|
||||
result = asyncio.run(main( Args(json.loads(sys.argv[1]))))
|
||||
print(json.dumps(result))
|
||||
except Exception as e:
|
||||
print(f"{type(e).__name__}: {str(e)}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
`
|
||||
|
||||
type Runner struct{}
|
||||
|
||||
func NewRunner() *Runner {
|
||||
return &Runner{}
|
||||
}
|
||||
|
||||
func (r *Runner) Run(ctx context.Context, request *code.RunRequest) (*code.RunResponse, error) {
|
||||
var (
|
||||
params = request.Params
|
||||
c = request.Code
|
||||
)
|
||||
if request.Language == code.Python {
|
||||
ret, err := r.pythonCmdRun(ctx, c, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &code.RunResponse{
|
||||
Result: ret,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported language: %s", request.Language)
|
||||
}
|
||||
|
||||
func (r *Runner) pythonCmdRun(_ context.Context, code string, params map[string]any) (map[string]any, error) {
|
||||
bs, _ := sonic.Marshal(params)
|
||||
cmd := exec.Command(goutil.GetPython3Path(), "-c", fmt.Sprintf(pythonCode, code), string(bs)) //ignore_security_alert RCE
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to run python script err: %s, std err: %s", err.Error(), stderr.String())
|
||||
}
|
||||
|
||||
if stderr.String() != "" {
|
||||
return nil, fmt.Errorf("failed to run python script err: %s", stderr.String())
|
||||
}
|
||||
ret := make(map[string]any)
|
||||
err = sonic.Unmarshal(stdout.Bytes(), &ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
62
backend/infra/impl/coderunner/script/python_script.py
Normal file
62
backend/infra/impl/coderunner/script/python_script.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import asyncio
|
||||
import time
|
||||
import random
|
||||
try:
|
||||
from RestrictedPython import safe_builtins, limited_builtins, utility_builtins
|
||||
except ModuleNotFoundError:
|
||||
print("RestrictedPython module required, please run pip install RestrictedPython",file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
custom_builtins = safe_builtins.copy()
|
||||
|
||||
custom_builtins['__import__'] = __import__
|
||||
custom_builtins['asyncio'] = asyncio
|
||||
custom_builtins['json'] = json
|
||||
custom_builtins['time'] = time
|
||||
custom_builtins['random'] = random
|
||||
|
||||
restricted_globals = {
|
||||
'__builtins__': custom_builtins,
|
||||
'_utility_builtins': utility_builtins,
|
||||
'_limited_builtins': limited_builtins,
|
||||
'__name__': '__main__',
|
||||
'dict': dict,
|
||||
'list': list,
|
||||
'print': print,
|
||||
'set': set,
|
||||
|
||||
}
|
||||
|
||||
class Args:
|
||||
def __init__(self, params):
|
||||
self.params = params
|
||||
|
||||
|
||||
DefaultCode = """
|
||||
class Args:
|
||||
def __init__(self, params):
|
||||
self.params = params
|
||||
class Output(dict):
|
||||
pass
|
||||
"""
|
||||
|
||||
|
||||
async def run_main(app_code, params):
|
||||
try:
|
||||
complete_code = DefaultCode + app_code
|
||||
locals_dict = {"args": Args(params=params)}
|
||||
exec(complete_code, restricted_globals, locals_dict) # ignore_security_alert
|
||||
main_func = locals_dict['main']
|
||||
ret = await main_func(locals_dict['args'])
|
||||
except Exception as e:
|
||||
print(f"{type(e).__name__}: {str(e)}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return ret
|
||||
|
||||
|
||||
code = sys.argv[1]
|
||||
result = asyncio.run(run_main(code, params=json.loads(sys.argv[2])))
|
||||
print(json.dumps(result))
|
||||
Reference in New Issue
Block a user