Smail/docs/恢复码取消与低资源补充验收.md
smail 7114e9ed4a
Some checks are pending
Security Checks / security (push) Waiting to run
修复恢复码请求取消并完成最终迁移补充验收
2026-09-21 20:26:50 +08:00

93 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 恢复码取消与低资源补充验收
日期:2026-09-21。本记录接续 SQLite 跨引擎迁移补充验收,不能替代全项目生产放行。
## 需求确认与任务状态
- [✓] 保留上一轮失败证据,九文件提交 `586f2bc` 已推送并核对远端哈希。
- [✓] 区分恢复码密码计算、数据库事务和 HTTP 请求取消,不把初始化超时写成迁移数据损坏。
- [✓] 接入请求取消、可取消互斥等待和事务回滚;四个相关 Go 包、全量本地后端及 Linux 专项回归通过,跳过项单独披露。
- [x] 完整应用的内存目标单变量对照已完成,PostgreSQL → SQLite 中间候选通过。
- [✓] 最终候选重新编译及云端 PostgreSQL → SQLite 复测通过,实际进程环境核对完成。
- [✓] 本地运行时回归 81 项、云端完整部署回归 151 项通过,后者零跳过。
- [✓] 127 份文件本地与远端摘要一致,616 个后端源码摘要一致;八个测试账号锁定,正式六服务和程序未变,测试单元全部停止。
- [!] 原 64 MiB Go 内存目标的受限环境仍存在 30 秒恢复码生成超时,不能按同条件通过处理。
- [!] 浏览器、外部邮件、凭据轮换、续期、长时容量和灾备等其他门禁仍未全部关闭。
## 超时定位证据
不降低 Argon2id 参数,不减少恢复码数量,不放宽探针 30 秒读取超时。密码算法仍为 `m=65536,t=3,p=1`,每轮生成十枚恢复码。
直接调用凭据服务的受限诊断使用新建 PostgreSQL 空库、专用账号、192 MiB 进程内存上限和 25% CPU 配额:
| 诊断实例后缀 | Go 内存目标 | 密码计算至事务开始 | 整体生成 | GC 次数 |
| --- | --- | --- | --- | --- |
| `20260921-082512` | 64 MiB | 23.753 秒 | 23.775 秒 | 138 |
| `20260921-082540` | 128 MiB | 24.079 秒 | 24.093 秒 | 10 |
这两个独立服务诊断没有显示明显的总耗时改善;数据库事务只占十几至二十几毫秒。不能仅凭 GC 次数差异宣称找到了完整应用的全部性能原因。前两次诊断启动遇到隔离挂载与执行路径错误,未进入应用测试,保留记录且专用账号已锁定。
随后用同一个中间候选 `062c15539ed0df446d4050bc15b55f717369b58fba0caa2e8c4f28ceabd5ed0c` 进行完整应用对照:
| 实例后缀 | Go 内存目标 | 密码计算 | 整体生成 | 结果 |
| --- | --- | --- | --- | --- |
| `20260921-083048` | 64 MiB | 30.208 秒 | 30.209 秒 | 客户端取消;尚未进入数据库事务,取消被服务识别 |
| `20260921-083337` | 128 MiB | 23.601 秒 | 23.619 秒 | 初始化及后续完整迁移通过 |
两个应用实例均保持 CPU 25%、进程硬上限 192 MiB、交换禁用、`GOMAXPROCS=1`、十枚恢复码和 30 秒读取超时,仅显式调整 Go 内存目标。直接证据确认失败发生在密码计算阶段,而非 PostgreSQL → SQLite 迁移执行阶段。内存目标变化与本次完整应用耗时改善存在对照证据,但不能从这一组样本外推所有负载下的性能。
原失败记录继续有效。128 MiB 是另一个明确标注的资源配置,不是把旧配置改写为通过,更不是生产容量或性能承诺。正式服务资源配置没有变动。
## 修改边界与反例
1. `GenerateRecoveryCodesContext` 接收 HTTP 请求上下文;旧无上下文入口保留,供兼容调用使用。
2. 每次 Argon2id 计算之间检查取消;单次计算本身不可中断,不改变哈希强度。
3. 凭据写入锁允许取消等待;取消不能释放其他请求持有的锁,也不能留下不可再用的锁。
4. 数据库事务使用请求上下文,插入和提交前检查取消;未提交事务统一回滚。
5. 自助及管理员代生成入口均传递请求上下文;管理员入口遇到密码计算繁忙时返回 `503`、`Retry-After: 1` 和 `AUTH_BUSY`。
6. 阶段日志只记录数量、耗时、阶段和成功/取消标志,不记录恢复码、哈希、口令或 Cookie。
反例覆盖:请求开始前取消、第一/第五/第十次计算后取消、等待凭据锁取消、等待数据库连接取消、第一/最后一次插入后取消、密码计算繁忙、互斥并发及非法解锁。成功路径继续检查十枚随机码及原 Argon2id 参数。
本修改保证已观察到取消且尚未提交的事务不会部分轮换恢复码。数据库提交已经成功后发生响应丢失,是另一种状态;不能承诺数据库提交与浏览器收到明文之间具有原子性。
## 工具与环境
- 隔离验收工具新增显式 Go 内存目标参数,默认仍是原 64 MiB;Go 目标与进程硬上限之间必须保留至少 64 MiB。
- 验收器读取进程环境时只保留 `GOMEMLIMIT`、`GOMAXPROCS`,不保存其他环境变量。
- 探针单独记录恢复码阶段和耗时,失败时不再把后续尚未创建的目标库误读为数据库损坏。
- 中间候选只重编译后端,复用未修改的前端与 Linux 插件资产,不能描述为全资产重建。
- 每轮使用新空隔离实例和新 SQL 库,不清空正式数据库,不停止正式 Smail 或其他项目,不删除离线证据。
中间候选 PostgreSQL → SQLite 实例 `20260921-083337`:内部 PID `794879` 不变,系统重启为 `795359`,故障恢复为 `795477`。三阶段源 PostgreSQL 连接数均为零,目标 SQLite 打开;运行目录只保留 `migrated.db`,没有第二个状态库。旧邮件、新邮件、正文和附件、配置历史原始字节、目标不可用时拒绝启动、恢复后读写均通过。
本地证据位于 `test-log/production-remediation-20260921/`,包括 `recovery-timing-*`、`mixed-runtime-evidence/smail-review-runtime-20260921-083048/` 和 `mixed-runtime-evidence/smail-review-runtime-20260921-083337/`。首次扩大本地回归遇到新测试夹具角色类型编译错误,修正后四个相关包均通过;前后日志均保留。
## 最终候选与回归结果
最终后端候选 SHA-256 为 `87eb782b34ac16473259e4b63caf98dd9dd073c887d0dcad008742bbc913bd35`,对应本轮恢复码修改和互斥非法解锁保护。构建仍复用未修改的前端及 Linux 插件资产,不是全资产重新构建,也未替换正式实例。
| 范围 | 结果与边界 |
| --- | --- |
| Windows 本地全量后端 | `go test -json -p 1 ./... -count=1 -timeout=240s` 退出零;62 个包通过,22 个包级跳过;1057 个顶层测试及 831 个子测试通过,34 个顶层测试及 7 个子测试跳过,零失败 |
| Linux 恢复码专项 | `20260921-085040` 两个测试程序退出零,共 19 个测试及子测试通过、零跳过;凭据包十枚强哈希耗时约 24.4 秒 |
| 最终候选应用级迁移 | `20260921-085155` PostgreSQL → SQLite 通过;恢复码 HTTP 耗时 23.772 秒,未放宽 30 秒超时 |
| 本地运行时工具回归 | 81 项通过,证据为 `recovery-runtime-python-tests.log` |
| Linux 全部部署工具回归 | `20260921-201523` 实际执行 151 项、零跳过、退出零;峰值 45.9 MiB、交换为零,正式六服务状态未变 |
本地全量跳过项包含平台相关的符号链接与权限检查、未启用的真实 SQL 集成、浏览器夹具及 Windows 提权 IPC 等,不视为验收通过。Linux 恢复码专项只补足本修改的运行平台证据,不覆盖全部本地跳过项。
最终迁移实例实际进程环境为 `GOMEMLIMIT=128MiB`、`GOMAXPROCS=1`,进程硬上限仍为 192 MiB、CPU 配额仍为 25%,无 OOM。内部重启 PID `796642` 不变,系统重启后为 `797013`,故障恢复后为 `797134`。三阶段源 PostgreSQL 活动连接均为零,目标 SQLite 打开,活动库只有 `migrated.db`;业务与配置历史同库。
待重启写入被拒绝、原会话保留、配置历史原始字节一致、历史及新增邮件中文正文和附件的 SMTP/IMAP/POP3 读写均通过。目标不可用时退出码为 1、PID 为零,没有回退源库;恢复访问后读写通过。测试账号锁定,桥接和网络隔离单元停止,无资源采集或清理错误。
本轮最后一个迁移方向已获得成功证据,但跨引擎六个方向来自不同阶段候选,不能表述为最终候选在同一轮跑完全部方向。迁移提交及配置切换临界点、SQL 复制中断、历史凭据轮换、静态安全剩余项、真实浏览器、外部投递、自动续期、容量及异机灾备等继续保持未完成。
## 独立复核与收尾
20 时补充回归后,`recheck_recovery.py` 对八次跨引擎应用级尝试、两个 Linux 专项程序及部署工具回归执行独立复核,合计检查 127 份文件,包括成功与失败日志、当前工具、最终候选及测试二进制;本地与远端摘要全部一致。616 个后端源码文件与最终构建清单一致。旧工具仅按原始证据摘要复核,不要求旧轮次工具与当前工具一致。
三次恢复码超时失败完整保留。八个 SQL 专用账号均锁定,PostgreSQL 账号不能登录、建库或提权;测试单元全部停止。正式六服务的 PID、InvocationID、重启次数及活动状态与测试前一致,正式主程序 SHA-256 仍为 `c14ef1c5ba1dc2096c312c8357039a7330c985cbeac90765aed01d8151e05e1f`。用户原 `云端全项目测试报告.md` 未编辑或暂存。
当前跟踪文件的凭据特征扫描通过,只代表该扫描器覆盖的当前文件检查,不代表历史凭据撤销或完整安全审计通过。整体验收继续未通过,不能部署为已验收生产版本。