残留批次A:成员删除、PR needs_local_worker 落库、推送 DNS TOCTOU

- 成员删除:DELETE /projects/{id}/members/{user_id},限 owner 或
  全局管理员,禁删唯一 owner,记 remove_member 审计
  (AuthStore.remove_member + server 分发,沿用 PATCH 守卫口径)
- PR needs_local_worker 落库:非 local 扫到 queued 任务时 CAS
  写行状态为 needs_local_worker;claim/find_open 同步认该状态,
  标记过的行仍可被 local worker 认领、不被搁置;另修
  claim/find_open 对裸 sqlite3 tuple 行的 dict() 兜底
  (TypeError/ValueError)
- 推送 DNS TOCTOU:发送改走建连时解析+判段的连接类,解析
  一次、只拨判过的 IP,Host/SNI 仍为原域名;opener 直接构造
  以排除 ProxyHandler 改写(build_opener 默认会塞代理)
This commit is contained in:
host committed 2026-10-27 19:10:49 +00:00
1 parent 6e3eb7ba11
commit 9bb9a50e4e
10 files changed
+725 -38

No files matched your search

+27 -15
View File
@@ -153,7 +153,8 @@ from cloud.sub2api import gateway_name as _gateway_name
from cloud.sub2api import gateway_origin as _gateway_origin
from cloud.sub2api import list_gateway_models as _list_gateway_models
from cloud.pr import PrSkipped, PrStepError
from cloud.pr_exec import (claim_pr_job, execute_task_pr, finish_pr_job)
from cloud.pr_exec import (claim_pr_job, execute_task_pr, finish_pr_job,
mark_pr_job_needs_local_worker)
from cloud.queue import budget_exceeded, ready_tasks
from cloud.repos import RepoError, checkout_dir, resolve_repo
from cloud.sandbox import CloudExecutor, DockerExecutor, LocalExecutor
@@ -3547,19 +3548,15 @@ class Worker:
P1 非 local 通道:旧版非 local worker 直接返回 [],
排队的 pr 任务看起来像“没人处理”且无任何痕迹——
静默未完成。现在改为显式 needs_local_worker:只读
peek 本主机 queued 的 pr 任务,逐条记审计 + 日志并
返回 needs_local_worker 条目,任务本身保持 merged、
pr 任务保持 queued(留给 local worker 认领),绝不
把它标 failed(failed 会让调用方以为 PR 已失败,且
任务仍可重调 /pr 的语义会被混淆)。为什么不直接把
pr_jobs 行写成 needs_local_worker 状态:pr_jobs 的认
领只认 queued(claim_pr_job 在 pr_exec.py,本路不改
该文件),写成新状态后 local worker 也认领不到,任务
会被永久搁置;真要落库状态,需 pr_exec.py 的认领同
步改成含 needs_local_worker 或 local 重排队——该改动
留给协调员(见汇报残留),本路不伪造一个“写了状态
却没人能接”的通道。签名无效时同样不碰任务(返回 [],
只记日志),fail-closed。
peek 本主机 queued 的 pr 任务,逐条把行状态持久化
为 needs_local_worker(CAS,只改仍是 queued 的行,
已被 local worker 认领的不覆盖),并记审计 + 日志
返回 needs_local_worker 条目。任务本身保持 merged,
pr 任务保持可被 local worker 认领(claim_pr_job
同时认 queued 与 needs_local_worker),绝不把它标
failed(failed 会让调用方以为 PR 已失败,且任务仍
可重调 /pr 的语义会被混淆)。签名无效时同样不碰
任务(返回 [],只记日志),fail-closed。
"""
if not self._code_signature_valid():
log_event(self.logger, "worker_pr_refused_code_signature",
@@ -3588,8 +3585,23 @@ class Worker:
continue
reason = ("PR 执行需要 local worker(host-worktrees"
" 只在主机上可见),本 worker 为 %s,"
"任务保持 queued 等 local worker 认领"
"任务保持可认领等 local worker 认领"
% self._executor_name())
marked = False
try:
conn = _db_connect(self.db_path)
try:
marked = mark_pr_job_needs_local_worker(
conn, job_id, reason)
finally:
conn.close()
except Exception as exc:
log_event(self.logger, "pr_job_mark_failed",
message="pr job mark failed: %s" % exc)
continue
if not marked:
# 已被 local worker 认领或已终态:不覆盖、不重复记。
continue
self._audit(project_id, "pr_job_needs_local_worker",
"%s: %s" % (job_id, reason))
log_event(self.logger, "pr_job_needs_local_worker",