Smail/docs/模拟部署与最新构建.md
smail 934acd9856
Some checks are pending
Security Checks / security (push) Waiting to run
补齐最新模拟部署与审计导出验收记录
2026-09-08 19:20:05 +08:00

115 lines
9.0 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.

# 模拟部署与最新构建
## 已确认要求
- 源码继续放在 `backend/`、`frontend/`。
- 生产、开发模拟部署均使用 `yunx-test/`,禁止把 `out/` 当运行目录。
- 配置固定为 `config/` 中的五个 JSON;证书及加密密钥归 `ssl/`;数据库归 `data/`;日志归 `log/`。
- 保留独立的 `smail`、`smail-admin`。Windows 使用 `.exe` 后缀。
- 前端开发仍使用原源码目录的 Vite 热更新。
- 不清空现有业务库,不删除原证书、密钥及历史备份。
## 当前任务状态
- `[✓]` 修改前的文档基线已提交并推送。
- `[✓]` 源码指纹和产物 SHA-256 校验已加入构建、部署入口。
- `[✓]` 开发启动入口固定使用 `yunx-test`,没有沿用旧后端;日志与进程路径已核对。
- `[✓]` Vite 从原 `frontend` 源码启动,使用模拟部署目录的域名和证书;浏览器已确认加载开发客户端。
- `[✓]` 停服备份、无损迁移到 `yunx-test`,原配置、证书、账号库和备份全部保留。
- `[✓]` 配置事务与历史备份迁入 `data/smail-state.db`,五个 JSON 仍是生效配置文件。
- `[✓]` 密钥、TLS、DKIM、ACME 和审计日志迁到最终目录,目录检查通过。
- `[✓]` 三个内置插件已编译并嵌入主程序;运行解包目录位于操作系统临时目录,不混入部署根目录。
- `[✓]` 迁移后的完整构建、产物哈希校验通过;审计导出修复后再次执行前端 138 项、部署 4 项及全量 Go 测试,全部通过。
- `[✓]` Windows 标准构建与后端测试入口共用工作区互斥量,4 项部署回归通过。
- `[✓]` 新目录开发运行、登录后刷新保持会话、配置读取和配置审计 CSV Blob 验收通过。
- `[✓]` HTTPS Cookie 属性及 CSRF 缺失、错误、正确令牌分支已实际验证。
- `[✓]` 构建互斥及审计导出修复后的完整部署、重启和源码指纹复查通过。
- `[✓]` 审计 Blob 错误保留最近认证状态;真实页面密码确认、自动重试及成功提示通过,下载文件落盘尚未核验。
- `[!]` Windows 生产模拟启动受管理员恢复 Named Pipe 权限限制,未降级或绕过保护。
- `[!]` Windows 生产插件隔离尚不可用,不能把插件打包成功视为真实插件运行验收。
- `[ ]` 配置保存后文件与历史状态数据库的浏览器写入验收。
- `[ ]` 全新初始化、忘记密码、二次验证、强制改密与普通用户权限的独立完整流程验收。
## 已实现入口
完整构建并部署二进制,不覆盖配置和数据库:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File deploy/deploy-runtime.ps1
```
完成运行数据迁移后,启动前后端:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File deploy/start-dev.ps1 -Service all
```
后端启动总是先完整编译、部署和校验。单独启动前端会校验当前源码与部署产物,不允许搭配过期后端。缺少迁移后的配置、账号库或密钥时拒绝启动,不会创建另一份空库。
构建收据保存在 `out/build-state.json`,不混入部署根目录。已有程序被覆盖前备份至 `out/deployment-history/`。历史前端编译目录归档至 `out/build-history/`,不删除生成物,也不将历次散列资源重复嵌入新程序。
## 构建与测试互斥
Windows 下,`deploy/build.ps1` 与 `node test/run.mjs backend` 共用工作区命名互斥量。构建计算指纹、归档嵌入资源之前就获取锁,测试从调用 Go 到退出始终持锁。遇到冲突立即拒绝执行并给出中文提示,不能继续移动资源或使用历史产物冒充成功。
锁标识由源码目录生成:同一登录会话内,不同工作区可并行;同工作区必须串行。正常退出和进程异常结束均不需要删除锁文件。不同 Windows 登录会话、直接调用 `go test`、直接调用 Vite 或单独插件构建不在该锁的保证范围内,不能与完整构建并发执行。
```powershell
# 前端、部署回归和后端依次执行,记录统一进入 test-log。
node test/run.mjs all -p 2 ./...
# 只检查构建互斥及后端参数转发。
node test/run.mjs deployment
```
新增的 PowerShell 文件使用 UTF-8 BOM,以便 Windows PowerShell 5.1 正确解析中文提示;JavaScript、Go 和 JSON 不因此添加 BOM。
前端热更新只更新源码开发页面,不会自动重编嵌入前端的主程序。源码修改完成后,仍须通过标准完整部署/重启入口刷新 `yunx-test`,不能只刷新浏览器就宣称运行包已更新。
## 2026-09-08 实测记录
- 迁移备份与核对收据:`test-log/deployment-migration-20260908-183213/receipt.json`。
- 互斥修复后的完整自动化测试:`test-log/run-2026-09-08T10-57-18-160Z-42364/`,前端 131 项、部署 4 项、Go 全量测试均通过。
- 完整构建期间,通过标准入口启动的后端测试被互斥量拒绝,退出码为 `1`:`test-log/run-2026-09-08T11-00-20-202Z-41728/backend.log`。这次失败属于预期防护结果,不是 Go 代码测试失败。
- 审计导出修复后的前端回归:`test-log/run-2026-09-08T11-05-45-804Z-42172/`,138 项全部通过。
- 当前代码再次执行 `node test/run.mjs all -p 2 ./...`:`test-log/run-2026-09-08T11-16-56-516Z-46036/`,前端 138 项、部署 4 项和全量 Go 测试全部通过。自动化测试使用独立测试环境,不清空正在运行的业务数据库。
- 浏览器页面为 `https://xuans.com/#/`,前端 80 跳转 HTTPS 443,后端开发接口监听 5201。
- 浏览器真实登录后强制忽略缓存刷新,收件箱与用户信息接口仍正常。配置状态、基础、邮件、证书、历史备份及插件列表读取成功。
- 配置审计导出返回 `text/csv` Blob;真实页面已完成“确认当前密码 → 自动重试 → 审计记录已导出”,但尚未核验下载文件落盘。
- 缺失或错误 CSRF 请求头均返回业务错误码 `100`,提示“请求来源校验失败”;当前接口使用 HTTP 200 包装业务错误,不能只看 HTTP 状态判断成功。
- 正确 CSRF 请求返回 CSV;HTTPS 登录响应中会话 Cookie 为 `Secure/HttpOnly/SameSite=Lax`,CSRF Cookie 为 `Secure/SameSite=Strict`。后者允许前端读取用于请求头,不应加 `HttpOnly`。
- Cookie 响应验证使用独立临时登录会话,结束后已退出;未将密码、Cookie 值或令牌写入测试记录。
- 生产模拟失败记录:`test-log/production-runtime-20260908.log`。开发运行明确停用管理员恢复通道,生产不能复用这一豁免。
### 审计导出最近认证修复
登录超过最近认证时限后,导出接口返回 HTTP `403`、业务错误码 `405`,以及 `RECENT_AUTH_REQUIRED`。原先 Axios 使用 `responseType: 'blob'` 时把 JSON 错误包装为 Blob,错误拦截器读不到业务错误码,只显示“无权访问”;导出操作也未接入现有的密码确认重试流程。
修复后,仅解析不超过 1 MiB、JSON 类型且具有非零数字 `errorNo` 的 Blob 错误信封;CSV、正常 JSON 导出、未知或损坏内容保持原样。导出操作复用最近认证流程,取消确认不误报失败,认证后最多重试一次,不放宽后端权限要求。
浏览器真实请求链已复核:
1. `reqid=1113`:`POST /api/v1/audits/config` 返回 `403`,页面弹出“确认当前密码”。
2. `reqid=1114`:`POST /api/v1/security/reauth` 返回 `200`,身份确认成功。
3. `reqid=1115`:自动重试 `POST /api/v1/audits/config` 返回 `200`,页面提示“审计记录已导出”。
验收记录不保存密码、Cookie 值、CSRF 令牌或导出审计内容。
### 最终运行核对
2026-09-08 19:15 左右,`node deploy/check-runtime.mjs` 与 `node deploy/build-state.mjs verify --deployed` 均通过:
- `out/build-state.json` 记录构建源码提交为 `9855a20`,构建时间为北京时间 `19:06:33`。
- 部署产物与当前源码指纹一致;之后的检查点或仅文档提交不会改变源码指纹,不需因此重复替换运行包。
- 后端进程 PID `26148`,路径为 `D:\Desktop\Smail\yunx-test\smail.exe`,带明确的开发恢复通道停用参数。
- 前端进程 PID `21008`,使用原 `frontend/node_modules/vite/bin/vite.js`,监听 `443`;后端 `5201 /api/ping` 与前端 HTTPS 均返回 `200`。
- `yunx-test` 根目录仅有 `config/`、`ssl/`、`data/`、`log/`、`smail.exe`、`smail-admin.exe`;`config/` 仅有约定的五个 JSON。
上述 PID、构建时间和请求编号是本次验收快照;下次启动或验收必须重新检查,不应直接沿用。
## 验收边界
此次是保留现有业务数据的迁移验收,未清空数据库,不是生产首次初始化验收。旧根目录的 `config/`、`data/`、`ssl/` 是保留的迁移来源,不是当前服务的生效目录。
生产管理员恢复、Windows 插件隔离、其他完整账号流程仍有未通过或未验证项目。编辑器异步包仍有约 809 kB 的 Vite 体积告警;不能宣称全部功能或全部优化均已完成。