Record U7 account transaction authorization and spec

Why: account creation, password changes, and bootstrap currently commit in separate steps and do not write an audit row. The spec fixes the transaction, audit, and open-existing boundaries before code changes.
Evidence: SELF precheck receipt already imported at task-start. No runtime test in this commit.
Impact: task card and spec only. Backend behavior is unchanged.
Refs: docs/svc-deploy/u7-account-tx-audit.md
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-12 14:09:19 +00:00
co-authored by Cursor
parent 5b6cc009a0
commit c5488426a8
2 changed files with 93 additions and 25 deletions
+30 -25
View File
@@ -7,44 +7,49 @@
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 4d362537d0e8755a03b1757b5bad92779a064b33
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-u7-account-tx-audit(worktree);分支:feature/u7-account-tx-audit
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
- 交付模式:manual(前序人工决策,智能体 Review/合入);其他阶段明确授权后可记为 authorized-continuous
- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入)
- 自动推进授权:无;授权范围:无;授权来源:无;授权终点:无;停止条件:无(未授权)
- 当前阶段:需求拆解;当前增量:I1(待定义)
- 授权与交付终点:用户 2026-10-12 批准账户方案 r2 新增(R13–R15、KTD11–14、U7)并授权连续推进到「PR 可合入」。本任务交付账户事务、审计、只读打开、凭据输入输出与 capabilities。合入由用户执行。
- 交付模式:authorized-continuous(阶段 1–5 已批准;6–9 按该授权执行,不代签人工测试/Review/合入结论)
- 合入执行:用户
- 自动推进授权:有;授权范围:规格、Backend 实现与测试、Dev 规格/pin/弃用说明、推送与建 PR;授权来源:2026-10-12 会话对实施计划的确认(approve_continuous,顺序 U8→U7→RDM);授权终点:Backend PR 与 Dev pin PR 可合入;停止条件:需改 scripts/svc.sh、对外 HTTP 响应形状或登录页,或需 live 实例/共享 PG 写入/部署,或身份严格核验必须同时改 svc
- 当前阶段:方案设计;当前增量:I1(U7 账户事务、审计与只读打开)
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
- 兄弟任务:feature/u8-sqlite-instance-guard 占用迁移 v28 时,本任务在 task-sync 后把审计迁移顺延到下一个版本号
## 目标与非目标
<预期结果、受影响入口/模块/契约;明确不做什么。>
开户与激活 Key、四条改密路径、以及 `--revoke-all-credentials` 各自在一个事务里提交,并写审计。bootstrap 在事务内串行复核「无用户且无业务数据」。账户运维只打开既有库,不建库、不迁移。凭据不再必须出现在 argv;`capabilities --json` 不碰库。
非目标:不改 scripts/svc.sh;不改登录页;不接 svc 与登录接线(账户 U5);`--dsn` / `--password` 保留并告警,到 U5 再移除。
## 关联方向与规划
- 适用状态:待核对(无适用规划时说明原因)
- 主记录路径/版本:待核对(路径按仓库根目录定位,归档后不变;只引用唯一正文)
- 对应里程碑:待核对
- 适用状态:已有主记录。r2 新增 U7 于 2026-10-12 由用户批准(本会话)
- 主记录路径/版本:modules/documents/docs/proposals/2026-10-12-svc-unified-deploy-and-login-key.md(r2);规格 docs/svc-deploy/u7-account-tx-audit.md
- 对应里程碑:账户方案 U7。Documents 正文的确认状态回写在收口 PR
## 需求分析
| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 |
|---|---|---|---|---|---|---|
| R1 | 待填写 | 待评估 | 待定 | 待定义 | 待确认 | 待评审 |
| R13 | 账户变更同事务且失败不留半态 | 需补齐;建号与 Key、改密与作废 Key 分次提交 | P0 | T7-2、T7-3、T7-5 | 无 | 纳入本增量 |
| R14 | bootstrap 串行且不覆盖已有业务 | 需补齐;只看用户表为空 | P0 | T7-1、T7-4 | U1 身份行 | 纳入本增量 |
| R15 | 账户路径写审计,运维打开不迁移 | 需补齐;audit_events 无账户写入;OpenExisting 仍迁移 | P0 | T7-5 与 T8-4 的不迁移半边 | U8 的 migrate 子命令 | 纳入本增量 |
## 方案与计划
- 方案引用:待填写(含对象版本)
- 实施计划引用:待填写(含增量与需求 ID)
- 测试计划引用:待填写(含需求 ID 与验收条件)
- 方案引用:账户方案 r2 U7;规格 docs/svc-deploy/u7-account-tx-audit.md(本分支)
- 实施计划引用:统一事务助手、严格 INSERT、applyPasswordChange、审计列、账户运维打开模式、capabilities
- 测试计划引用:T7-1–T7-5。PG 用例本地无 AGENT_PG_TEST_DSN 时记 NOT_RUN,GATE 为 Dev CI 的 test-backend-pg。「两个版本的真实更新」记 NOT_RUN
## 阶段评审
| 阶段 | 对象版本 | 结论 | 评审人 | 时间 | 依据 |
|---|---|---|---|---|---|
| 需求拆解 | 待定 | 未评审 | — | — | — |
| 需求评估 | 待定 | 未评审 | — | — | — |
| 需求表确认 | 待定 | 未评审 | — | — | — |
| 方案设计 | 待定 | 未评审 | — | — | — |
| 实施计划 | 待定 | 未评审 | — | — | — |
| 需求拆解 | r2 新增 R13–R15 | 通过 | 用户 | 2026-10-12 | 本会话批准方案设计 |
| 需求评估 | r2 新增 R13–R15 | 通过 | 用户 | 2026-10-12 | 同上 |
| 需求表确认 | r2 新增 R13–R15 | 通过 | 用户 | 2026-10-12 | 同上 |
| 方案设计 | r2 U7 | 通过 | 用户 | 2026-10-12 | 同上 |
| 实施计划 | U8→U7→RDM 计划中的 U7 | 通过 | 用户 | 2026-10-12 | 用户确认按该计划实施 |
| 实施与自检 | 待定 | 未评审 | — | — | — |
| 正式测试与验收 | 待定 | 未评审 | — | — | — |
| 代码 Review | 待定 | 未评审 | — | — | — |
@@ -77,13 +82,13 @@
## 规划进展与下一步
- 本次推进/剩余:待核对(依据实际成果更新适用方案/规划)
- 首选下一任务:待核对(无适用规划、已完成或受阻时如实说明,不虚构任务)
- 推荐依据:待填写
- 前置条件/待确认:待核对
- 预期产物/验收条件:待定义
- 重复任务核对:待核对(已有/在途任务、PR 与规划记录)
- 启动授权:未授权(建议不自动启动新任务,仍须明确授权)
- 本次推进/剩余:本卡交付 U7。随后是 RDM 导出缺口,再是 Documents 收口
- 首选下一任务:RDM U5 导出缺口(D2/D3/D7 与审计页导出入口)
- 推荐依据:2026-10-12 已批实施顺序 U8→U7→RDM
- 前置条件/待确认:U8 先合入时,本分支 task-sync 并顺延迁移版本号
- 预期产物/验收条件:Backend PR 与 Dev pin PR 可合入
- 重复任务核对:feature/u7-ops-drills 是协作存储演练,不是本任务
- 启动授权:已由本会话授权到 PR 可合入;不自动启动 RDM 以外的新任务
## 合入与清理
+63
View File
@@ -0,0 +1,63 @@
# U7 账户事务、审计与只读打开
本规格落实账户方案 r2 的 U7(R13–R15、KTD11–14)。HTTP 响应形状不变。`scripts/svc.sh` 与登录页不在本增量。
## 1. 事务
存储层提供一个事务助手。业务函数在该事务内完成写入,成功则同事务追加审计,失败则整笔回滚。
严格建号使用 INSERT。owner 已存在时返回 `ErrConflict`,不读取后再 UPDATE,因此并发不能覆盖先提交的账户。
以下每条是一次提交:
- 开户:用户行、激活 Key(无初始密码时)、成功审计。
- `applyPasswordChange`:写密码哈希、更新 must_change、作废该 owner 未使用的登录 Key、按路径处理会话、成功审计。覆盖四条调用:主动改密、强制设密、管理员或 CLI 重置、恢复设密。
- `--revoke-all-credentials`:吊销长期 API Key、删除会话、作废未使用登录 Key、签发新 Key、成功审计,一次提交。
失败路径在回滚之后另记一条 `outcome=rejected` 的审计。该条不包含密码、哈希或明文 Key。
## 2. bootstrap
`bootstrap-admin` 在事务内复核,不能只看用户表在事务外为空。
- SQLite:`BEGIN IMMEDIATE`。
- PostgreSQL:`SELECT ... FROM agent_system_identity FOR UPDATE`。没有身份行则拒绝,本命令不补建身份。
复核条件:`users` 为空,且下列业务表都为空:`projects`、`conversations`、`messages`、`runs`、`api_keys`、`sessions`、`login_keys`。任一表有行则拒绝。通过后,管理员、激活 Key 与成功审计同事务提交。
## 3. 审计
迁移在 `audit_events` 增加列:`entry`、`instance_id`、`operation_id`、`outcome`。文本,默认空串。既有行保持可读。版本号取本分支当前最大版本的下一个整数。若 U8 已占用该号,task-sync 时顺延,不改已发布的迁移正文。
成功记录与变更同事务。`actor`:HTTP 取会话 owner;CLI 取操作系统 uid 的十进制字符串。`login_keys.instance_id` 在签发时写入调用方给出的实例标识,缺省空串。
## 4. 账户运维打开
`user`、`apikey`、`identity verify` 只打开既有库:文件或库不存在则失败,不创建父目录,不执行迁移。schema 版本与本二进制不一致时拒绝,错误文本提示使用 `migrate` 或先启动一次服务。
设置了 `AGENT_SYSTEM_INSTANCE_ID` 或 `--instance-id` 时,与库内身份行严格比对,不一致则拒绝。未设置时不补建身份。
## 5. 凭据输入输出
- DSN:`AGENT_SYSTEM_DSN`,或模式 0600 的 `--dsn-file`。
- 密码:`--password-stdin`。
- 明文 Key 或生成的密码写入 `--out-file`。创建使用独占创建(已存在则失败),权限 0600。
- stderr 只打印 operation id 与凭据 id。
`--dsn` 与 `--password` 仍可用,并在 stderr 打印弃用警告,以兼容现有 `scripts/svc.sh` 与 `scripts/e2e.sh`。移除留给账户 U5。
`agent-system capabilities --json` 打印本二进制能力,不打开数据库,不创建目录。
## 6. HTTP
`internal/server/accounts.go` 的建号、改密、重置走同一事务助手和审计。响应 JSON 字段保持现状。
## 7. 测试
`internal/store/account_lifecycle_test.go` 在 SQLite 上运行。设置了 `AGENT_PG_TEST_DSN` 时同一用例再跑 PostgreSQL;未设置则该档 SKIP,任务卡记 NOT_RUN,GATE 取 Dev CI 的 `make test-backend-pg`。
- T7-1 / T7-4:两个进程同时用同一 owner 开户,只有一个成功。并发 bootstrap,以及 bootstrap 与普通开户竞争,同样只有一个成功。
- T7-2:在提交中途注入失败,读到的只能是完整旧态或完整新态。
- T7-3:改密、重置、恢复设密之后,旧的未使用登录 Key 不能再兑换。长期 API Key 仅在 `--revoke-all-credentials` 时撤销。
- T7-5:关闭再打开后原密码仍能校验。真实进程收到 SIGTERM 或 SIGKILL 后同样能校验。两个版本的真实升级记 NOT_RUN。
- 账户 CLI 对既有库不执行迁移;缺文件时不建目录。既有登录 Key 与认证测试保持通过。