9.6 KiB
IAM U3 阶段 6 审阅后契约修订与补测计划 r1
状态:待阶段 4–5 人工重审;日期:2026-10-14。本文是已批准 U3 r1 的增量修订,不替换其已批准正文。对象是 U3 实施候选在合并 Backend U7 账号事务后暴露的四项缺口;U4–U9、生产迁移、部署和真实账户操作不在本次授权申请内。
1. 当前证据与为什么要重审
U3 r1 的实施候选为 Backend 4053c4d038b1d13a356e0196db56ab11c0e4f8e1、RDM 源码 ad815febce522d029a74cd90217409efc9a81c35、Frontend a961b19ebb793d6c02a72002050d269700b1a5bd。Backend 在此后有未提交的审阅修复候选;它们不是已批准或已验收版本。Dev 任务卡 feature/iam-u3-account-directory-recovery 保存上述固定版本的 SELF 收据,RDM 任务卡保存源码外 Go overlay 的 SELF 收据。正式 pin、独立重放、GATE、生产与部署均 NOT_RUN。
独立只读代码审阅发现以下可复现缺口;现有绿色单测不推翻这些代码路径事实:
| ID | 触发与证据位置 | 对 U3 r1 的影响 |
|---|---|---|
| A1 在途写入 | internal/server/server.go 的 createProject 在读取请求体后调用 Store.CreateProject;internal/store/projects.go 插入时不读取当前账号。请求通过认证后暂停,另一连接停用账号,再继续请求,项目仍可在停用提交之后写入。其它非 GET 业务入口须同样盘点,不能只修这一条。 |
违反 r1 §7 Backend 有后果写入前检查有效态;同库可闭合的窗口尚未闭合。 |
| A2 API key 隐式建号 | internal/app/app.go 的 CreateAPIKey 调用 Store.CreateAPIKey;后者 EnsureUser 可创建启用、来源为 legacy 的账号,再签发完整 API key。 |
绕过 r1 §3 待初始化账号及首凭据边界;纯集成账号的历史读取兼容与新增建号须分开。 |
| A3 锁顺序 | 合并 U7 后普通建号走 account 锁再取 bootstrap 锁;首管及本地建号曾反向取得两锁,同 owner 并发有 PG 死锁风险。 | 影响首管与并发建号的活性及 U7 的准入保证。 |
| A4 游标与可见版本 | internal/app/account_directory.go 和 internal/server/account_search.go 以进程内随机密钥签游标,负载均衡切到另一实例时下一页 409。受限候选的版本又组合了全局 public revision,域外账号改名也会使该域游标过期。 |
违反 r1 §5 多实例分页及“目录版本只受可见辨识资料/有效态变化影响”的范围;后一问题还可成为域外活动侧信道。 |
本次提出的处理改变持久数据设计(共享游标签名密钥)和账号入口兼容行为(阻断 API key 隐式建号),并需要把原计划的“写前复验”细化为同库提交围栏。按 Dev policy/delivery.md 的“技术路线、模块职责、公开契约、数据或权限设计……修订方案或计划,经人工重审后继续”,阶段 6 评审暂缓,先审本文阶段 4–5 修订。
2. 修订后的契约
A1:同库账号写入围栏
Backend 自有数据库内,每个以账号身份执行的有后果业务写入,必须在最终写事务内按统一顺序取得该 actor 的账号锁,读取当前 enabled 并在同事务提交业务变更。若目标资源另有 owner,仍由领域授权决定可写范围;账号锁不能授予项目或文档权限。停用事务取得相同账号锁并推进有效态,因此并发结果只能是业务写入先提交、停用后提交,或停用先提交、业务写入拒绝;不得出现停用提交后旧请求再写入成功。
实现采用显式 Store 事务入口和逐路由终点映射,不在请求全程持有额外数据库连接,也不以“handler 刚检查过”代替事务内复验。先盘点 Backend 当前 66 条非 GET API 路由,将凭据/资料写入(已有或补充最终事务复验)、Backend 自有业务写入、外部副作用/运行控制、只读或无业务后果动作分别记录。项目、会话消息、工件、设置、任务、工具/命令等适用的 Backend 自有写入改由同一账号锁和事务检查;文件或外部工具在真正执行前重验并使用既有取消机制,不能宣称跨外部系统原子性。auth-off 的本地默认 owner 继续按 r1 的嵌入式隐式身份规则处理;若存在明确停用记录则拒绝。独立 RDM 数据库的最终提交窗口沿用 r1 §7 已声明限制,不在 U3 声称零窗口跨库 fencing。
变更须给出“路由 → 最终 sink → actor/owner 来源 → 围栏方式 → 重放用例”清单;有未覆盖的有后果入口即阻止阶段 6 完成。对同一数据库中的认证版本、会话/API key 在途撤销窗口另作影响分析;若需要扩大本次安全承诺,先再修订本文,不用账号 enabled 检查冒充凭据撤销栅栏。
A2:API key 不再建号
本地 apikey create 只对已存在、当前启用、已完成初始化的账号签发;迁移而来的 legacy 账号保留既有无密码集成 Key 兼容,但其 Key 不得作为 U3 本人恢复证明。待初始化账号、停用账号及不存在的 owner 拒绝,不执行 EnsureUser、不新增账号或 Key;现有 Key 不因本修订自动撤销。CLI 由当前机器/DB owner 边界执行,不能通过普通管理员 HTTP 或角色 grant 自助补领。未来新增纯集成账号须单列身份/授权方案,不能借 apikey create 的历史便利隐式建号。
Store 的旧 CreateAPIKey 目前被许多内部测试当建号 fixture 使用。生产调用入口先收紧;实施时应把内部 fixture 与正式签发 API 分离,并扫描所有非测试调用者,避免新调用重新打开隐式建号旁路。CLI 对不存在 owner 的返回由“创建并签发”改为明确拒绝,这是有意兼容收紧。
A3:统一锁序
PG 账号事务统一按账号 owner 升序取得账号 advisory lock,再取得首次建号/末位管理员保护所需 bootstrap lock,然后锁用户行及后续 proposal、grant、session。SQLite 保持同等业务检查,依靠写事务串行。普通建号与首管竞争仍须保留 U7 的“空库同时入场仅一方成功”语义;不能通过改锁顺序让两方都成功。多 owner 操作按稳定排序,事务内重查 ID、版本和管理员资格。不得用死锁重试掩盖顺序倒置。
A4:共享、分域且可见的游标
使用 256-bit CSPRNG 密钥,经共享账号数据库的 compare-and-set 在首次需要时原子持久化;保存密钥版本,绝不输出到 API、日志、任务卡或浏览器。管理搜索与领域目录以不同 HMAC 域签名,游标绑定密钥版本及 r1 原定的 actor、purpose、locator、范围、匹配字段、查询、过滤、可见目录版本。多实例从同一数据库读取同一密钥;密钥读取失败拒绝分页,旧进程本地随机游标切换时返回明确冲突并要求重新查询,不静默换页。
AllCandidates 的公共辨识变化可以使用全局公开 revision;有限候选范围的版本应由当前可见候选集合内的稳定 ID、有效态与获准辨识字段及领域 ScopeVersion 形成,不加入域外账号或未授权字段。快照读取与游标版本计算需在一致的数据库视图内完成,或在返回前复核版本并拒绝过期结果,避免版本与页面来自不同时间点。资料私密字段编辑不改变不获准字段的目录版本;当前允许披露的 staffNo 独立纳入版本。候选名单变化须失效旧游标。
若权威数据库已经实际应用 U3 v32,不能就地修改其迁移正文,必须追加新的迁移并给出旧游标废止步骤;只有证明 v32 尚未进入任何持久实例,才可在未发布候选内修订 v32。U7 account_audit 占 v31,U3 账号基础/恢复仍按已合并候选的 v32/v33 排序。
3. 实施与验证顺序
- 固定当前主干与候选 SHA,盘点 66 条非 GET 路由、Host/runmgr 出口及账号写入者;给每条有后果 sink 指定最终有效态围栏和测试。完成 A2 生产入口及内部 fixture 分离,补“不存在/pending/disabled 均不建号或签 Key”双档测试。
- 按 A3 统一 PG 锁序。用两个独立连接/进程和可控屏障覆盖首管对普通建号、同 owner 建号、管理员停用对初始化/改密;验证无死锁、唯一成功与事务审计。
- 落 A4 密钥持久化、域分隔和范围内版本;补 SQLite 两 Store、PG 两实例跨进程翻页、字段/范围变动、域外改名、密钥不可见和故障拒绝测试;确认迁移版本前置事实。
- 按 A1 路由清单逐类实现最终写围栏。用暂停请求体和暂停最终 SQL 写入的确定性测试,在 SQLite、PG 双连接与 PG 两进程验证“停用先提交则无晚到写”;覆盖项目、消息、工件、设置等代表性入口及实际 RDM 限制说明。外部副作用单独验证最后检查与取消。
- 同步最新 main,重跑 Backend 全包、PG Store/Server、RDM 源码外组合与 Frontend 正常测试;对受影响真实浏览器路径重放。三仓正式 pin、GATE、独立 Review、阶段 7 验收仍遵守原计划的后续人工节点和受信发布前置。
4. 评审决定
请只裁定是否批准本修订的阶段 4–5,使 U3 阶段内可继续上述修复和隔离验证,然后重新提交阶段 6 人工评审。不请求现阶段批准阶段 6、阶段 7、PR 合入、受信版本 tag、真实机器/数据库账号操作、生产迁移或部署。若 A1 的全路由写围栏成本或 A2 的 CLI 兼容收紧不可接受,应在此处明确缩小验收承诺或另立增量;不得保留原 U3 §7 的完成声明同时留下已知晚到写。