Docker sandbox real test + cloud merge status endpoint
- DockerExecutor: extra mounts (host.py work/state, repo, codex-home
at same paths), worker --docker-extra-mounts, container user
configurable; Dockerfile copies codex-resources beside the codex
binary and puts bwrap on PATH (previous /usr/local/lib layout
made codex report bubblewrap unavailable inside the container).
- Real Docker task on external host: triple added in ~18s, merged
inside a container, main repo now add+mul2+triple, --rm cleanup.
Honest boundary: this host/kernel forbids unprivileged user
namespaces, so bwrap fails on host and in containers; production
mode here is Docker isolation + inner danger-full-access, not
double sandboxing.
- Cloud merge status: POST /tasks/{id}/merge syncs status only
(merge itself stays with host.py merge); completed -> merged,
maintainer+ (approve_merge), other states and repeat calls 409,
audit merge_task. Tests: cloud 223, host 27, all passing.
This commit is contained in:
1 parent
631580beab
commit
07a8eaaa73
9 files changed
+1082
-37
No files matched your search
+51
-2
@@ -14,8 +14,8 @@
|
||||
cost 的 CostStore、webhooks 的 NotificationService)本版尚未接成
|
||||
HTTP 端点,留给 worker 接线时调用;本 server 只接入其中两处:
|
||||
AuthStore(认证/权限/审计)与 webhooks 的验签/解析函数。
|
||||
- DockerExecutor/CloudExecutor 目前仍是占位(见 sandbox.py),
|
||||
本 server 不假装已接通容器或云端执行。
|
||||
- DockerExecutor 已接通(见 sandbox.py),CloudExecutor 目前仍是占位
|
||||
(见 sandbox.py),本 server 不假装已接通云端执行。
|
||||
|
||||
导入规则:只用绝对包导入(from cloud.auth import ...)。绝不要把
|
||||
cloud/ 目录加进 sys.path:标准库已有 queue 模块,会和 cloud/queue.py
|
||||
@@ -367,6 +367,8 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
self._task_cost(user_id, rest[: -len("/cost")])
|
||||
elif rest.endswith("/cancel") and method == "POST":
|
||||
self._cancel_task(user_id, rest[: -len("/cancel")])
|
||||
elif rest.endswith("/merge") and method == "POST":
|
||||
self._merge_task(user_id, rest[: -len("/merge")])
|
||||
elif rest.endswith("/heartbeat") and method == "POST":
|
||||
self._heartbeat_task(user_id, rest[: -len("/heartbeat")])
|
||||
else:
|
||||
@@ -984,6 +986,53 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
store.audit(user_id, task["project_id"], "cancel_task", task_id)
|
||||
self._send_json(200, task)
|
||||
|
||||
def _merge_task(self, user_id, task_id):
|
||||
"""把云端任务标记为已合并:只补状态,不执行合并本身。
|
||||
|
||||
合并本身仍由 host.py merge(本地或 Docker 容器内)执行,
|
||||
成功后再调本接口同步云端状态——两者分离是故意的:合并
|
||||
是要人看 diff 才点的操作,云端不该在任务 completed 时
|
||||
自动把主分支改了。规则:任务必须存在(404)、调用方
|
||||
必须是项目 maintainer 以上(approve_merge,403)、任务
|
||||
必须是 completed(其它状态一律 409,含已 merged 的重复
|
||||
调用,避免二次合并混淆)。成功后写审计 merge_task。
|
||||
"""
|
||||
row = self._fetch_task(task_id)
|
||||
if row is None:
|
||||
self._send_json(404, {"error": "task not found"})
|
||||
return
|
||||
task = _task_to_dict(row)
|
||||
with _auth_store(self.server.db_path) as store:
|
||||
if not store.check_permission(
|
||||
user_id, task["project_id"], "approve_merge"):
|
||||
self._send_json(403, {"error": "forbidden"})
|
||||
return
|
||||
if task["status"] != "completed":
|
||||
self._send_json(409, {
|
||||
"error": "only completed tasks can be marked merged",
|
||||
"status": task["status"],
|
||||
})
|
||||
return
|
||||
now = time.time()
|
||||
conn = self._db()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE tasks SET status = 'merged', updated_at = ?"
|
||||
" WHERE id = ?",
|
||||
(now, task_id),
|
||||
)
|
||||
conn.commit()
|
||||
task = _task_to_dict(
|
||||
conn.execute(
|
||||
"SELECT * FROM tasks WHERE id = ?", (task_id,)
|
||||
).fetchone()
|
||||
)
|
||||
finally:
|
||||
conn.close()
|
||||
with _auth_store(self.server.db_path) as store:
|
||||
store.audit(user_id, task["project_id"], "merge_task", task_id)
|
||||
self._send_json(200, task)
|
||||
|
||||
def _heartbeat_task(self, user_id, task_id):
|
||||
row = self._fetch_task(task_id)
|
||||
if row is None:
|
||||
|
||||
Reference in new issue
Block a user