Files
Agent-System-Dev/docs/svc-deploy/u1-instance-account-binding.md
T
weichenandCursor 2a03dd58f9 Bind svc user CLI to instance storage and reject lock bypass
Why: U1 requires account ops to hit manifest data_root/DSN with OpenExisting and refuse missing flock or default ./data.
Evidence: python3 -m unittest tests.test_svc_user_binding (T1–T5) + test_svc_identity
Impact: svc <env> user … calls ENV_BIN with --open-existing; deploy/user fail closed without flock.
Refs: docs/svc-deploy/u1-instance-account-binding.md; Backend OpenExisting (PR #171)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 03:55:24 +00:00

4.4 KiB
Raw Blame History

U1 实例—账户绑定补齐(规格 v0.1)

状态:已启动实施(分支 feature/svc-deploy-u1-account-binding)。主记录:modules/documents/docs/proposals/2026-10-12-svc-unified-deploy-and-login-key.md §7 U1。
前置:恢复方案 recovery U1 已合入 main(Dev #415)——docs/recovery/u1-identity-manifest.md、scripts/svc_manifest.py、启动身份校验与 svc init。
本增量不重做 manifest 层;只补齐账户操作与安装入口对既有身份合同的消费缺口。

基线:任务卡 R0;实施中。真实 PG 绑定专项缺环境标 NOT_RUN。

1. 目标与非目标

目标: 同一实例的启停、升级、开户、签发/撤销登录 Key 始终命中同一存储与数据根;缺失、不符或锁不可用时拒绝;为后续 install / doctor 提供稳定的实例解析入口。

非目标:不实现二进制下载(U2)、不实现 doctor/env prepare 全量(U3)、不实现一次性 Key 语义(U4)、不改登录页(U5)。

2. 不变量(相对 recovery U1)

ID 不变量 相对 #415
B1 账户 CLI 只接受「实例名 → manifest 解析出的 data_root / db / secrets 引用」 新增消费方
B2 禁止回落默认 ./data 或未声明 DSN 新增硬拒绝
B3 OpenExisting:目标不存在则失败;可选禁止自动 migrate Backend 新增打开模式
B4 无 flock / 锁获取失败 → 拒绝冲突操作(deploy/start/stop/user/*) 收紧现状「直通」
B5 install / 兼容 --from 写入同一 manifest 身份字段,不另起配置根 入口骨架

3. 触点与文件

文件 变更
scripts/svc.sh user 子命令骨架:解析 ENV_NAME → 读 manifest/svc_manifest.py → 组装 --data/AGENT_SYSTEM_DSN/--open-existing 调 $ENV_BIN;锁检查收紧;install 可先做 dry-run 计划打印(完整 binary/source 属 U2)
scripts/svc_manifest.py 如需:导出「账户操作所需最小字段」查询(data_root、db mode/ref、auth);不改 schema=1 语义
modules/backend/cmd/agent-system/main.go user 子命令增加 --open-existing(或全局 store 打开标志);缺库/缺目录失败
modules/backend/internal/store/store.go OpenExistingSQLite / PG 等价:不 MkdirAll 创建新数据根;可选 MigrateMode=requireCompatible|forbid
tests/test_svc_identity.py 或新 tests/test_svc_user_binding.py 错误 data、缺 manifest、无 flock 拒绝;正确绑定命中

4. OpenExisting 合同

OpenExisting(path|dsn, opts):
  if storage path/parent missing → error (do not create)
  if SQLite file missing → error
  open DB
  if opts.migrate == forbid → read schema version only; mismatch → error
  if opts.migrate == requireCompatible → existing migrate(); reject unknown newer schema (keep current migrate gate)
  never create empty business DB as side effect of account recovery

CLI 默认:账户运维命令使用 OpenExisting + requireCompatible。
svc init / 首次服务启动仍走现有 Open(可创建)路径,与 recovery U1 一致。

5. 锁合同

  • 复用 runtime/<name>/.start.lock。
  • flock 不可用或超时:退出非 0,写 hist_event,不得执行 deploy/start/stop/user。
  • 账户操作与生命周期互斥(同一锁)。

6. 验收用例(U1)

# 场景 判据
T1 实例有合法 manifest;svc <name> user list 使用 manifest data_root/DSN;列表与该库一致
T2 故意传错误 --data 或未绑定实例 拒绝;不创建目录;不写默认 ./data
T3 删除 data 根后再 user create OpenExisting 失败;无新空库
T4 隐藏 flock(PATH 去掉)后 deploy/user 拒绝;旧服务若在跑则仍在
T5 recovery U1 既有 T1–T6 回归 全绿(不破坏 identity)

真实 PG:绑定 dbref 与 marker 一致才允许 user 操作;缺环境标 NOT_RUN。

7. 完成门槛与依赖

  • 完成条件见主提案 §7 U1 行。
  • 依赖:main 已含 recovery U1(#415)。
  • 被依赖:U4 CLI 签发、U5 svc user 接线、U2 install 写身份。

8. 任务卡建议(待授权后 task-start)

  • 分支名:feature/svc-deploy-u1-account-binding
  • R0:与本提案合入后的 origin/main(或与 U4 兄弟共享批准时的同一 R0)
  • 交付模式:manual;实施需主提案阶段批准后再授权