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

52 lines
2.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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。