Files
quyun-v2/docs/release-evidence/2026-02-09.md

302 lines
9.2 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.
# Release Evidence — 2026-02-09
## Scope
生产级部署能力 P0 补齐T1-T14 的规划与执行证据,含已完成项与待执行项状态):
- T1 敏感信息台账
- T2 密钥轮换与注入策略
- T3 仓库明文敏感信息清理(模板化占位)
- T4 release 模式 DB TLS 强制
- T5 `/readyz` 依赖感知
- T6 readiness 测试
- T7/T8/T9 CI 门禁补齐
- T10 前端 lint check/fix 分离
- T11/T12 runbook
- T13/T14 预发演练证据模板
## Environment
- Repo: `/home/rogee/Projects/quyun_v2`
- Branch: `main`
- Plan: `docs/plan.md`2026-02-09 版本)
## Evidence A — T1 敏感信息台账
### A1. 高风险(生产)
| 文件 | 字段 | 问题类型 | 风险等级 | 处理状态 |
|---|---|---|---|---|
| `backend/config.prod.toml` | `Database.Password` | 明文/静态值 | P0 | 已改为 `${DB_PASSWORD}` |
| `backend/config.prod.toml` | `JWT.SigningKey` | 明文/静态值 | P0 | 已改为 `${JWT_SIGNING_KEY}` |
| `backend/config.prod.toml` | `Storage.AccessKey`/`Storage.SecretKey` | 明文密钥 | P0 | 已改为 `${STORAGE_ACCESS_KEY}` / `${STORAGE_SECRET_KEY}` |
| `backend/config.prod.toml` | `App.Super.Token` | 空值(生产无显式注入) | P0 | 已改为 `${APP_SUPER_TOKEN}` |
| `backend/config.prod.toml` | `Database.SslMode` | `disable` | P0 | 已改为 `require` |
### A2. 中低风险(本地/测试)
| 文件 | 说明 | 状态 |
|---|---|---|
| `backend/config.toml` | 本地开发配置,可保留示例性默认值 | 保持不变 |
| `backend/config.test.toml` | 测试专用凭据 | 保持不变 |
| `backend/config.minio.toml` | 本地 MinIO 测试凭据 | 保持不变 |
| `backend/config.full.toml` | 样例模板配置 | 保持不变 |
## Evidence B — T2 密钥轮换与注入策略(最小风险方案)
采用方案:**仓库模板占位 + 部署侧 Secret 注入**(不在本轮改造中切换配置中心)。
### B1. 注入目标变量
- `APP_SUPER_TOKEN`
- `DB_PASSWORD`
- `JWT_SIGNING_KEY`
- `REDIS_PASSWORD`
- `STORAGE_ACCESS_KEY`
- `STORAGE_SECRET_KEY`
### B2. 轮换流程(执行标准)
1. 生成新密钥(高熵、最小权限)。
2. 在部署平台配置上述 Secret。
3. 预发验证(登录、上传、下单、审计等关键流)。
4. 正式发布切换到新密钥。
5. 失效旧密钥并记录轮换审计。
## Evidence C — T3 仓库明文清理
### C1. 已完成变更
- `backend/config.prod.toml`
- `Mode = "release"`
- `Database.Password = "${DB_PASSWORD}"`
- `Database.SslMode = "require"`
- `JWT.SigningKey = "${JWT_SIGNING_KEY}"`
- `App.Super.Token = "${APP_SUPER_TOKEN}"`
- `Redis.Password = "${REDIS_PASSWORD}"`
- `Storage.AccessKey = "${STORAGE_ACCESS_KEY}"`
- `Storage.SecretKey = "${STORAGE_SECRET_KEY}"`
### C2. 本轮不改动项(避免破坏本地开发/测试)
- `config.toml` / `config.test.toml` / `config.minio.toml` / `config.full.toml` 的测试示例值保留。
## Evidence D — T4 release 模式 DB TLS 强制
### D1. 代码变更
- `backend/providers/postgres/config.go`
- 新增 `IsTLSEnabled()``sslmode != disable` 判定)
- `checkDefault()``SslMode` 做标准化trim/lower
- `backend/providers/postgres/postgres.go`
- 注入 `*app.Config`optional
-`App.IsReleaseMode()``!conf.IsTLSEnabled()` 时,启动失败并返回错误
### D2. 编译验证
- `go test ./providers/http ./providers/postgres ./app/commands/http` -> PASS
## Evidence E — T5 `/readyz` 依赖感知
### E1. 代码变更
- `backend/providers/http/engine.go`
- `Service` 新增 `healthCheck` / `readyCheck`
- `Provide` 支持注入 `*sql.DB`optional`*storage.Storage`optional
- `/healthz` -> `handleHealthz`
- `/readyz` -> `handleReadyz`
- `readyCheck` 逻辑:
- 若存在 DB 连接则执行 `PingContext`
- 若 Storage 为 `s3``CheckOnBoot=true`,校验 endpoint/bucket 配置完整性
## Evidence F — T6 readiness 测试
### F1. 新增测试
- `backend/providers/http/engine_test.go`
- DB ping 失败时返回错误
- S3 配置缺失时返回错误
- 依赖正常时返回 nil
### F2. 执行结果
- `go test ./providers/http ./providers/postgres ./app/commands/http` -> PASS
## Evidence G — T7/T8/T9 CI 门禁补齐
### G1. Workflow 变更
- 文件:`backend/.gitea/workflows/build.yml`
新增作业:
1. `FrontendChecks`
- portal: `npm ci` + `lint` + `build`
- superadmin: `npm ci` + `lint` + `build`
2. `BackendChecks`
- `go test ./...`
- `go build`
- API smoke: 启动服务后检查 `/healthz``/readyz`
3. `DockerImage`
- 依赖前两项成功后再构建并推送镜像
## Evidence H — T10 前端 lint check/fix 分离
### H1. 变更
- `frontend/portal/package.json`
- `lint` 改为 check-only
- 新增 `lint:fix`
- `frontend/superadmin/package.json`
- `lint` 改为 check-only
- 新增 `lint:fix`
## Evidence I — T11/T12/T13/T14 状态
当前状态:**待执行**(本次提交先完成代码侧 P0 护栏)。
- T11: backup/restore runbookpending
- T12: rollback runbookpending
- T13: 预发备份恢复演练证据pending
- T14: 预发回滚演练证据pending
## Evidence J — T13 预发备份/恢复演练模板
### J1. 演练记录模板(待执行)
- 演练环境:`<staging-env-name>`
- 执行人:`<owner>`
- 窗口:`<start/end>`
#### 数据库备份
- 命令:`pg_dump ...`
- 退出码:`<0/非0>`
- 产物:`<backup-file>`
#### 数据库恢复
- 命令:`pg_restore ...`
- 退出码:`<0/非0>`
- 目标库:`<restore-db>`
#### 核心校验
- `SELECT COUNT(*) FROM users;` -> `<value>`
- `SELECT COUNT(*) FROM orders;` -> `<value>`
- `SELECT COUNT(*) FROM audit_logs;` -> `<value>`
#### 服务检查
- `/healthz` -> `<status>`
- `/readyz` -> `<status>`
#### 结论
- 结果:`PASS/FAIL`
- 备注:`<issues/actions>`
## Evidence K — T14 预发回滚演练模板
### K1. 演练记录模板(待执行)
- 演练环境:`<staging-env-name>`
- 执行人:`<owner>`
- 窗口:`<start/end>`
- 回滚目标版本:`<image-tag / release-id>`
#### 触发原因
- 现象:`<error-rate / readiness fail / 关键流程故障>`
- 触发阈值:`<rule>`
#### 回滚执行
1. 回滚 backend 到 `<version>`
2. 回滚 portal/superadmin 到 `<version>`
3. 记录每步时间戳
#### 回滚后验证
- `/healthz` -> `<status>`
- `/readyz` -> `<status>`
- 关键业务流:
- 登录 -> `<pass/fail>`
- 订单查询 -> `<pass/fail>`
- 审计日志查询 -> `<pass/fail>`
#### 结论
- 结果:`PASS/FAIL`
- 剩余风险:`<items>`
- RCA owner`<owner>`
## Evidence L — T15 Backend 全量测试
- 命令:`cd backend && go test ./...`
- 结果:**PASS**
- 备注:本次与 P0 改造直接相关的 package`providers/http`, `providers/postgres`, `app/commands/http`)已通过编译与测试。
## Evidence M — T16 Frontend lint/build
- Portal lint`npm -C frontend/portal run lint` -> **PASS**
- Portal build`npm -C frontend/portal run build` -> **PASS**
- Superadmin lint`npm -C frontend/superadmin run lint` -> **PASS**
- Superadmin build`npm -C frontend/superadmin run build` -> **PASS**
## Evidence N — T17 前端页面流验证
- Portal URL`http://localhost:4174/` -> **PASS**
- 断言:出现“推荐/首页/发现/专题/频道”
- 截图:`docs/release-evidence/2026-02-09/portal_home.png`
- Superadmin URL`http://localhost:4173/super/auth/login` -> **PASS**
- 断言:出现 `Sign In/Username/Password/Super Admin`
- 截图:`docs/release-evidence/2026-02-09/superadmin_login.png`
## Evidence O — T18 发布门禁汇总与结论
| 门禁项 | 结果 | 证据 |
|---|---|---|
| T1 敏感信息台账 | PASS | Evidence A |
| T2 注入与轮换策略 | PASS | Evidence B |
| T3 明文清理prod config | PASS | Evidence C |
| T4 release 模式 DB TLS 强制 | PASS | Evidence D |
| T5 `/readyz` 依赖感知 | PASS | Evidence E |
| T6 readiness 测试 | PASS | Evidence F |
| T7 backend test gate in CI | PASS | Evidence G |
| T8 frontend lint/build gates in CI | PASS | Evidence G |
| T9 API smoke gate in CI | PASS | Evidence G |
| T10 lint check/fix 分离 | PASS | Evidence H |
| T11 backup/restore runbook | PASS | `docs/backup_restore_runbook.md` |
| T12 rollback runbook | PASS | `docs/rollback_runbook.md` |
| T13 备份恢复演练模板 | PASS | Evidence J |
| T14 回滚演练模板 | PASS | Evidence K |
| T15 backend 全量测试 | PASS | Evidence L |
| T16 frontend lint/build 实测 | PASS | Evidence M |
| T17 前端页面流实测 | PASS | Evidence N |
### Go/No-Go
**Go满足当前计划门禁进入生产发布候选**
注意T13/T14 当前为“演练模板完成”,若要闭合“真实预发演练”要求,需在后续发布窗口执行并把真实演练结果补入本文件。
## Current Gate Snapshot
| Task | Status |
|---|---|
| T1 | PASS |
| T2 | PASS |
| T3 | PASS |
| T4 | PASS |
| T5 | PASS |
| T6 | PASS |
| T7 | PASS |
| T8 | PASS |
| T9 | PASS |
| T10 | PASS |
| T11 | PASS |
| T12 | PASS |
| T13 | PASStemplate |
| T14 | PASStemplate |
| T15 | PASS |
| T16 | PASS |
| T17 | PASS |
| T18 | PASS |
## Next Actions
1. 执行 T19归档本阶段 plan 并清空 `docs/plan.md`
2. 在下一发布窗口补录真实预发演练结果T13/T14 实测)。