feat: 沙箱规模——/tmp 顺序加严、注册表寻址与失联精确清理、超时边界抽取
- Docker /tmp tmpfs 移到全部 -v 之前(父挂载在前,seed 子挂载在后); 宿主级 bwrap /tmp 仍宣告未隔离,口径见 tmp_isolation_status() - workers 表补 host/pid/address(老库幂等补列),心跳透传与保留语义, _claim 写 claimed_by_worker;orphaned_containers 精确识别失联容器, Worker.cleanup_orphaned_containers 默认只杀 pid_verified 的精确容器名 - docker_run_timeout() 纯函数抽取(行为与原内联一致),README 补边界与 未验证清单;新增 test_sandbox_scale.py 20 项
This commit is contained in:
1 parent
143ab30094
commit
06710cf47b
7 files changed
+897
-48
No files matched your search
+49
-12
@@ -41,6 +41,33 @@ from cloud.marker_tools import extract_wait_threads as _extract_wait_threads
|
||||
from cloud.peer_messages import extract_peer_messages as _extract_peer_messages
|
||||
|
||||
MAX_STDOUT_CHARS = 2000
|
||||
|
||||
|
||||
def tmp_isolation_status():
|
||||
"""各层 /tmp 隔离现状的唯一口径(README 与单测都以它为准)。
|
||||
|
||||
返回 {docker: bool, host_bwrap: bool, ...}:
|
||||
- docker=True:DockerExecutor 给每个任务容器挂 --tmpfs /tmp
|
||||
与 --tmpfs /var/tmp(容器随 --rm 消失,/tmp 也随之消失,
|
||||
绝不落宿主 /tmp;见 build_run_command 的顺序注释)。
|
||||
- host_bwrap=False:宿主级 codex workspace-write(bwrap)
|
||||
的挂载由 codex 二进制内部决定,host.py 只传
|
||||
sandboxPolicy 类型、没有任何挂载旋钮,所以本仓库改不
|
||||
了它;2026-10-26 宿主实测 agent 写 /tmp 落到宿主 /tmp,
|
||||
本轮未在宿主重测、也不宣称已修复。需要 /tmp 隔离的
|
||||
任务请走 docker 执行器,不要走宿主级沙箱 worker。
|
||||
本函数是状态宣告,不是修复开关:调用方绝不能拿它的
|
||||
docker=True 去给宿主级任务背书。
|
||||
"""
|
||||
return {
|
||||
"docker": True,
|
||||
"host_bwrap": False,
|
||||
"docker_detail": "per-container tmpfs /tmp + /var/tmp, removed with --rm",
|
||||
"host_bwrap_detail": "bwrap mounts are owned by the codex binary;"
|
||||
" host.py passes only a sandboxPolicy type"
|
||||
" and has no mount knob; /tmp is shared"
|
||||
" with the host (2026-10-26 host test)",
|
||||
}
|
||||
# 任务结果文本上限:2000 字截断的是 host.py 打印的整段 JSON,
|
||||
# text 超过 2000 字时 JSON 本身被截断,worker 再解析 stdout
|
||||
# 取 text 必然失败,存库的就变成截断的 JSON(2026-10-30
|
||||
@@ -1111,23 +1138,33 @@ class DockerExecutor(Executor):
|
||||
cmd += ["--runtime", self.runtime]
|
||||
if network:
|
||||
cmd += ["--network", network]
|
||||
cmd += ["-v", "%s:/work" % self._worktree_for(task),
|
||||
"-v", "%s:/app:ro" % self._app_dir(),
|
||||
"-w", "/work"]
|
||||
# 额外挂载放在基础挂载之后:/app/work 这类子路径挂载会
|
||||
# 覆盖 /app:ro 的对应子路径,让容器内 host.py 能写
|
||||
# work/ 和 host-state.json,同时代码主体仍只读。
|
||||
mounts = self.extra_mounts if extra_mounts is None \
|
||||
else self._parse_extra_mounts(extra_mounts)
|
||||
for host_p, cont_p, mode in mounts:
|
||||
cmd += ["-v", "%s:%s:%s" % (host_p, cont_p, mode)]
|
||||
# /tmp 固定为 tmpfs:容器内 /tmp 绝不落在宿主 /tmp,也不受
|
||||
# 额外挂载影响(/tmp 目标的额外挂载已在解析时拒绝)。
|
||||
# /tmp 固定为 tmpfs,且必须放在所有 -v 挂载之前:父挂载
|
||||
# 在前、子挂载在后是 Linux 挂载顺序的基本要求——附件
|
||||
# seed 以 /tmp/codex-seed:ro 挂进容器(见 dispatch_task),
|
||||
# 它是 /tmp 之下的子挂载,只有 tmpfs 先挂、seed 后挂,
|
||||
# seed 才不会被后挂的 tmpfs 遮掉。旧顺序把 --tmpfs 放在
|
||||
# 全部 -v 之后,本 VM 无 docker、未在真实 docker 上证实
|
||||
# 旧顺序确实遮挡(docker 可能按父子关系重排),所以这里
|
||||
# 写为顺序加严而非“已证实 bug 修复”;单测只断言顺序,
|
||||
# 不宣称旧顺序一定失效。
|
||||
# 容器内 /tmp 绝不落在宿主 /tmp,也不受额外挂载影响
|
||||
# (/tmp 目标的额外挂载已在解析时拒绝)。
|
||||
# 诚实边界:这是 Docker 外层能做的;内层 codex 的 bwrap
|
||||
# workspace-write 仍由 codex 二进制控制,本仓库改不了它
|
||||
# 的 --proc 挂载,宿主级 bwrap 的 /tmp 不隔离问题也不在
|
||||
# 本仓库的修复范围内——不要把本改动说成“内层沙箱已修”。
|
||||
cmd += ["--tmpfs", "/tmp", "--tmpfs", "/var/tmp"]
|
||||
cmd += ["-v", "%s:/work" % self._worktree_for(task),
|
||||
"-v", "%s:/app:ro" % self._app_dir(),
|
||||
"-w", "/work"]
|
||||
# 额外挂载放在基础挂载之后:/app/work 这类子路径挂载会
|
||||
# 覆盖 /app:ro 的对应子路径,让容器内 host.py 能写
|
||||
# work/ 和 host-state.json,同时代码主体仍只读;seed 的
|
||||
# /tmp/codex-seed:ro 同样在此后挂载,压在 tmpfs 之上。
|
||||
mounts = self.extra_mounts if extra_mounts is None \
|
||||
else self._parse_extra_mounts(extra_mounts)
|
||||
for host_p, cont_p, mode in mounts:
|
||||
cmd += ["-v", "%s:%s:%s" % (host_p, cont_p, mode)]
|
||||
if self.env_key:
|
||||
cmd += ["-e", self.env_key]
|
||||
merged_env = dict(self.extra_env)
|
||||
|
||||
Reference in new issue
Block a user