python.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package python
  2. import (
  3. _ "embed"
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "path"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/google/uuid"
  12. "github.com/langgenius/dify-sandbox/internal/core/runner"
  13. "github.com/langgenius/dify-sandbox/internal/core/runner/types"
  14. "github.com/langgenius/dify-sandbox/internal/static"
  15. )
  16. type PythonRunner struct {
  17. runner.TempDirRunner
  18. }
  19. //go:embed prescript.py
  20. var sandbox_fs []byte
  21. var (
  22. REQUIRED_FS = []string{
  23. path.Join(LIB_PATH, LIB_NAME),
  24. }
  25. )
  26. func (p *PythonRunner) Run(
  27. code string,
  28. timeout time.Duration,
  29. stdin []byte,
  30. preload string,
  31. options *types.RunnerOptions,
  32. ) (chan []byte, chan []byte, chan bool, error) {
  33. configuration := static.GetDifySandboxGlobalConfigurations()
  34. // initialize the environment
  35. untrusted_code_path, err := p.InitializeEnvironment(code, preload, options)
  36. if err != nil {
  37. return nil, nil, nil, err
  38. }
  39. // capture the output
  40. output_handler := runner.NewOutputCaptureRunner()
  41. output_handler.SetTimeout(timeout)
  42. err = p.WithTempDir(LIB_PATH, REQUIRED_FS, func(root_path string) error {
  43. // cleanup
  44. output_handler.SetAfterExitHook(func() {
  45. os.RemoveAll(root_path)
  46. os.Remove(root_path)
  47. os.Remove(untrusted_code_path)
  48. })
  49. // create a new process
  50. cmd := exec.Command(
  51. configuration.PythonPath,
  52. untrusted_code_path,
  53. LIB_PATH,
  54. )
  55. cmd.Env = []string{}
  56. if configuration.Proxy.Socks5 != "" {
  57. cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", configuration.Proxy.Socks5))
  58. cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_PROXY=%s", configuration.Proxy.Socks5))
  59. } else if configuration.Proxy.Https != "" || configuration.Proxy.Http != "" {
  60. if configuration.Proxy.Https != "" {
  61. cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", configuration.Proxy.Https))
  62. }
  63. if configuration.Proxy.Http != "" {
  64. cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_PROXY=%s", configuration.Proxy.Http))
  65. }
  66. }
  67. err = output_handler.CaptureOutput(cmd)
  68. if err != nil {
  69. return err
  70. }
  71. return nil
  72. })
  73. if err != nil {
  74. return nil, nil, nil, err
  75. }
  76. return output_handler.GetStdout(), output_handler.GetStderr(), output_handler.GetDone(), nil
  77. }
  78. func (p *PythonRunner) InitializeEnvironment(code string, preload string, options *types.RunnerOptions) (string, error) {
  79. if !checkLibAvaliable() {
  80. // ensure environment is reversed
  81. releaseLibBinary()
  82. }
  83. // create a tmp dir and copy the python script
  84. temp_code_name := strings.ReplaceAll(uuid.New().String(), "-", "_")
  85. temp_code_name = strings.ReplaceAll(temp_code_name, "/", ".")
  86. script := strings.Replace(
  87. string(sandbox_fs),
  88. "{{uid}}", strconv.Itoa(static.SANDBOX_USER_UID), 1,
  89. )
  90. script = strings.Replace(
  91. script,
  92. "{{gid}}", strconv.Itoa(static.SANDBOX_GROUP_ID), 1,
  93. )
  94. if options.EnableNetwork {
  95. script = strings.Replace(
  96. script,
  97. "{{enable_network}}", "1", 1,
  98. )
  99. } else {
  100. script = strings.Replace(
  101. script,
  102. "{{enable_network}}", "0", 1,
  103. )
  104. }
  105. script = strings.Replace(
  106. script,
  107. "{{preload}}",
  108. fmt.Sprintf("%s\n", preload),
  109. 1,
  110. )
  111. code = strings.Replace(
  112. script,
  113. "{{code}}",
  114. code,
  115. 1,
  116. )
  117. untrusted_code_path := fmt.Sprintf("%s/tmp/%s.py", LIB_PATH, temp_code_name)
  118. err := os.MkdirAll(path.Dir(untrusted_code_path), 0755)
  119. if err != nil {
  120. return "", err
  121. }
  122. err = os.WriteFile(untrusted_code_path, []byte(code), 0755)
  123. if err != nil {
  124. return "", err
  125. }
  126. return untrusted_code_path, nil
  127. }