feat: cloud 门禁/超时/成本/沙箱收敛为单一判定源
- 新增标准库叶子层 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 项。
This commit is contained in:
1 parent
2720acef46
commit
41e8c98512
16 files changed
+1068
-301
No files matched your search
+125
@@ -0,0 +1,125 @@
|
||||
"""门禁层:调用方只传事实,本层只出决定。
|
||||
|
||||
收敛对象是主线上已经存在的硬门禁,不是新发明的门禁
|
||||
种类。主线(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"
|
||||
Reference in new issue
Block a user