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:
host committed 2026-11-03 02:49:25 +00:00
1 parent 143ab30094
commit 06710cf47b
7 files changed
+897 -48

No files matched your search

+11 -6
View File
@@ -1189,6 +1189,10 @@ def migrate_tasks_table(conn):
# HA 阶段 1:认领任务的 worker 所在主机名;/pr 据此判断
# worktree 在本机(同步跑)还是别机(排 pr 任务给该主机)。
"worktree_host": "TEXT",
# 沙箱规模:认领任务的 worker_id(worker._claim 在 CAS
# 认领时写);失联容器识别的 owner 依据,见
# workers.orphaned_containers。老行 NULL = 无 owner 记录。
"claimed_by_worker": "TEXT",
# 任务级选项(console 选模型/强度/权限用):NULL = 跟随
# worker 配置默认值;model 不做白名单(中转目录会变,
# 下拉只是建议值),effort/approval 由 _create_task 校验。
@@ -1959,6 +1963,7 @@ def _task_to_dict(row, attachments=None, total_tokens=None):
"attachments": list(attachments or []),
"resume_message": _row_get(row, "resume_message"),
"worktree_host": _row_get(row, "worktree_host"),
"claimed_by_worker": _row_get(row, "claimed_by_worker"),
"model": _row_get(row, "model"),
"effort": _row_get(row, "effort"),
"child_model": _row_get(row, "child_model"),
@@ -9068,9 +9073,11 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
executor/capacity/running/host/pid/address。心跳本身就是
注册:worker_id 不存在时自动注册,绝不 404。running 是
worker 上报的当前占用槽数(启动中占位也算);未给时保留
旧值。host/pid/address 只存调用方显式给的值:远程 worker
的 host/pid 绝不由 server 本机推导(server 的主机名/进程
号不是该 worker 的),未给时保留旧值。"""
旧值。host/pid/address 只存调用方显式给的值:远程 worker
的 host/pid 绝不由 server 本机推导(server 的主机名/进程
号不是该 worker 的),未给时保留旧值;host 须为字符串、
pid 须为整数、address 须为字符串,否则 400(注册表里的
寻址信息错了比没有更危险,失联判断会拿错 host/pid 当证据)。"""
body, err = self._read_json()
if err:
self._send_json(400, {"error": err})
@@ -9103,9 +9110,7 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
return
pid = body.get("pid")
if pid is not None:
try:
pid = int(pid)
except (TypeError, ValueError):
if isinstance(pid, bool) or not isinstance(pid, int):
self._send_json(400, {"error": "pid must be an integer"})
return
if pid <= 0: