Smail/docs/生产补充验收记录.md
smail 793a4b504f
Some checks are pending
Security Checks / security (push) Waiting to run
"校准补充验收记录的未关闭边界"
2026-09-22 02:03:06 +08:00

417 lines
42 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 年 9 月 20 日 22:55 开始,代码基线为 `05f7490`。
本记录补充最新单数据库版本的生产门禁,不覆盖原有云端全项目测试报告中的未提交修改。
测试域名、账号和密码仅用于测试,不是产品默认配置或放行依据。
## 当前结论
**关键补充验收已取得实机通过证据,但整体生产验收尚未通过。**
本记录按明确范围更新旧清单:旧双 SQLite 验收、旧 SSH 阻塞、旧资源限额未部署等描述不能继续当作当前事实。
源码整改、隔离通过和生产实例正式升级分别记录,不互相替代。
## 任务清单
- [✓] 核对历史阻塞、当前部署、隔离产物及证据边界。
- [✓] 最新构建 SQLite 空数据初始化、登录、安全设置、三协议认证与中文附件读取。
- [✓] 独立 Nginx 反代、跳转、上游 TLS 校验、双来源限流和过载恢复;新候选复验见后文。
- [✓] 三种数据库共十段真实迁移、正式配置事务切换、配置管理器重新加载和历史保真。
- [✓] 同机隔离冷备、全新目录还原、历史及新增邮件的正文和附件取回。
- [✓] 当前生效证书覆盖根域名与泛域名,管理入口和应用托管证书指纹一致。
- [✓] 权威 DNS 与一个公网递归解析器核验地址和邮件记录,DKIM 公钥与部署私钥匹配。
- [✓] 前端生产依赖审计、静态检查、全量自动化和全量竞态回归。
- [✓] 四个 DNS 工具移除明文云密钥,新增脱敏扫描器及持续集成门禁。
- [!] 历史云密钥、服务器凭据的轮换、访问审查和泄露处置没有完成证明。
- [!] 静态安全扫描尚未逐条完成修复或可审计排除;Windows 初轮 61 条、Linux 历史扫描 44 条、管理员恢复整改后 38 条,其中 7 条已有专项复核证据,不能生产放行。
- [✓] SQLite、MySQL、PostgreSQL 各自从空库完成首次安装、真实配置历史写入及邮件业务闭环。
- [✓] 新候选在三种数据库下验证协议码和客户端码撤销:三协议旧连接操作及新登录均被拒绝。
- [✓] HTTP 退出后原 Cookie 重放、账号禁用及修改密码后的旧会话拒绝;浏览器操作另行验收。
- [✓] 管理员恢复整数边界及系统程序路径整改,云端 Linux 包 41 个顶层测试零跳过通过;新候选三库空数据实机复验通过。
- [✓] 修复自动 DNS 证书加载与导出遗漏根域名校验,保留整改前云端失败反例;新候选的证书专项与三库回归通过。
- [✓] SQLite 同引擎及双 SQL 同引擎、跨引擎切库后的真实进程重启与目标不可用恢复;分阶段证据见后文。
- [✓] 涉及 SQLite 的四个跨引擎应用级方向分阶段通过;不同候选与资源配置的证据不合并为最终候选统一矩阵。
- [✓] MySQL、PostgreSQL 的 SQL 提交与配置切换临界点恢复;SQLite 相关中断项仍按独立专项记录,不与 SQL 联合故障结果合并。
- [ ] 最新候选浏览器初始化、账号恢复及完整用户操作闭环。
- [!] Windows 提权本地通道验收需要管理员会话,当前终端未提权。
- [!] 生产 DNS 自动续期需要安全注入有效且已轮换的最小权限凭据,当前为手动托管证书。
- [!] 外部收件最终到达、真实恢复邮件、外部插件调用需要受控测试账号和收件确认。
- [ ] 生产容量、长时运行、告警触发和异机灾备验收。
- [✓] 静态安全扫描执行、脱敏统计、回归证据复核与本轮变更整理;提交推送结果以 Git 记录为准。
## 发布安装回滚补充
详见 `发布安装回滚补充验收.md`。基于 `7114e9e` 修复已有恢复备份被覆盖和恢复失败被误标为完整回滚的问题;保留原始失败及夹具修正记录。
Windows 发布包回归与竞态检查分别为 21 个测试及子测试通过,Linux 云端隔离专项 23 项通过,均零跳过。正式六服务及程序未变,没有执行正式升级。
发布包 Linux 目标静态复扫仍有 4 条 G304 和 1 条 G306,退出 1,不能排除路径竞争、父目录信任、并发升级和崩溃一致性风险。整体生产验收仍未通过。
## DNS 签名参数隔离补充
详见 `DNS签名参数隔离补充验收.md`。基于 `33eab66` 复现并修复请求参数复用时旧签名参与新签名计算的问题,原始失败保留。现有调用链每次新建参数,因此不能据此认定线上续期故障根因。
Windows SSL 包竞态回归 51 个测试及子测试通过、3 个符号链接权限跳过;云端 Linux SSL 包全量隔离测试 54 项通过、零跳过。独立复核源码、程序及日志摘要一致,正式六服务及程序未变。
本轮采用受控模拟传输,不使用真实云凭据、不修改公网 DNS;G505 风险、真实续期及全协议换证仍未关闭。
两批修复之后完成当前后端全项目 Linux 目标静态复扫:84 个包、348 个非测试源码文件,无包加载错误,仍有 38 条告警,退出 1。告警集合和原有五个忽略标记均未变化;619 份后端源码摘要未漂移。完整证据见 `静态安全告警复核记录.md`,整体生产门禁不放行。
## 操作边界
- 仅操作 Smail;不停止共享数据库、Nginx 或其他项目。
- 实机测试先使用全新空数据隔离实例,施加内存、CPU 和运行时间限制。
- 不删除用户文件,不擅自轮换服务器凭据,不重写 Git 历史。
- 外部收件人的最终收件、凭据轮换、异机灾备等缺少必要条件时明确保留阻塞。
- 不将源码检查、模拟测试、跳过项或历史版本证据计为本轮实机通过。
## 初始只读核对
- Smail 主进程、其他项目进程与前轮记录一致;当前服务限额为内存上限 512 MiB、高水位 384 MiB、CPU 配额一个核、任务数上限 256。
- 上述限额已部署,不能继续沿用旧清单中“限额未部署”的描述;但限额不等于生产容量通过。
- 名为 `smail-certificate-renew.timer` 的单元未安装;需要进一步核对应用内续期与其他调度,不能仅据此断言所有续期均不存在。
- 旧隔离工具仍断言双 SQLite 完整性,需要更新为单数据库要求并增加反例回归。
- 共享主机存在历史交换空间占用;后续压测只在受限隔离单元内执行,不推导全机容量。
## 产物与部署对应
本轮前端、Linux 插件嵌入产物和 Linux 主程序重新编译完成。
| 项目 | 证据 |
| --- | --- |
| 本地证据目录 | `test-log/production-acceptance-20260920/`,已被 Git 忽略 |
| 隔离候选路径 | `/var/tmp/smail-review-acceptance-20260920/smail` |
| 候选主程序 SHA-256 | `2ed95b506b4489bc1a971a853826dfc549bfb0712b16adfded328c3011cec0ce` |
| 正式主程序 SHA-256 | `c14ef1c5ba1dc2096c312c8357039a7330c985cbeac90765aed01d8151e05e1f` |
| 正式运行目录 | `/opt/smail`,本轮未替换、未重启、未清库 |
上表为 9 月 20 日初轮候选,没有注入正式发行版本号,不伪造发行标识。9 月 21 日已修改 PostgreSQL 初始化及协议连接授权等应用逻辑,并重新构建候选;新旧版本证据不能混用,见后文独立记录。
每个隔离实例有独立挂载和网络命名空间;测试密码和协议凭据不输出,备份恢复所需测试密码仅在内存及匿名标准输入管道传递。
## 云端实机结果
### 首次安装与反向代理
- 23:16 的空 SQLite 实例通过一次性初始化令牌保护、HTTPS 登录、会话接口和正式安全设置。
- SMTP、IMAP、POP3 使用正式生成的独立协议授权码认证;明文 SMTP 认证被拒绝,错误凭据返回 `535`。
- 通过 SMTP 收取中文邮件,IMAP 在收件箱按 Message-ID 搜索并取回正文和附件,POP3 通过 RETR 取回相同内容。
- 三轮各八并发的 HTTP 与邮件协议混合认证测试,同时观察成功和可重试繁忙响应,后续正常请求恢复。
- 23:31 的独立 Nginx 实例使用仓库部署模板,验证应用 `8001/8002` 与代理 `443` 链路;未关闭上游证书校验。
- HTTP 与内部入口跳转均保持公网 HTTPS 地址,恢复页脚本可加载且不缓存;伪造转发头不能绕过限流,不同来源仍可独立登录。
- 每次收尾只允许 `smail.db`,要求存在 `config_records`,完整性检查为 `ok`;正式库没有隔离实例测试邮件。
主要证据:`isolated-runtime-231650.log`、`nginx-runtime-233251.log` 及配套结果、探针和服务日志。
SMTP 的实际投递为隔离域内部收信;认证成功不等于已经通过认证外发或外部邮箱最终到达验收。
### 三种数据库迁移与真实配置事务
23:44 对真实 MySQL、PostgreSQL 服务执行以下链路,共十段,9.58 秒通过,零跳过:
1. SQLite → MySQL → MySQL → SQLite。
2. SQLite → PostgreSQL → PostgreSQL → SQLite。
3. SQLite → MySQL → PostgreSQL → MySQL → SQLite。
最终轮调用真正的 `ConfigManager.SwitchDatabase`,核验待重启标记、配置代次、重新创建配置管理器后目标连接仍保持一致。
每段校验中文主题、中文日志、自增序列、真实配置备份,以及二进制历史 payload 与 SHA-256 不变。
配置审计写入器仍使用测试内存实现,未把它计为生产日志持久化验收。
证据:`live-migration-234401.log`。此前 `live-migration-231721.log` 仅使用替代切换回调,不能替代最终轮证据。
测试只使用随机命名的专用库,测试账号已锁定、禁止登录,库保留供复核;没有停止共享数据库或修改其他项目的库。
**配置管理器重新加载并不等于应用服务进程切库重启,后者仍未完成。**
### 冷备与空目标还原
23:36 完成新空实例全流程后停掉该隔离实例,冷备全部十八个文件并在全新目录还原。
- 所有文件 SHA-256 与源一致,还原库 inode 与源不同;归档只允许正常文件和目录,拒绝链接、设备和路径穿越。
- 23:37 在独立网络和挂载空间启动还原实例,原账号正常登录,三种协议重新授权后认证通过。
- IMAP、POP3 均能取回备份中的历史邮件和中文附件。
- 还原后再次通过 SMTP 收信,两种取信协议均能取回新增正文和附件。
- 源目录字节不变,正式服务状态不变,还原库完整性 `ok`,测试单元全部停止。
- 恢复业务验证耗时 16.09 秒;这不是包含传输、故障发现和运维响应的生产恢复时间目标。
证据:`restore-runtime-233756.log`、`restore-233756-smail-review-restore-20260920-233730-result.json`。
范围仅为同机隔离冷备,不覆盖在线备份一致性、异机灾备或生产定时备份。
### 当前正式实例只读收尾
`live-final-state.json` 确认:
- 主域为 `solit.cn`,后台为 `web.solit.cn`;数据目录仅一份 `smail.db`。
- 使用系统信任链,分别以根域、后台和邮件域 SNI 访问本机 Nginx,TLS 校验通过;不是跳过校验的探测。
- 实际返回证书 SAN 为 `*.solit.cn`、`solit.cn`,与应用配置引用的托管证书 DER 指纹一致。
- `ssl/custom.crt` 是旧文件,不是当前证书配置依据;本轮没有删除它。
- Smail、Nginx、MySQL、Scert、FDM、PostgreSQL 均运行,既有进程和调用标识未变化,未留下运行中的本轮测试单元。
这些 TLS 探测走本机地址并保留真实 SNI,不能替代公网 DNS、浏览器或不同用户网络的验证。
本轮没有改动 DNS;后续只读 DNS 核验见下一节,不将记录存在等同于真实邮件投递通过。
### DNS 与 DKIM 只读核验
证据中的 UTC 时间为 `2026-09-20T16:07:56Z`,对应北京时间 9 月 21 日 00:07:56。
- 从云服务器直接查询权威服务器 `dns13.hichina.com` 和公网递归服务器 `8.8.8.8`,根域、后台、邮件域和新随机测试子域均返回 `47.108.78.12`。
- MX 保留优先级 1 的 `mail.solit.cn`,以及优先级 20 的既有阿里云邮件目标;本轮未删除或改写任何记录。
- SPF、`default._domainkey` DKIM、DMARC 均有记录;两处解析结果一致。
- 在服务器内由当前部署 DKIM 私钥导出公钥,与权威 DNS 公钥字节比对一致;只记录公钥指纹,不输出私钥。
- 对 `1.1.1.1` 的八次查询均超时,不能声称所有公网解析器都通过。
- Windows 当前系统解析器的 A 记录返回 `198.18.*.*`,与权威答案不同;原因未查明,不能以此路径证明直接解析到生产地址,也没有擅自修改本机网络设置。
证据:`public-dns-20260921.json`、`local-dns-20260921.json`、`dkim-dns-match-20260921.json`。
以上仅证明所列解析路径及密钥匹配,不证明外部邮件最终到达、收件端 DKIM 验签或浏览器可访问。
## 自动化与安全回归
| 验证 | 结果与边界 |
| --- | --- |
| `node test/run.mjs all -p 1 ./...` | 初轮及最终轮退出码均为零;前端 210 项通过,部署 JavaScript 4 项通过、1 项仅适用 Linux 的测试跳过 |
| `node test/run.mjs backend -race -p 1 ./...` | 全量通过;新增真实切换测试再以 `-race -count=1 ./services/dbmigration` 复核通过,耗时 10.044 秒 |
| Linux Python 部署回归 | 初轮 82 项通过,新增凭据前置校验后最终 83 项通过;Windows 的 fcntl、POSIX 路径不兼容失败记录保留,不冒充 Windows 全量通过 |
| Linux 资源策略回归 | 15 项通过;首次上传漏掉两个只读夹具,补齐后通过,失败日志保留 |
| 新增验收与凭据扫描回归 | 13 项验收器反例、6 项凭据扫描反例通过,并加入持续集成;最终六项扫描器回归在 Windows 和 Linux 均通过 |
| `go mod verify` | 通过 |
| 前端生产依赖审计 | 162 个生产依赖,报告各级漏洞均为零;不包含开发依赖 |
| 前端 ESLint | 不使用自动修复,退出码零 |
| `govulncheck ./...` | Windows 和 Linux/amd64、CGO 禁用扫描均退出零;可达与导入包层命中为零,依赖模块层命中三项,不能宣称全部依赖零漏洞 |
| `gosec ./...` | 未通过,退出码 1;扫描 340 个文件、55,843 行,61 条告警,高等级 13、中等级 26、低等级 22;Go 包加载错误为零 |
证据包括 `final-all-tests.log`、`race-tests.log`、`linux-deployment-regressions.log`、`linux-resource-policy-retry.log`、`frontend-audit.log` 和 `govulncheck.log`。
补充证据为 `final-migration-race.log`、`govulncheck-linux.log`、`linux-secret-regressions-final.log`、`linux-deployment-regressions-final.log`。
Linux 漏洞报告中的模块层条目为 `GO-2026-6355`、`GO-2026-6354`、`GO-2026-5932`;当前调用路径未命中,不等于可忽略后续依赖维护。
本地未提权的 Windows Named Pipe 用例存在跳过,不计为通过;云端 MySQL、PostgreSQL 专项有单独零跳过证据。
### 静态安全扫描:结果已复核,门禁未通过
扫描使用 `gosec v2.22.10`,以可执行文件的 Go 模块构建信息确认版本;报告中的展示版本为 `dev`。
本次为 Windows 构建平台扫描,不替代 Linux 平台完整扫描。完整 JSON 位于 `gosec.log` 的末尾,脱敏统计另存 `gosec-summary.json`,没有单独产生原计划的 `gosec.json`。
| 规则 | 数量 | 需要复核的范围 |
| --- | --- | --- |
| G115 | 13 | IMAP 序号、UID、消息数量的整数转换,以及旧数据库端口解析 |
| G202 | 6 | 跨库迁移中的动态 SQL、标识符转义和来源边界 |
| G304 | 13 | 配置、证书、迁移和发布流程中的动态文件路径 |
| G302 | 4 | 配置及部署目录的权限设置,需区分目录执行位与普通文件权限 |
| G306 | 2 | 发布产物与插件写入权限 |
| G505 | 1 | DNS 服务商签名代码中的 SHA-1 导入及协议使用边界 |
| G104 | 22 | 文件、锁、连接等关闭或释放操作的错误处理 |
初步源码复核发现,`config/migrate.go:685,714` 的两个端口转换之前已调用 `validPort`,其范围为 1 至 65535;不能将这两条直接宣布为已确认可利用的整数溢出。
迁移 SQL 中存在标识符引用函数,目录权限告警中存在有意使用的 `0700`;这些也需要逐条记录依据,而不是批量视为漏洞或批量忽略。
IMAP 相关转换优先复核位置:`services/list/imap_search.go:107`,`listen/imap_server/session_poll.go:38`,`session_messages.go:49,59,63`,`session_expunge.go:39,46,121`,`server.go:210,211`。
以上行号相对 `backend/`,其中同一行可能包含多个转换告警。
**61 条告警不是 61 个已确认可利用漏洞,但当前扫描门禁确实未通过。** 本轮没有关闭规则、添加批量忽略或修改扫描退出码;不能用单元测试通过覆盖这个阻塞。
### 最新候选的 Linux 目标扫描与专项复核
北京时间 2026 年 9 月 21 日 02:35,最新候选应用代码的扫描日志结束;进程退出码为 1。此次是在 Windows 主机设置 `GOOS=linux`、`GOARCH=amd64`、`CGO_ENABLED=0` 后执行,不是云端原生 Linux 扫描。
- 扫描 345 个文件、56,780 行;44 条告警,高 5、中 37、低 2;Go 包加载错误为零,现有 `nosec` 数量为 5。
- 分布:G115 5、G202 5、G204 1、G304 20、G302 8、G306 2、G505 1、G104 2。
- 原始输出为 `test-log/production-remediation-20260921/gosec-revocation-linux.log`;工具将 JSON 写入日志末尾,随后完整提取为同目录的 `gosec-revocation-linux.json`,不是另一次扫描。
- Windows 初轮与 Linux 目标报告的平台和代码基线不同,不能将 61 与 44 的差值解释为修复了 17 个漏洞。
新增两份回归测试,只扩展验收,不修改应用运行逻辑。云端 `023702` 专项在全新 MySQL、PostgreSQL 隔离库验证每库 7 个特殊表名的真实建表、写入、读取和哨兵表保留;另验证 20 组引用边界、25 组非法外键动作后缀,以及插件 UID/GID 的 24 组边界输入。最终两项测试程序均退出零,没有跳过,服务峰值分别为 9.6 MiB、20.7 MiB。
该专项为五条 G202 和两条插件 G115 提供源码与反例证据;没有新增规则忽略,原始扫描仍为 44 条、退出 1。其余 37 条尚未关闭,完整范围、失败记录和证据边界见 `静态安全告警复核记录.md`。
测试执行中遇到私有临时目录隐藏二进制、PostgreSQL 环境变量名称不一致、驱动尝试访问被隔离的默认客户端证书三个问题,失败和跳过日志全部保留,不计为通过。最终使用测试目录只读映射和私有临时目录内明确不存在的客户端证书路径,保留 `sslmode=require`,没有开放 `/opt/smail` 或 `/run/smail`。
本地证据位于 `test-log/production-remediation-20260921/security-evidence/`,十份下载文件的摘要在 `index.json`。最终数据库账号全部锁定,测试单元无运行进程,正式服务及其他五个保护服务没有变化。
## 发现的问题及未关闭门禁
### 9 月 21 日数据库与连接撤销整改
本节时间均为北京时间。应用候选提交为 `8899e74`,包含 `fa0cea9` 的 PostgreSQL 初始化修复;测试用版本标识为 `review-revocation-20260921`,不是正式发行号。
| 项目 | 证据 |
| --- | --- |
| 新候选 SHA-256 | `b969912d9713af4d0f20b0d91c9ce4baec38eea69a140497d59c81c33caeac44` |
| 云端候选路径 | `/var/tmp/smail-review-revocation-20260921/smail` |
| 本地原始证据 | `test-log/production-remediation-20260921/` |
| 新候选 SQLite | `evidence/smail-review-runtime-20260921-020012/` |
| 新候选 MySQL | `evidence/smail-review-runtime-20260921-020206/` |
| 新候选 PostgreSQL | `evidence/smail-review-runtime-20260921-020331/` |
| 新候选同机冷备恢复 | `evidence/smail-review-restore-20260921-020113/` |
**数据库问题与修复:** PostgreSQL 首次安装产生的安全连接选项与旧配置解析不一致,真实安装未能进入正式服务。修复安装侧连接选项,并仅允许可由正式配置等价表示的 `sslmode=require`、`timezone=UTC`、`search_path=public`;未知、重复及降级 TLS 的选项仍拒绝自动迁移。没有放宽成接受任意连接字符串。
MySQL 首轮探针只验证配置历史表存在,没有实际生成配置记录;现通过正式配置 API 提交日志级别变更,检查配置代次推进。三库最终轮均执行同一业务闭环,SQL 模式配置历史记录为 1、SQLite 文件数为 0;SQLite 仅有 `smail.db`,包含业务及配置表,完整性为 `ok`。单数据库要求不是限定部署路径,也不是同时启用三种数据库。
上一候选 `fa0cea9` 的 PostgreSQL、MySQL、SQLite 通过证据分别位于 `012553`、`012640`、`012740` 实例,冷备位于 `012826` 实例;它们仅作为此前修复的证据,不能代替上述新候选结果。
**旧协议连接缺陷:** `013718` 实例真实确认,协议码撤销后 SMTP、IMAP、POP3 新登录均被拒绝,但三种旧连接仍可操作。应用现绑定认证时的用户与单个凭据快照,在数据命令入口复核数据库状态;数据库错误、凭据撤销或轮换、用户安全状态变化时拒绝旧授权。拒绝后的连接不因重新启用恢复权限,命令复核不重复执行密码哈希。
- SMTP 复核 `MAIL`、`RCPT`、`DATA`,并在 DATA 读取完成后再次复核;不允许失效的已认证连接降级成匿名收信。
- IMAP 统一保护数据命令与 IDLE 轮询,失效监听连接不能阻断其他有效收件连接。
- POP3 在事务命令前复核;撤销连接不能通过 `QUIT` 提交延迟删除。
- 三种数据库实机测试均保持原连接跨越正式撤销 API 调用,分别验证协议码及客户端专属码的六个拒绝结果;两组结果全部为真。
- 专项竞态回归及全量 `node test/run.mjs backend -race -count=1 -p 1 ./...` 通过;全量日志为 `test-log/run-2026-09-20T17-49-20-822Z-31240/`。
所有上述新候选实例均无 OOM、无资源采集或清理错误,正式服务及其他五个保护服务的进程、调用标识保持不变。测试 SQL 账号锁定、数据库桥接关闭。冷备恢复包含十八个文件,空目录还原字节一致,源目录未变,历史及新增中文邮件和附件均可读取;仍只计同机冷备恢复。
**新增 HTTP 会话验收:** 在隔离实例创建独立普通用户,先证明原 Cookie 可访问,再调用正式退出、禁用、修改密码 API。原 Cookie 重放和另一独立旧会话必须明确返回业务错误码 `403`,不接受服务器错误或单纯客户端清空 Cookie 作为通过。另验证无关会话保留、旧密码被拒绝、新密码可登录、超管会话不受影响。
首轮在三库通过,SQLite 同时复验独立 Nginx 与冷备恢复(`020610`、`020738` 实例)。复审后加强禁用再启用检查:使用另一条独立登录会话,在禁用期间完全不发请求,避免仅证明先前已销毁的会话不能恢复。最终通过目录如下:
| 数据库与拓扑 | HTTP 最终证据目录 |
| --- | --- |
| SQLite、独立 Nginx、上游 TLS 校验 | `evidence/smail-review-runtime-20260921-021127/` |
| MySQL、直接 TLS | `evidence/smail-review-runtime-20260921-021257/` |
| PostgreSQL、直接 TLS | `evidence/smail-review-runtime-20260921-021440/` |
三轮八项会话结果全部为真,同时再次通过协议码及客户端码撤销、邮件正文与附件读取、IMAP APPEND/EXPUNGE 和过载恢复。测试工具本地 runtime 回归 33 项通过,云端 Linux 部署回归最终 103 项通过,日志为 `linux-deployment-session-final.log`。这部分仅扩展验收工具,使用的应用二进制仍为上表同一个 SHA-256。
`evidence-revocation-index.json` 对十一份新候选有效结果目录记录文件摘要,逐份复核通过状态、正式服务不变、资源和清理错误为空;SQL 模式还复核单库配置历史及账号锁定。`live-final-revocation.json` 再次确认六个正式服务状态不变、本轮隔离测试单元全部停止、正式主程序摘要不变。
**保留失败及验证边界:**
- 原 `013403` SMTP 探针依赖不存在的隔离域 MX,返回 `451`,未到达撤销阶段;后改用同连接 `MAIL/RCPT/RSET` 验证,不能把原失败算作撤销缺陷。
- IMAP `TestIdleNotice` 首次专项回归超时;原测试把 IDLE 继续响应当成应用注册完成。增加等待实际注册后,专项与全量通过,未降低通知断言。
- 构建首次因外层 PowerShell 把 Vite 警告视为错误中断;`build-revocation-retry.log` 对应完整重建成功,旧日志保留。
- HTTP 反代首轮错误传入全局 `nginx.conf` 而非站点 `smail.conf`,验收器在启动服务前拒绝;改为正式站点模板后通过,失败日志为 `cloud-http-session-sqlite.log`。
- 早期归档下载器对不存在的可选文件留下了零字节占位;这些不是有效证据,也没有删除。后续下载先确认远端文件存在、非空,再校验 JSON。
- 以上均为隔离实机或自动化证据,不替代真实浏览器、外部邮件最终收件、自动证书续期或正式实例升级。
### 历史凭据:生产阻塞
四个 Git 跟踪的 DNS 工具原含历史明文云 API 凭据,现已改为读取 `SMAIL_ALIDNS_ACCESS_KEY_ID` 和 `SMAIL_ALIDNS_ACCESS_KEY_SECRET`。
新增扫描器仅输出文件、行号和类别,不输出匹配值;检查云 AccessKey 特征、私钥标头和 Python 密钥字面量。
同时修复页面探针的 Python 语法错误,测试 URL 改为环境变量注入。
最终复核发现 `add_dns.py` 在读取环境变量之前尝试 SSH 连接,现已将凭据检查前移;补充反例覆盖四个工具分别缺少任一凭据时,不创建 SSH 客户端或发起 HTTP 请求。
**源码和当前提交清理不代表历史凭据已撤销。** 未执行未经授权的密钥轮换、Git 历史重写或强推。
需要凭据所有者完成旧凭据撤销、访问审查及安全注入新凭据;在此之前不允许生产放行。
### 资源容量:记录真实失败
23:29 的反代测试在 128 MiB 应用限额下,恢复码生成阶段发生 cgroup OOM,代理返回 `502`。
线上服务未受影响。验收器增加明确且有限的内存参数,同时提高启动前可用内存门槛。
在 192 MiB 限额下,23:31 反代重测通过,应用峰值约 73.9 MiB;23:36 空安装及还原轮也通过且无交换空间使用。
单次低峰值不能推翻先前 OOM,不把 128 MiB 宣称为可用生产容量;生产限额仍为 512 MiB,尚缺长时容量和告警演练。
### 证书续期:有效证书不代表生命周期已验收
当前 `management=custom`、`mode=managed_upload`。应用仅在自动模式执行自动续期,不能因为有定时检查代码就认定当前手动模式会续期。
根域加泛域名的当前证书已通过校验,但真实 DNS 挑战、调度、失败告警和换证后全协议热加载仍需实机验收。
仓库旧外部续期脚本仍采用固定五域名配置,不能直接套到根域加泛域名的当前部署;本轮未启用或修改线上续期任务。
### 其他未完成范围
真实浏览器流程、超级管理员正式命令交互、外部邮箱最终收件、插件外部调用、异机灾备等保留未完成状态。HTTP 旧会话及协议旧连接的已验证范围见 9 月 21 日整改记录,不能继续全部标为未验证,也不能扩大为所有安全场景已通过。
Windows 受保护本地通道验收需要提权会话,不得降级成公开 TCP 或普通 HTTP 重置接口。
测试全部通过的限定项可以单独复核,但不能将此记录标题或部分勾选解释为整个项目审计结束。
## 本轮收尾边界
### 9 月 21 日管理员恢复补充
详见 `管理员恢复安全补充验收.md`。新主程序摘要为 `ef9d5c20fb2c66b1d499feac9f0b7dc72e51f235366f968e7c9b6ceb05cfb22e`,在 SQLite、MySQL、PostgreSQL 的新空实例中分别通过直接 TLS 回归;配置历史和业务保持同库。缺少测试辅助模块导致的 MySQL 首次失败已保留,补齐模块后另建空库通过。
全项目静态复扫实际结果为 38 条,退出码仍为 1;不增加 `nosec`,不以降低六条告警替代生产放行。独立浏览器启动被执行策略拒绝,准备实例和隧道已经停止,既未复用 Scert 浏览器,也没有浏览器通过证据。正式程序、六个保护服务及用户原有报告均保持不变。
### 9 月 21 日根域名证书校验补充
详见 `根域名证书校验补充验收.md`。云端反例证实仅有泛域名的证书会被自动 DNS 配置复验、加载及导出错误接受;现统一加入根域名要求,并验证失败时保留有效导出文件及内存证书。云端配置证书专项 21 项、SSL 初始化包 26 项零跳过通过,最新主程序 `bb451caf67f6421253c5b4edddc6fce9961ac04613c4fe3166db36a465291939` 的三库空数据回归也已通过。
本次配置包静态复扫仍为原有七条,退出码 1;不是再次全项目复扫。测试仍不替代真实 DNS 自动续期、全协议换证、浏览器或正式实例升级。
本轮整理明确列出的应用整改、回归测试、验收工具、持续集成和本记录;原有 `docs/云端全项目测试报告.md` 的用户修改不编辑、不加入本轮提交。
本轮不执行生产版本替换,测试候选与正式实例保持分离。未关闭门禁继续保留,不能将本轮提交或推送成功解释为生产验收通过。
### 9 月 21 日数据库迁移与重启补充
详见 `数据库迁移重启补充验收.md`。真实云端迁移发现后台重启可能提前关闭 HTTP/HTTPS 响应,现改为有界排空后停服。本地确定性反例、五轮竞态回归和云端六项零跳过专项共同复核修复。
SQLite 已完成迁移失败不覆盖目标、成功迁移、内部重启、系统级进程重启、目标不可读时明确失败不回退、恢复后真实收发与历史配置保留。最新主程序 `21ec0820f9b09eb1f8262d6d444bbc5d235d4cf64115d6f4b3378be2083533a0` 的 MySQL/PostgreSQL 基础回归通过,业务与配置历史同库、SQLite 文件零个;尚不能扩大为 SQL 切库进程重启验收通过。
失败反例和离线源库均保留,正式服务与其他项目未变。SQL 迁移恢复、迁移中断、浏览器、外部服务、安全告警及凭据轮换等仍有未关闭门禁。
### 9 月 21 日 SQL 切库与扩大部署回归补充
上述 SQL 待办随后取得新证据,详见 `SQL切库与部署回归补充验收.md`。MySQL、PostgreSQL 两轮同引擎切库、系统级进程重启及目标账号故障恢复已通过;源库零活动连接、目标库独占新邮件写入,配置历史完整保留,未生成额外 SQLite。26 份下载证据已重新与远端逐份核对摘要,源/目标账号均锁定,PostgreSQL 临时建库权限已撤销。
云端扩大 Python 部署测试在修正隔离运行器的能力传递后,125 项、零跳过、退出零。此前 Windows 平台不兼容、非特权夹具失败、隔离 Nginx 降权失败的日志均保留。修正只为本轮隔离单元显式传递原有能力边界内的 `CAP_SETUID`,没有关闭隔离、改变正式 Nginx 或降低应用安全检查。
这不是全项目验收完成:同引擎切库不等于跨引擎迁移矩阵通过;扩大部署测试不等于真实 DNS 自动续期、全协议换证、浏览器交互或外部投递通过。迁移中断、历史凭据轮换、其余安全告警及其他生产门禁继续保留。
### 9 月 21 日 SQLite 复制中断补充
详见 `SQLite复制中断恢复补充验收.md`。未提交复制事务中的真实 SIGKILL 中断、源库和配置保持不变、恢复后的登录与真实邮件读写、失败目标拒绝覆盖已通过。随后正常迁移及两类重启、目标权限故障恢复通过,最终活动业务库只有 `migrated.db`,配置历史同库;离线源库和失败目标仅保留为证据。
扩充云端部署套件实际执行 131 项、零跳过、退出零;20 份中断实机证据、四个工具及 610 个后端源码摘要已复核。正式服务与其他项目保持不变,未替换正式程序。SQLite 提交及配置切换临界点、SQL 中断、跨引擎矩阵和前述其他生产门禁仍未关闭,不能宣称整体验收通过。
### 9 月 21 日双 SQL 跨引擎补充
详见 `SQL跨引擎迁移补充验收.md`。MySQL → PostgreSQL 首轮实机被完整性校验拒绝,经过只读 Go 驱动诊断,定位并修复定长字符填充表示差异。修复仅按源引擎和列类型处理填充,不忽略任何业务表,不裁剪普通文本、二进制值或 SQLite 数据;保留失败反例和 22 个子用例。
新候选完成 MySQL ↔ PostgreSQL 双向迁移、内部重启、系统级重启、目标账号故障及恢复后的真实三协议读写,源库零活动连接、源内容不变、配置历史同库、没有 SQLite 文件。26 份实机证据、六个工具及 611 个后端源码摘要再次核对一致,测试账号锁定且临时建库权限撤销,正式六服务和程序未变。
云端完整部署回归实际为 136 项、零跳过;新增 Go 专项两个顶层测试零跳过。本地全量后端通过,但明确保留 35 个顶层和 12 个子测试跳过,不能称全平台零跳过。涉及 SQLite 的其余四个跨引擎应用级方向、中断临界点和此前其他生产门禁仍未关闭,整体生产验收尚未通过。
### 9 月 21 日 SQLite 跨引擎补充
详见 `SQLite跨引擎迁移补充验收.md`。沿用源码摘要一致的最新编译候选,只扩展验收工具;SQLite → MySQL、SQLite → PostgreSQL、MySQL → SQLite 三个方向通过。两个 SQLite 源均停止占用,MySQL 源活动连接归零;目标独立承载业务和配置历史。两类重启、目标故障拒绝启动与恢复、原会话、历史邮件及新增邮件正文和附件均通过。
PostgreSQL → SQLite 两次在初始化恢复码生成时发生 30 秒 HTTP 读取超时,未进入迁移。没有降低哈希强度、减少码数量或放宽超时条件,不将失败标为通过。该初始化耗时问题和最后一个迁移方向继续待查。
最终本地运行时回归 79 项、Linux 完整部署回归 149 项通过,Linux 零跳过;47 份成功与失败证据、七个工具及 611 个后端源码摘要已独立复核。五个 SQL 测试账号锁定,测试单元全部停止,正式六服务和程序未变;用户原测试报告未编辑。全项目生产验收仍未通过,历史凭据、其余安全告警、真实浏览器、外部投递、自动续期、容量及异机灾备等范围不能由本轮结果代替。
### 9 月 21 日恢复码取消与最终 PostgreSQL → SQLite 补充
详见 `恢复码取消与低资源补充验收.md`。恢复码生成接入 HTTP 请求取消、可取消凭据锁及事务回滚,管理员代生成入口补齐资源繁忙时的可重试状态。原 64 MiB Go 内存目标的 30 秒超时保留为失败;128 MiB Go 目标是明确区分的另一种资源配置,没有降低密码强度、减少恢复码或放宽超时。
最终后端候选 `87eb782b34ac16473259e4b63caf98dd9dd073c887d0dcad008742bbc913bd35` 在 `20260921-085155` 隔离实例完成 PostgreSQL → SQLite 迁移、两类重启、目标故障恢复及真实邮件读写。进程环境值已核对,三阶段源连接为零,目标业务与配置历史同库,只使用一个 SQLite 文件。正式实例未替换。
本地全量后端 1888 个测试及子测试通过、41 个跳过、零失败;Linux 恢复码专项 19 个测试及子测试通过、零跳过;本地运行时工具 81 项及云端部署工具 151 项通过,云端零跳过。不同范围和不同候选的结果分别保留,不能叠加为全部生产门禁通过。
收尾独立复核 127 份文件本地与远端摘要、616 个后端源码摘要均一致,八个测试数据库账号锁定,三次超时失败证据保留。正式六服务和主程序未变,测试单元全部停止;用户原测试报告没有编辑或暂存。其余安全、续期、浏览器、外部投递、容量和灾备门禁继续未关闭。
### 9 月 21 日双 SQL 未提交复制中断补充
详见 `SQL复制中断恢复补充验收.md`。最新后端重新编译的同一候选 `468c0ce4dd6555d58c8cb79a920c9a0e9008e41e8d7894d4704d6f212036d761` 完成 MySQL、PostgreSQL 未提交复制事务中的真实进程终止及恢复。两轮均观察到唯一未结束事务,独立查询的目标邮件和配置历史均为零行;SIGKILL 后事务回滚,源库全表数据及活动配置摘要保持一致。恢复后历史与新邮件正文、附件、三协议读取及失败目标防覆盖均通过。
随后正常迁移、内部重启、进程重启、目标账号故障拒绝启动及恢复通过;活动库唯一、配置历史与业务同库,没有额外 SQLite。离线源库与失败目标保留为证据,不当作第二个活动业务库。使用 128 MiB Go 内存目标及 192 MiB 硬上限,不掩盖旧配置的超时失败。
本地运行时工具 90 项通过,云端完整 Linux 部署工具 160 项通过、零跳过。Windows 全部署套件的两项路径断言失败和两个 `fcntl` 加载错误单独保留,不能称全平台通过。前端及插件资源仅复用并核对摘要,不宣称本轮完整发行包已重新构建。
22:56 独立复核 40 份实机证据、两份程序及两组八个工具的远端摘要一致,709 份构建输入(含 619 份 Go 源文件)未漂移;六个测试账号锁定,PostgreSQL 建库权限撤销,测试库连接及本轮测试进程归零。正式六服务和程序未变,用户原全项目报告没有编辑或暂存。本项复审通过,但未替换正式部署。
跨引擎复制中断和最终完整发行候选统一验收仍未关闭;本轮双 SQL 结果已覆盖 MySQL、PostgreSQL 的提交与配置切换临界点,但不扩展为整体生产放行。
### 9 月 21 日晚启动的配置事务崩溃恢复补充
详见 `配置事务崩溃恢复补充验收.md`。补齐真实测试子进程强制终止、正式配置管理器启动恢复、根配置切换前后、损坏归档拒绝及恢复幂等验证。分区部分写入和根清单滞后明确标为构造落盘状态,不冒充完整应用中的指令间隙观测。
发现并修复新事务首份清单发布前被终止时留下无效活动目录、从而阻塞启动的问题:准备归档改放在独立 `transaction-staging` 目录,完整后原子发布,再开始替换活动配置。旧版活动区的不可信残留继续保留并失败关闭,不擅自删除。暂存目录不是额外数据库。
最终 Linux 崩溃专项重复三次,114 个测试及子测试通过,78 次确认的 SIGKILL,零失败、零跳过;Linux 完整配置包 417 项通过、1 项真实数据库集成测试跳过。Windows 全量后端 1945 项通过、42 项跳过、零失败。三种数据库配置选择下的文件恢复测试不等同三种真实数据库提交联合验收。
最新后端候选 `89e115d94ef2f12fd2ab082888f22517460e87cbe9e1b5a98d32f55ae38426b8` 在 `20260921-235814` 隔离实例完成 SQLite 正常迁移、内部与进程重启、目标库故障失败关闭及恢复后的邮件正文和附件验证。最终活动库为 `migrated.db`,业务与配置历史同库,源库及占用目标仅作为离线证据保留。前端及插件资源复用,不宣称完整发行包重构建,也未替换正式部署。
独立复核 21 份远端程序、工具与日志文件摘要一致、710 份构建输入未漂移,六个已核查测试单元均停止,隔离应用活动事务和暂存区为空。正式六服务及程序、用户原全项目报告未变。本轮 SQLite 配置事务专项范围复审通过;完整发行候选、SQLite 其他中断边界及其他生产门禁继续未关闭。MySQL、PostgreSQL SQL 提交与配置切换联合故障结果见下节。
### MySQL、PostgreSQL SQL 提交与配置切换联合故障补充
本节记录工作区现有的四份联合故障结果,不覆盖或改写用户原有的 `docs/云端全项目测试报告.md`。测试使用同一份隔离候选主程序,SHA-256 为 `0daae897a5272f53ff78c23ef47f043e5ec18e6795424a271bb568fe159de223`;正式 `/opt/smail` 实例未替换、未重启、未清库,同机其他服务未停止。
| 数据库 | 故障边界 | 结果文件 | 结果 |
| --- | --- | --- | --- |
| MySQL | 根配置原子替换前 | `test-log/production-remediation-20260921/switch-fault-result-20260922-010951.json` | 通过 |
| MySQL | 根配置原子替换后 | `test-log/production-remediation-20260921/switch-fault-result-20260922-012102.json` | 通过 |
| PostgreSQL | 根配置原子替换前 | `test-log/production-remediation-20260921/switch-fault-result-20260922-013137.json` | 通过 |
| PostgreSQL | 根配置原子替换后 | `test-log/production-remediation-20260921/switch-fault-result-20260922-013651.json` | 通过 |
四份结果共同确认:
- SQL 目标库可见完整已提交邮件数据,配置历史已提交且摘要一致,事务清单的 `sections_committed` 阶段和根配置替换边界均被真实观测。
- 只有在应用线程全部停止后才终止隔离进程;强制终止后,正式配置管理器可自动恢复,历史邮件、新邮件、正文、附件以及再次进程重启均可读取或通过。
- 源库内容未变化,源库连接归零,目标库成为唯一活动数据库;完整性结果为 `sqlite_files: 0`,配置记录为 1,清理错误和资源错误均为空。
- PostgreSQL 临时建库权限已撤销,随机测试数据库账号已锁定;正式服务的 `ActiveState`、`MainPID`、`InvocationID` 和 `NRestarts` 在结果证据中保持不变。
此前修复前捕获的失败结果 `switch-fault-result-20260922-003538.json` 保留为真实反例:它记录了原子写临时文件误判导致的启动恢复阻断,不能改写为通过,也不计入四个通过场景。
上述四个结果只关闭 SQL 提交与配置切换联合故障专项,不等同于最终生产放行。浏览器完整验收、外部邮件投递与恢复邮件、插件调用及密钥边界、Windows 提权本地 IPC、自动续期与换证、容量长稳、异机灾备、真实公网 DNS/泛域名证书及最终统一发行候选仍未关闭。
本次继续执行期间尝试再次进行云端只读收尾复核,但 SSH 返回 `Authentication failed`;未使用不安全的主机密钥或 TLS 绕过,也未对云端执行任何变更。因此本节引用的是已保存的隔离结果和既有收尾证据,不能把本次失败的即时连接尝试表述为新的云端复核通过。
结果文件名含 `20260922`,而当前会话适用日期为 2026 年 9 月 21 日;本节仅如实登记工作区现有文件内容,不据此伪造本会话的执行时间线。日期一致后仍应使用严格 SSH 凭据重新执行只读收尾复核。