- 新增标准库叶子层 timeouts/gates/quota/sandbox_policy: 审批 3600 与单轮 600 各有名常量与环境覆盖层,已建项 expires_at 永不重算;目录/控制/合并状态门禁统一判定, 目录违规无任何覆盖参数;配额取数与比较唯一来源 (USD 先于无价、命中均为 >=、无价只计 actual 行); /tmp 隔离矩阵与失联清理判定纯函数化。 - 调用点委托:server/worker/automations/auto_memory 的 配额 SQL 与比较、server/tree/marker 的目录解析、 marker 的控制门、sandbox 的任务容器名正则、两处 300 秒 陈旧阈值默认值均收敛,别名与错误文案不变。 - 统一两个 P0 口径分歧:服务端无价计数由全部 usd IS NULL 行改为 actual-only;显式不限额用户在服务端准入亦不受 无价上限约束(与 worker 运行时一致)。 - 不新增门禁种类与 record 模式(主线无此实现);不改 skill_seed/skills/SKILL.md;不改 v1.1 契约与分支保护。 - 新增 test_arch_converge.py 18 项。
126 lines
5.5 KiB
Python
126 lines
5.5 KiB
Python
"""门禁层:调用方只传事实,本层只出决定。
|
||
|
||
收敛对象是主线上已经存在的硬门禁,不是新发明的门禁
|
||
种类。主线(origin/main)上不存在 merge_gate 的
|
||
record/enforce 模式、分支保护门禁与全自动门禁——那些只
|
||
在未合并的分支里;本轨不从分支搬功能、不新增门禁种类、
|
||
不把硬门禁降级为“只记录不阻断”(那会削弱安全语义,
|
||
不属于收敛)。本层收敛的是三类已有判定:
|
||
|
||
1. 目录门(resolve_inside):worktree 内相对路径的安全
|
||
解析。服务端 _safe_worktree_path、cloud/tree.py 的
|
||
resolve_tree_path、cloud/marker_tools.py 的
|
||
safe_worktree_path(worker 经 marker_tools 调用)此前
|
||
各写了一份 realpath + commonpath,仅在 commonpath
|
||
的 ValueError 处理上不一致(服务端不捕,另两处捕)。
|
||
现统一为本函数:绝对路径、.. 逃逸、符号链接逃逸、
|
||
跨盘符 ValueError 一律拒绝;空串返回原 worktree。
|
||
2. 控制门(decide_control):marker_tools.check_control_gate
|
||
的纯函数判定(cancel / retry 的目标状态与派生关系),
|
||
现为本层 canonical 实现,marker_tools 只保留同名薄壳
|
||
(调用点与测试 import 的名字不变)。
|
||
3. 合并状态门(merge_state_decision):服务端 _merge_task
|
||
的状态判定——只有 completed 可标记 merged,其它状态
|
||
一律拒绝(含已 merged 的重复调用)。权限判定
|
||
(approve_merge)仍在服务端,不进本层:本层只看事实
|
||
(任务状态),不查权限。
|
||
|
||
不可覆盖规则(冻结):
|
||
- 目录门的拒绝没有任何 confirm / override / bypass 参数。
|
||
本模块的函数签名里 deliberately 没有这类参数:显式
|
||
确认即使存在,也只能覆盖“保护类风险”,绝不能覆盖
|
||
目录违规——而主线上目录违规本来就没有确认通道,
|
||
任何调用方都不得以“用户已确认”为由绕过本层。
|
||
测试钉住:resolve_inside 与 decide_control 的签名中
|
||
不含 confirm / override / bypass 字样。
|
||
- 合并状态门同样没有覆盖参数:非 completed 任务不存在
|
||
“确认后合并”的路径,重复 merged 调用仍是拒绝。
|
||
|
||
返回形态沿用 codebase 的元组风格:(allowed, reason),
|
||
reason 为空表示放行;目录门另有 resolve_inside 直接
|
||
返回路径或 None(旧调用点的形态不变)。
|
||
"""
|
||
|
||
import os
|
||
|
||
TERMINAL_STATUSES = ("completed", "failed", "interrupted", "merged",
|
||
"merge-failed")
|
||
RETRYABLE_STATUSES = ("failed", "interrupted", "merge-failed")
|
||
|
||
|
||
def resolve_inside(base, rel):
|
||
"""worktree 内相对路径的安全解析:越界回 None。
|
||
|
||
空串返回 base 本身(旧三处行为一致);绝对路径、
|
||
.. 逃逸、符号链接逃逸、commonpath 跨盘符 ValueError
|
||
一律 None。目录内指回内部的符号链接放行到真实位置
|
||
(调用方仍只拿到 worktree 内的内容)。
|
||
"""
|
||
if not rel:
|
||
return base
|
||
if os.path.isabs(rel):
|
||
return None
|
||
real_base = os.path.realpath(base)
|
||
target = os.path.realpath(os.path.join(real_base, rel))
|
||
try:
|
||
if os.path.commonpath([real_base, target]) != real_base:
|
||
return None
|
||
except ValueError:
|
||
return None
|
||
return target
|
||
|
||
|
||
def is_goal_task(task):
|
||
"""goal 任务判定:verify_command 非空或 goal_mode 为真。
|
||
|
||
与 worker run_one 的 goal 分支同款;goal 字段本身是
|
||
goal_mode=1 时 prompt 的副本,不单独当判定条件。
|
||
"""
|
||
if not task:
|
||
return False
|
||
return bool(task.get("verify_command") or task.get("goal_mode"))
|
||
|
||
|
||
def decide_control(target, sender, relation, kind):
|
||
"""task-cancel / task-retry 的纯函数门禁,返回 (ok, reason)。
|
||
|
||
kind 只能是 "cancel" 或 "retry",其它值一律拒绝。
|
||
权限层不在这里:worker 侧另查 create_task /
|
||
approve_merge;本函数只管目标状态与关系,单测不需
|
||
AuthStore。goal 任务不可取消或重试(goal 循环自有轮次)。
|
||
"""
|
||
if kind not in ("cancel", "retry"):
|
||
return False, "未知的控制操作"
|
||
if target is None:
|
||
return False, "目标任务不存在"
|
||
if (target.get("project_id") is not None
|
||
and sender.get("project_id") is not None
|
||
and target.get("project_id") != sender.get("project_id")):
|
||
return False, "跨项目任务不可操作"
|
||
if target.get("id") == sender.get("id"):
|
||
return False, "不能操作自己"
|
||
if is_goal_task(target):
|
||
return False, "goal 任务不可取消或重试(goal 循环自有轮次)"
|
||
status = target.get("status")
|
||
if kind == "cancel":
|
||
if status in TERMINAL_STATUSES:
|
||
return False, "目标已终态(%s),不可取消" % status
|
||
else:
|
||
if status not in RETRYABLE_STATUSES:
|
||
return False, ("仅 failed / interrupted / merge-failed"
|
||
" 可重试,当前状态为 %s" % status)
|
||
if relation not in ("descendant", "same_creator"):
|
||
return False, "目标不在发送方派生链上且创建人不同"
|
||
return True, ""
|
||
|
||
|
||
def merge_state_decision(status):
|
||
"""合并标记的状态判定:仅 completed 放行,返回 (ok, reason)。
|
||
|
||
含已 merged 的重复调用在内,其它状态一律拒绝;文案与
|
||
服务端旧 409 错误一致。权限判定不在本层。
|
||
"""
|
||
if status == "completed":
|
||
return True, ""
|
||
return False, "only completed tasks can be marked merged"
|