Files
storage-labos/flashops/docs/decisions/0004-safety-in-control-plane.md
yuanshuai c91a64fddb
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run
chore(repo): initialize team collaboration repository
2026-07-27 20:40:12 +08:00

2.6 KiB
Raw Permalink Blame History

ADR-0004:安全门禁放在控制平面,Agent 保持"笨"

  • 日期:2026-07-27
  • 状态:已接受

背景

危险动作有三类:刷固件、Format/Sanitize、断电。任何一次误盘 = PoC 判定失败 (方案 §9.3:0 次错盘、0 次系统盘破坏)。

门禁可以放在 Agent(离设备近,判断准)或控制平面(离决策近,可审计)。

决定

全部放控制平面,且拒绝发生在下发之前。Agent 只执行已批准的命令模板 + schema 校验过的参数,自己不做任何"这条命令安不安全"的判断。

Agent 侧保留的唯一防线是 precheck(设备在不在、路径对不对), 它是执行前自检,不是安全决策。

理由

  • 可审计:审批记录、模板版本、操作者、参数必须与决策在同一个地方, 否则审计链断在 Agent 上。客户安全评审第一个问的就是这个。
  • Agent 可信度低:Agent 跑在客户的测试主机上,那台机器会蓝屏、会被人手动改配置、 会装乱七八糟的工具。安全判断不能依赖一个随时可能处于异常状态的环境。
  • 升级路径:安全规则改了,改控制平面就全网生效。要靠 Agent 判断, 就得推送 Agent 升级到每台客户主机——在实验室里这是以周计的事。
  • 可测试:门禁是纯函数(safety/gates.py),误盘场景可以在单测里穷举, 不需要真的接一块盘来试。

具体门禁(safety/gates.py

  1. DUT 绑定:序列号 + 设备路径 + allow_destructive 标签三信号一致才放行。 任一不匹配 → 拒绝,记 SAFETY_REJECTED 事件。
  2. 系统盘保护:解析目标设备的挂载点/启动标志/分区表,命中系统盘立即拒绝。 这一条没有 override 开关,代码里不给绕过的口子。
  3. 命令模板白名单:危险命令只能来自 safety/templates.py 注册表, 参数受 JSON Schema 约束。不接受自由文本命令行。
  4. 环境指纹一致性:A/B 对比的两次运行环境指纹不一致 → 结论标记为不可比。

代价

  • 控制平面必须掌握足够的设备信息才能判断(依赖 Agent 上报的设备探针数据)。 上报延迟 → 判断基于稍旧的数据。缓解:危险步骤执行前强制刷新一次探针, Agent 的 precheck 再做一次现场核对,两者不一致直接拒绝。
  • 多一次往返。危险动作本来就不该快。

什么时候推翻

不推翻。可以增强(加人工审批门、加双人复核),但不下放到 Agent。