fix(release): keep owners and grants in production recovery points

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-14 21:01:52 +08:00
co-authored by Grok (agent loop)
parent d13250f40a
commit 09906cdccc
13 changed files with 381 additions and 145 deletions
@@ -0,0 +1,41 @@
# PROGRESS · 发布通路修复单 2(2026-10-14)
- 分支:`codex/release-path-production-20261014`
- issue:#74。先并入当时的 `origin/staging`(合并提交 `d13250f4`),没有改写已推历史。
- 产品选 A:恢复点带上属主和权限,并在本机真实 PostgreSQL 17 上演练。没有点生产按钮。
- 新记录:BUG-1350。不是 BUG-203 的复发。BUG-203 是恢复点锁文件的所有权。
## 做了什么
1. 恢复点导出只保留自定义格式。还原后比较表权限、列权限、表属主,不一致就不写恢复点记录。记录里写 `RECOVERY_FORMAT=2`。创建恢复点的按钮输出仍是原来的 7 行,那个工作流文件没有改。
2. 部署和迁移在允许回退时,读主机上的恢复点记录。版本低于 2 就拒绝,并提示先做新的恢复点。正向部署不要求这份文件。
3. 演练不再改类型属主。迁移前后比较授权,收回了原有授权就退出 1。人物表列级读取权缺了就退出 4。新的一次性库补上迁移角色的连接和建对象权限,因为整库导出带不走数据库本身的权限。
4. 手册的整库还原去掉丢掉属主和授权的参数。还原后补回迁移角色在这个库上的连接和建对象权限。读网站账号之前先设登录身份,否则行级安全会把行藏起来。
## 和任务书不完全一样的地方
- 空库必须留着 `public`。备份是去改它的属主,不是重新创建它。先删掉会停在「schema public 不存在」。
- 数归档会话时,列还不存在不能写在同一条查询里,数据库会在解析阶段就拒绝。先看列在不在,再计数。没有这一列时仍输出 `absent`。
- 本机演练用的是 fixture 里的 PostgreSQL 17,不是生产主机上的那一份备份。生产恢复脚本要求生产目录,不能在这台电脑上原样执行。导出参数、加密方式和还原核对是按脚本重放的。
## 自测
| 命令 | 结果 |
| --- | --- |
| `bash -n` 四个生产脚本 | 退出码 0 |
| `tests/test_rehearse_production_migrations.py` | 6 通过,退出码 0 |
| `tests/test_resolve_release_revision.py` 与上一份一起 | 13 通过,退出码 0(授权那条断言是在这之后加上的,演练测试又单独跑过) |
| `tsc --noEmit -p frontend` | 退出码 0 |
| `npm run lint --prefix frontend` | 退出码 0,0 error,123 条原有 warning |
| `frontend/tests/staging-backend-workflows.test.ts` | 44 条里 39 通过、5 失败、0 取消。失败是这台 Windows 机器的环境:python 退出码 9009、两条缺 rsync、临时目录改权限被拒绝、纯文档范围脚本退出码 49。生产部署、恢复点、生产迁移合同(第 32、34、35、36、37 条)通过 |
| 本机 PostgreSQL 17 演练 | 见 `docs/testing/production-migration-rehearsal-20261014.md`。权限三样一致,`rehearsal_ok=1`,退出码 0,演练库 0 个残留,网站角色读到 1 行 |
## 预检
`scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` 退出码 1。远端仓库可见,适配器正常。碎片扫描 90 秒超时,聚焦测试 45 秒超时。这是这台电脑上预检超时的老问题,没有改台账,也不写成预检通过。
## 没做
- 没有点生产按钮,没有连生产主机。
- 没有推 `staging` 或 `main`。
- 没有改测试环境工作流、门禁路径清单、纯文档判断脚本。
+1 -1
View File
@@ -336,7 +336,7 @@
| `TASK-beta-main-path-fix-20261014.md` | `PROGRESS-beta-main-path-20261014.md` | **#73 第 1 次打回**:`fca62fda` 内容通过;与 #63 删除的旧报告视图有代码冲突,接受删除即可 | 待验收 | `codex/beta-main-path-20261014` |
| `TASK-release-path-production-20261014.md` | `PROGRESS-release-path-production-20261014.md` | **发布通路 + 生产首发**:产品 10-14 授权改生产工作流(发布 SHA = 最近门禁成功提交 + 其后纯文档);63 个迁移清单与演练脚本、首发 runbook;生产拒绝测试验证码。Grok 不 dispatch 生产工作流 | 第 2 次打回后续修 | `codex/release-path-production-20261014`(BUG-1348、BUG-1349) |
| `TASK-release-path-production-fix-20261014.md` | `PROGRESS-release-path-production-fix-20261014.md` | **#74 第 1 次打回**:发布规则成立;测试写死 Windows 路径(Linux 全红)、主机演练依赖主机 node 且会留下生产数据副本、docs-only 头时回滚被拒;另补 CHECK_RELEASE_GATE 断言与 OTP 守卫规范化 | 已修,第 2 次仍未过 | `codex/release-path-production-20261014` |
| `TASK-release-path-production-fix2-20261014.md` | `PROGRESS-release-path-production-fix2-20261014.md` | **#74 修复单 2(产品选 A)**:恢复点要带属主与权限,旧格式不得回退;演练按备份里的授权比对,并在真实 PostgreSQL 17 上跑通一次 | 执行中 | `codex/release-path-production-20261014` |
| `TASK-release-path-production-fix2-20261014.md` | `PROGRESS-release-path-production-fix2-20261014.md` | **#74 修复单 2(产品选 A)**:恢复点要带属主与权限,旧格式不得回退;演练按备份里的授权比对,并在真实 PostgreSQL 17 上跑通一次 | 待验收 | `codex/release-path-production-20261014` |
| `TASK-beta-safety-net-20261014.md` | — | **内测安全网**:每日备份 + 恢复演练、探活告警、本地错误汇总、日志轮转、按 requestId 查日志。**等发布通路单合入、#58 合入后开工** | 待前置 | — |
| `TASK-beta-capacity-20261014.md` | — | **内测容量**:按用户限流、重计算短排队与对话重试、兑换码当邀请码、staging 10/20 并发压测。**等 #58 合入后开工,压测等 #57 合入** | 待前置 | — |
| `TASK-special-lagnas-native-20261008.md` | `PROGRESS-special-lagnas-native-20261008.md` | **特殊上升点原生计算(线上缺陷)**:sync6 U6 运行时调 PyJHora,生产镜像没有 PyJHora → staging 上 Hora/Ghati/Sree/Indu/Pranapada 全 blocked;原生实现、PyJHora 只作冻结对照、快速门禁止运行时 import jhora;最先做 | 已验收(已部署 staging `795b8845`,BUG-1273) | `codex/special-lagnas-native-20261008`(未上线;部署以 `/api/health` 为准) |