文件
hyb-oa/.trellis/tasks/08-08-production-authenticated-readiness/design.md
T
wangsli 4f3f761d0a
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
规划(08-08-production-authenticated-readiness): 锁定生产登录态只读验收门禁
2026-08-08 22:57:52 +08:00

130 行
6.8 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# 生产登录态只读验收:设计说明
## 1. 设计边界
本任务是生产账号诊断与登录态只读验收,不是账号修复或产品开发。前一部署任务已经证明产品候选、migration、匿名鉴权和公网基础 readiness;本任务只补齐因仓库外凭据 `401` 而缺失的登录态证据。
核心原则是“先读取状态,再决定是否允许一次登录”。账号失败计数和锁定属于生产安全状态,不能拿登录端点当探针。合同终止是不可逆写入,浏览器验收必须在输入和网络两层同时保证不会提交。
## 2. 状态序列
```text
生产身份 / 已部署 SHA / 65 migration(只读)
-> rollback window PRE(只读)
-> admin/employee identifier 登录语义 + 账号状态(BEGIN READ ONLY)
-> 分流:identifier / locked / inactive-role / password credential
-> 仅当合法新鲜凭据 + 全部门禁 PASS:每角色最多一次登录
-> admin 合同详情只读 + terminate POST=0
-> employee 权限负向
-> rollback window POST(只读)
-> 只读 reviewer / 结论
```
任何箭头失败都停止。`PRE` 与 `POST` 快照即使中间步骤 `PAUSED` 也都要执行;这样能区分本任务未写入与同期真实用户关闭窗口。
## 3. 账号只读诊断
### 3.1 查询合同
生产查询使用 `BEGIN READ ONLY`,只处理 admin/employee 两个 role key。identifier 从受控进程变量读取,在数据库内与 `email`、`phone` 做精确比较;不能因为现有 dry-run helper 支持 `employee_no` 就把员工编号视为可登录 identifier。
稳定输出模型:
```text
roleKey=admin|employee
matchedBy=email|phone|none
active=true|false
archived=true|false
locked=true|false
failureCount=<非负整数>
expectedRoleReady=true|false
```
不输出 identifier、员工编号、邮箱、手机号、锁定时间、密码 hash、角色明细或原始行。查询目标多于一条、事务不是 read-only、输出字段异常都 fail-closed。
### 3.2 分流矩阵
| 只读结果 | 结论 | 动作 |
| --- | --- | --- |
| `matchedBy=none` | secret 中 identifier 过期或不符合 email/phone 登录合同 | `PAUSED`;账号持有人从合法来源恢复仓库外凭据 |
| active/role 不满足 | 账号或授权事实已变化 | `PAUSED`;另设账号/权限 task |
| `locked=true` | 账号当前锁定 | `PAUSED`;不试登录、不解锁 |
| 匹配、active、role 正确、未锁定,既有结果为 401 | 按当前 auth 分支可判定仓库外密码不匹配 | `PAUSED`;密码变更另行批准 |
| 合法新鲜凭据已恢复且全部健康 | 允许有限登录验证 | 每角色最多一次,单 worker、零 retry |
账号不存在与密码错误在 HTTP 上同为 401;只有数据库只读诊断能安全拆分。若一次获准登录仍失败,立即重查 failure count/locked,记录差值并停止。
## 4. 回滚窗口双快照
termination migration 已 applied,因此必须真实查询:
```sql
SELECT count(*) FROM contract_registry WHERE status = 'terminated';
```
查询异常不可 catch 后默认 `OPEN`。两次快照使用同一目标、同一查询合同和同一输出格式:
- count = 0:`rollbackWindow=OPEN`
- count > 0:`rollbackWindow=CLOSED`
- PRE OPEN / POST CLOSED 且 terminate request count = 0:并发真实用户已产生首条终止记录;记录窗口永久关闭,不归因于本任务
- PRE CLOSED:全部验收仍只读,旧应用回退从一开始就不可用
## 5. 登录预算与浏览器控制
### 5.1 登录预算
- 执行前确认仓库外凭据是新鲜、合法来源,不靠修改生产账号获得。
- 管理员、员工各最多一次;Playwright 固定 `--workers=1 --retries=0 --reporter=list`。
- 禁止复用默认 CI retry;一次失败即结束该角色路径。
- 失败后重新运行账号只读查询,证明是否增加失败计数或触发锁定。
### 5.2 合同详情安全断言
`draft/archived` 不显示终止面板,无法承担“误点后服务端 409”的兜底。对已有 `active/expired` 合同采用以下边界:
1. 打开合同详情并验证自然中文状态和只读摘要;证据不采集正文或敏感字段。
2. 注册请求监听,统计匹配终止端点的 `POST`;初始为 0。
3. 验证“终止合同”面板、至少 10 字提示和 destructive 按钮存在。
4. 终止原因保持空值或不足 10 字;断言按钮 disabled。
5. 不点击按钮,不打开确认层,不调用 API;结束时终止 `POST` 仍为 0。
优先使用 Playwright CLI 的受控会话;若 CLI 命令不能可靠表达请求监听和 disabled 断言,则由执行者本人做更窄人工检查,只验证入口与按钮状态,不打开确认层。不得为本任务新增会提交数据的 spec。
### 5.3 权限与数据分支
- 管理员正向:能进入合同台账/详情。
- 员工负向:合同管理入口不可达或服务端返回既定无权结果;不得扩大权限。
- archived 样本存在:只读验证字段锁定;不存在则 `PAUSED`。
- terminated 样本存在:只读验证中文标签与终止事实;不存在则 `PAUSED`,绝不制造样本。
## 6. 失败与权限边界
| 阶段 | 失败 | 处理 |
| --- | --- | --- |
| 身份/SHA/migration | 目标或版本不符 | 停止,不登录 |
| rollback PRE/POST | 查询失败或不可解析 | fail-closed,不推断 OPEN |
| identifier | 不匹配 email/phone 或不唯一 | `PAUSED`,恢复仓库外 secret |
| 状态/角色/锁定 | 任一不健康 | `PAUSED`,另行批准账号治理 |
| 登录 | 首次失败 | 停止,重查失败计数/锁定,不重试 |
| 管理员 UI | 数据缺失或只读断言失败 | `PAUSED/FAIL`,不造数据、不改产品 |
| 员工负向 | 权限扩大或结果不符 | `FAIL`,不改权限推进 |
| terminate 请求 | 计数不为 0 | 紧急停止并复核 POST 确切结果与窗口;不得再次操作 |
## 7. 证据与隐私
原始查询和浏览器会话只在受控现场存在。提交材料保存稳定枚举、布尔、计数、SHA、HTTP status 和相对 evidence 引用;不保存生产 identity 明文、账号、凭据、cookie、合同正文、相对方、金额、终止原因或 payload。
截图不是必需证据;若必须截图,应使用无业务正文的局部裁切或脱敏摘要。任一敏感扫描命中都先处理证据,不降低 scanner。
## 8. 只读 review 与 readiness 结论
本任务涉及生产认证、权限和不可逆状态机边界,执行后必须启动只读 reviewer。reviewer 不修改代码、账号、权限、数据库或证据,只核对:
- 登录前诊断确实先于登录;
- 每角色尝试次数与失败后复查;
- 终止原因/确认层/POST 均未越界;
- rollback window 前后快照及变化解释;
- 证据脱敏与最终 readiness 用语。
只要必需登录态 AC 仍 `PAUSED`,最终结论只能是“已部署但登录态验收未完成”,不能告知用户可以测试。