残留批次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:
1 parent
6e3eb7ba11
commit
9bb9a50e4e
10 files changed
+725
-38
No files matched your search
+43
-9
@@ -54,18 +54,23 @@ def ensure_pr_jobs_table(conn):
|
||||
|
||||
|
||||
def find_open_pr_job(conn, task_id):
|
||||
"""找该任务未完成的 pr 任务(去重:同一任务同时只排一个)。"""
|
||||
"""找该任务未完成的 pr 任务(去重:同一任务同时只排一个)。
|
||||
|
||||
needs_local_worker 也算未完成:非 local worker 标记过的任务
|
||||
仍在等 local worker 认领,再调 /pr 必须复用它,不能重排。"""
|
||||
ensure_pr_jobs_table(conn)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM pr_jobs WHERE task_id = ?"
|
||||
" AND status IN ('queued', 'running')"
|
||||
" AND status IN ('queued', 'running', 'needs_local_worker')"
|
||||
" ORDER BY created_at ASC LIMIT 1",
|
||||
(task_id,)).fetchone()
|
||||
if row is None:
|
||||
return None
|
||||
try:
|
||||
return dict(row)
|
||||
except TypeError:
|
||||
except (TypeError, ValueError):
|
||||
# 裸 sqlite3 连接(无 Row 工厂)返回 tuple:dict() 对
|
||||
# tuple 抛 ValueError(对 Row 抛 TypeError 的旧路径不动)。
|
||||
return {"id": row[0], "task_id": row[1], "project_id": row[2],
|
||||
"host": row[3], "status": row[4]}
|
||||
|
||||
@@ -84,34 +89,63 @@ def enqueue_pr_job(conn, task_id, project_id, host):
|
||||
|
||||
|
||||
def claim_pr_job(conn, host):
|
||||
"""CAS 认领本主机的一个 queued pr 任务(最老优先)。
|
||||
"""CAS 认领本主机的一个 pr 任务(最老优先)。
|
||||
|
||||
两个同主机 worker 抢同一任务时只有一个能拿到 rowcount == 1。
|
||||
认领 queued 与 needs_local_worker 两种状态:后者是非 local
|
||||
worker 标记的“需 local worker”任务,仍在等 local worker,
|
||||
必须能被认领(否则标记等于搁置)。两个同主机 worker 抢
|
||||
同一任务时只有一个能拿到 rowcount == 1。
|
||||
返回任务 dict 或 None。
|
||||
"""
|
||||
ensure_pr_jobs_table(conn)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM pr_jobs WHERE host = ? AND status = 'queued'"
|
||||
"SELECT * FROM pr_jobs WHERE host = ?"
|
||||
" AND status IN ('queued', 'needs_local_worker')"
|
||||
" ORDER BY created_at ASC LIMIT 1",
|
||||
(host,)).fetchone()
|
||||
if row is None:
|
||||
return None
|
||||
job_id = row["id"] if hasattr(row, "__getitem__") else row[0]
|
||||
try:
|
||||
job_id = row["id"]
|
||||
except TypeError:
|
||||
# 裸 sqlite3 连接(无 Row 工厂)返回 tuple:按位置取。
|
||||
# hasattr(__getitem__) 判据对 tuple 也为真,不能用它区分。
|
||||
job_id = row[0]
|
||||
now = time.time()
|
||||
cur = conn.execute(
|
||||
"UPDATE pr_jobs SET status = 'running', started_at = ?,"
|
||||
" updated_at = ? WHERE id = ? AND status = 'queued'",
|
||||
" updated_at = ? WHERE id = ?"
|
||||
" AND status IN ('queued', 'needs_local_worker')",
|
||||
(now, now, job_id))
|
||||
conn.commit()
|
||||
if cur.rowcount != 1:
|
||||
return None
|
||||
try:
|
||||
return dict(row)
|
||||
except TypeError:
|
||||
except (TypeError, ValueError):
|
||||
# 同上:tuple 行的 dict() 抛 ValueError。
|
||||
return {"id": row[0], "task_id": row[1], "project_id": row[2],
|
||||
"host": row[3], "status": "running"}
|
||||
|
||||
|
||||
def mark_pr_job_needs_local_worker(conn, job_id, reason):
|
||||
"""把 queued 的 pr 任务标为 needs_local_worker(CAS)。
|
||||
|
||||
只有仍是 queued 时才改写并返回 True;已被 local worker
|
||||
认领(running)或已终态时返回 False,绝不覆盖。标记后
|
||||
任务仍可被 local worker 认领(见 claim_pr_job),只是
|
||||
重读时能看到它在等 local worker,而不是“没人处理”。
|
||||
"""
|
||||
ensure_pr_jobs_table(conn)
|
||||
now = time.time()
|
||||
cur = conn.execute(
|
||||
"UPDATE pr_jobs SET status = 'needs_local_worker', error = ?,"
|
||||
" updated_at = ? WHERE id = ? AND status = 'queued'",
|
||||
(reason, now, job_id))
|
||||
conn.commit()
|
||||
return cur.rowcount == 1
|
||||
|
||||
|
||||
def finish_pr_job(conn, job_id, status, pr_url=None, pr_number=None,
|
||||
error=None):
|
||||
"""写回 pr 任务终态(completed/failed)。"""
|
||||
|
||||
Reference in new issue
Block a user