Why: user approved the proposal and U1/U4 specs and authorized push/PRs plus U1/U4 implementation start. Evidence: SELF conversation approval 2026-10-12; implementation still NOT_RUN. Impact: planning status only. Refs: docs/proposals/2026-10-12-svc-unified-deploy-and-login-key.md Co-authored-by: Cursor <cursoragent@cursor.com>
14 KiB
title, type, date, artifact_contract, execution, product_contract_source
| title | type | date | artifact_contract | execution | product_contract_source |
|---|---|---|---|---|---|
| svc 统一部署与一次性登录 Key 方案 | feature | 2026-10-12 | ce-unified-plan/v1 | code | ce-plan-bootstrap |
svc 统一部署与一次性登录 Key 方案 r1
确认状态:已批准(2026-10-12 用户「批准,继续推进」:需求拆解→实施计划五阶段及 U1/U4 规格一并批准;授权推送/PR 与启动 U1/U4 实施;合入仍由 owner 执行)。业务实施、测试、部署与运行验收在批准时仍为 NOT_RUN,由后续实施任务推进。
修订记录:r1=2026-10-12 草案经源码复核后定稿(四项取舍采纳;补齐 §6 合同;对齐恢复方案 KTD 与已合入的 recovery U1 实例身份);同日获批并进入推送与 U1/U4 实施。
需求来源:2026-10-12 用户提出将 svc.sh 增强为统一部署入口(二进制与源码、环境准备、无初始密码开户与账户恢复),并要求一次性 API Key 只能兑换「设置密码」受限会话。负责人:weichen;编制:Cursor Agent。
主记录:本文;任务卡:Dev .task/feature-svc-unified-deploy-login-key.md。源码路径以 Dev 根目录为基准。
1. 目标与成功边界
目标:在干净或既有机器上,用同一套 svc 入口完成二进制或源码部署、按档准备依赖,并通过后端账户能力完成无初始密码开户与账户恢复;一次性登录 Key 只能兑换设密受限会话,完成设密前不能访问业务数据。
必须区分三类能力:
| 能力 | 结果 | 非目标 |
|---|---|---|
| 统一安装 / 升级 | 指定版本或提交物化为可切换候选;切换后实例身份、DB、数据根与账户不变 | 不接管共享 PostgreSQL;不因发现端口而认领外部服务 |
| 环境检测与准备 | doctor 只报告;env prepare 按模式执行可幂等计划 |
不把任意发行版 Go/Node 标为可构建;工具链版本读自所选提交或发布清单 |
| 账户激活 / 恢复 | 无预设密码开户或签发恢复 Key;原子兑换 → 受限会话 → 设密 → 正常登录 | 不删除重建用户;不迁移业务归属;普通找回默认不撤销长期集成 Key |
与 服务重启与全量数据恢复方案 r2 的关系:
- 复用 KTD1–5、KTD12:持久 manifest、唯一监管者、team=PG 且失败不回落 SQLite、readiness 与身份。
- 复用 已合入的 recovery U1(Dev #415):
runtime/<name>/manifest.json、启动身份校验、svc init、原子写路径(见 Devdocs/recovery/u1-identity-manifest.md)。 - 本方案新增:部署来源统一(binary/source)、doctor/env prepare、账户生命周期与一次性登录 Key、安装入口与双轨收敛。
- 命名区分:账户恢复 Key ≠ 服务数据恢复。
2. 当前事实及重点差距
源码基线(SELF·工作区观察,启动 precheck READY):Dev af9c2de663be5ff102dcab7698464a645832f569;Backend gitlink 以该提交为准;本地评审时曾对照 3fa0d3a / Backend 696ef15,与当前 main 可能有漂移,实施前以 task-sync 后 SHA 为准。运行验收 NOT_RUN。
| 对象 | 已存在的基础 | 尚需补齐 |
|---|---|---|
| 部署来源 | deploy --from local|dev|release|rdm;dev/rdm 独立缓存物化;release 读本地 Releases 仓并校验 sha256 |
远程下载/离线导入;统一 install;release@ver 钉扎(现 sort -V|tail -1 取最大版本,见 scripts/svc.sh resolve_release) |
| 部署生命周期 | 预检失败不停机;预检通过后 先停再构建;无程序备份/自动回滚 | 候选获取与校验全程不停旧服务;缺摘要硬失败;迁移后回退独立判断 |
| 实例身份 | recovery U1:manifest + marker + init;svc.env 派生 |
账户 CLI 必须绑定实例最终配置;缺绑定拒绝,禁止回落 ./data |
| 环境 | 端口/flock/pg 工具链按需检查;文档列前提 |
doctor / env prepare;无 flock 时不得放行冲突操作(现状直通) |
| 账户 CLI | user create|reset-password|list;省略密码 → 随机明文一次 + must_change |
无密码创建 + 激活 Key;恢复 Key;OpenExisting(不建空库、不静默 migrate) |
| API Key | 明文只显示一次;可长期复用;无 TTL/次数 | 独立一次性登录凭据表;不可走 Bearer/?key= |
| 强制改密 | 前端门控 + /api/me 标志;changePassword 要求原密码 |
服务端中间件拦截待改密/受限会话;设密分型(一次性会话不要求原密码) |
| 安装双轨 | Dev svc deploy 多实例;Releases install.sh 系统 systemd |
统一部署计划;install.sh 薄封装或明确遗留 |
命题裁定(源码复核):
- 长期 API Key 是 show-once plaintext,不是 single-use — 成立。
- 无统一中间件拦截
must_change_password— 成立。
3. 需求合同
| ID | 范围 | 要求与可判定验收 |
|---|---|---|
| R1 | 安装入口 | doctor / install / 兼容 --from 生成同一部署计划;二进制无需 Go/Node;源码固定提交且子模块组合可核验 |
| R2 | 实例身份 | 启停、升级、开户、签发 Key 命中同一 store 与 data 根;缺失/不符拒绝;与恢复案 R2/manifest 一致 |
| R3 | 切换安全 | 构建/下载/摘要失败时旧服务继续;程序+插件+前端作为版本组合切换;固定版本不得被「最大版本」替代 |
| R4 | 存储档 | team 默认 PG+auth;existing / managed-local / local(SQLite) 显式选择;PG 失败不回落 SQLite |
| R5 | 开户 | 无初始密码;角色明确;创建与激活 Key 同事务;同名冲突不覆盖 |
| R6 | 账户恢复 | 精确命中既有账户;不改密码/不吊销会话/不改业务数据于签发时;保持 owner/角色/成员关系 |
| R7 | 一次性 Key | ≥256bit、只存摘要、activate|recover、默认 TTL 30min、状态机、原子兑换、专用 POST body |
| R8 | 受限会话 | 仅身份查询、设密、退出;业务/下载/SSE/admin/插件拒绝;普通 must_change 同样服务端限制 |
| R9 | 设密事务 | 写 hash、清待激活/待改密、作废未用恢复凭据、失效相关会话同事务;成功后销毁受限会话并要求密码重新登录 |
| R10 | 集成 Key | 普通找回默认保留长期 API Key;失陷恢复显式 --revoke-all-credentials |
| R11 | 首次管理员 | 仅核验为新实例(无用户且无历史业务标记);事务防并发;不得因「未发现管理员」接管有数据环境 |
| R12 | 证据 | 验收绑定固定源码/制品摘要/环境;SELF/REPLAY/GATE 分源 |
4. 技术决策(KTD)
KTD1. 部署方式只决定程序来源,不决定数据位置。 binary ↔ source 可切换;切换保持 DB、数据根、账户与 instance_id。
KTD2. 账户规则只在 Go 后端。 脚本调用实例对应版本的 CLI;不直接改用户表。
KTD3. 一次性登录凭据独立于长期 api_keys。 专用表与兑换 API;普通 Bearer、SSE ?key=、长期 Key 路径均拒绝。
KTD4. 受限会话为独立 scope。 默认 10 分钟;allowlist 仅 me / 设密 / logout。
KTD5. 团队安装默认 PostgreSQL;存储选择显式。 与恢复 KTD5、config.Tier=team 一致。
KTD6. 一次性 Key 默认 30 分钟(可配置建议范围 5–120 分钟);审计记实际 TTL。
KTD7. 激活/恢复设密成功后必须重新密码登录(销毁受限会话、清 cookie)。普通主动改密可保留「要求原密码」路径;激活路径不要求原密码。
KTD8. 普通账户恢复默认保留长期集成 Key;失陷显式撤销全部凭据。 两种情况均保留业务数据。
KTD9. 候选校验完成前不停旧服务;切换短窗;schema 迁移后能否自动回退旧程序另行判断,失败不自动用备份覆盖业务库。
KTD10. 双轨收敛到同一部署计划。 新旧 CLI 同后端;Releases install.sh 变为薄封装或文档降级为遗留,禁止第三套生命周期。
5. 职责划分与接口示例
| 部分 | 负责 |
|---|---|
svc.sh |
doctor、env prepare、获取制品、构建、实例配置、生命周期、调用账户 CLI |
| 后端 CLI | 创建账户、签发/撤销一次性 Key、核验目标库、OpenExisting、操作审计 |
| 后端认证 | 原子消费 Key、受限会话、设密事务、中间件限制 |
| 登录页 | 输入一次性 Key、设密、过期/重发提示;遵循 DESIGN.md |
| 发布制品 | 版本、平台、摘要、组件版本、能力声明 |
拟新增 CLI(当前脚本尚不支持;兼容 --from 保留):
./svc.sh doctor --mode binary --tier team
./svc.sh install prod --mode binary --version <固定版本>
./svc.sh install prod --mode source --repo <仓库> --ref <固定提交>
./svc.sh prod deploy --mode binary --version <固定版本>
./svc.sh prod user create --owner alice --role user
./svc.sh prod user issue-login-key --owner alice --purpose recover
./svc.sh prod user list
./svc.sh prod user revoke-login-key --id <凭据编号>
Linux 服务账户与应用账户分开管理。
6. 规格合同(实施前必须写进 U1/U4,否则返工)
- 独立凭据类型 +
POSTbody 兑换 API。 - 会话 scope / 中间件 allowlist;覆盖
must_change普通首登。 - 设密接口分型:受限会话不校验原密码;普通改密继续要求原密码;同事务完成写 hash / 清标志 / 作废 Key / 吊销会话。
- 密码未设置状态:
password_hash可空或 sentinel;VerifyLogin拒绝未设密;创建 = 用户行 + 激活 Key 同事务。 - CLI
OpenExisting:目录/DB 不存在则失败;运维模式可禁止自动 migrate / 要求 schema 兼容。 release@<ver>必须解析到该版本目录;缺摘要硬失败。- 部署:获取/构建/校验不停旧服务;组合切换;迁移后回退独立判断。
install与--from同一计划;双轨收敛(KTD10)。- 首次管理员仅新实例;事务防并发。
- 凭据交付:交互 stdout 一次 / 非交互
chmod 600文件;日志与 evidence 只记凭据 ID;随机密码路径首期可并存但默认无密码 + Key。 - 无
flock时拒绝冲突生命周期与账户操作(收紧现状「直通」)。
详细设计(正文在 Dev 仓,随本任务分支提交):
- U1:
docs/svc-deploy/u1-instance-account-binding.md - U4:
docs/svc-deploy/u4-one-time-login-key.md
7. 增量与完成门槛
| 增量 | 主要范围 | 完成条件 |
|---|---|---|
| U1 实例—账户绑定补齐 | 账户 CLI 读实例 manifest;OpenExisting;锁缺失拒绝;install 骨架对接既有 identity | 开户/签发命中同一 store;错误 data/DSN 拒绝;与 recovery U1 字段对齐 |
| U2 二进制与源码来源 | 下载/离线导入、仓库物化、版本清单、候选先校验 | 无开发仓可部署;固定版本与摘要可核验;修复 release 钉扎 |
| U3 环境检测与准备 | 系统适配器、依赖计划、专用工具链、监管配置 | Ubuntu/Debian 首验;幂等;不接管共享服务;binary 不装 Go/Node |
| U4 一次性凭据与认证限制 | Backend CLI/Store/Server/迁移 | 原子开户/兑换/设密;受限会话无法调业务 API;并发兑换单胜 |
| U5 脚本与登录页接线 | 账户命令、首次管理员、凭据交付、Login/设密页 | 新建与恢复走通;刷新与异常可续;DESIGN.md |
| U6 组合与故障验收 | Dev 组合、发布包、真机、数据保护 | 两种部署 × 存储档;故障注入;浏览器 + 真机;治理回归 |
近期优先 U1、U4(可并行兄弟分支、共用 R0)。跨仓顺序:Backend(U4)→ Frontend(U5)→ Dev gitlink + svc.sh(U1/U2/U3/U5);组合 make test 后宣称可合入。
必须覆盖的验收场景(摘要)
干净机器二进制安装;源码固定提交与子模块;两种部署互切后数据不变;构建/摘要/配置失败旧服务可用;PG 身份不符拒绝且不回落 SQLite;无密码开户且不覆盖既有;同 Key 并发兑换仅一次成功;受限会话拒业务/SSE/admin;消费后建会话失败与设密中途失败无半完成态;恢复前后业务与权限对账;SQLite 与真实 PG;治理回归;源码测试不代替浏览器与真机。
额外钉住:release@v 多版本不得装成更高版本;账户 CLI 不得回落默认 ./data。
8. 一次性 Key 流程
flowchart LR
A["创建账户或签发恢复 Key"] --> B["输入一次性 Key"]
B --> C["后端原子消费"]
C --> D["仅允许设置密码的短期会话"]
D --> E["设置并确认新密码"]
E --> F["作废恢复凭据及相关旧会话"]
F --> G["使用新密码正常登录"]
凭据规则:独立前缀;只存摘要;用途 activate|recover;状态未使用/已消费/已撤销/已过期;密码变更后旧恢复凭据不可再用。符合 OWASP Forgot Password 与 Session Management;保留现有 CSRF 校验。
9. 风险与未授权范围
- 实施、故障注入、真机部署、浏览器验收:未授权 / NOT_RUN。
- 本任务交付终点:正式提案 r1 + U1/U4 规格 + 任务卡与索引入口;推送/PR 须另获授权。
- 与 recovery U1 重叠处只做增量,不重做已合入的 manifest 层。
10. 规划进展与下一步
- 本次推进:源码复核;四项取舍定案;正式提案 r1;U1/U4 规格细化。
- 首选下一任务(待授权):并行启动 U1 实施与 U4 实施(兄弟分支、共用 R0);U2/U3 规格可随后写作但不阻塞 U1/U4。
- 前置:人工批准本提案 r1(至少需求表 + 方案设计 + U1/U4 实施计划阶段);实施前
make precheck与task-sync。