Go-Sandbox 开发实录 (4):穿越铁窗 —— 那些关于 IO 和超时的坑

牢笼建好了,犯人也关进去了。最后的问题是:我们怎么知道他在里面干了什么? 对于 Code Interpreter 来说,用户的代码输出(Stdout/Stderr)必须实时、完整地传回给前端。而且,如果代码死循环了,我们得能把它杀掉。 这两个看似简单的需求,在实现时也让我们踩了不少坑。 坑一:IO 阻塞与 Goroutine 泄漏 最初,我们简单地用 cmd.StdoutPipe() 获取管道,然后在一个 Goroutine 里读。 // 错误示范 go func() { io.Copy(outputChan, stdoutPipe) }() 但在高并发场景下,我们发现 Goroutine 数量飙升。原来,如果 Python 进程异常退出或者被 kill 掉,有时候管道的 Read…

Go-Sandbox 开发实录 (3):画地为牢 —— 我们是如何构建“监狱”的?

把 Go 代码注入到 Python 进程后,我们拿到了控制权。现在的任务是:把这个进程关进“监狱”里。 在 internal/core/lib/python/add_seccomp.go 中,我们定义了这座“监狱”的构造。 第一步:切断退路 (Chroot) 首先要解决的是文件系统的隔离。我们不希望用户代码能看到 /etc/passwd,也不希望它能看到宿主机的任何文件。 chroot 是最古老也是最有效的手段之一。 // internal/core/lib/python/add_seccomp.go func InitSeccomp(uid int, gid int, enable_network bool) error { // 1.…

Go-Sandbox 开发实录 (2):特洛伊木马 —— 如何“黑”进 Python 进程?

在上一篇中,我们确定了“进程级沙箱”的路线。但摆在面前的第一个技术难题是:如何在 Python 进程启动的那一刻,强行插入我们的安全代码? 我们需要在用户代码执行之前,完成 Chroot 和 Seccomp 的设置。如果等到用户代码开始跑了再限制,黄花菜都凉了。 尝试一:直接修改解释器源码? 最硬核的办法是下载 CPython 源码,在 main 函数里加几行代码,重新编译一个 safe-python。 但这太蠢了。 1. 维护噩梦:每次 Python 发新版,我们都得重新打补丁、编译。 2. 不通用:那 Node.js 怎么办?Java 怎么办?难道都要改源码? 我们需要一种非侵入式的方案。 尝试二:LD_PRELOAD? Linux 有个黑魔法叫…

Go-Sandbox 开发实录 (1):为了毫秒级启动,我们放弃了 Docker

做 LLM Agent 开发时,Code Interpreter 是个绕不开的功能。让 AI 写代码容易,但让它安全地运行代码,却是个棘手的工程问题。 在设计 go-sandbox 之初,我们面临的最大抉择就是:到底是用 Docker,还是自己造轮子? Docker 的诱惑与代价 最开始,我们自然而然地想到了 Docker。它成熟、安全、隔离性好。我们尝试为每个代码执行请求启动一个容器: docker run --rm -it python:3.10 python -c "print('hello')" 但在高并发测试中,问题很快暴露了: 1. 慢:即使是热启动,容器的创建和销毁也需要几百毫秒。对于用户来说,…