Files
Jyotisha/docs/tasks/TASK-release-path-production-fix-20261014.md
T

5.8 KiB
Raw Blame History

TASK · 发布通路修复单(issue #74,第 1 次打回)

  • 日期:2026-10-14
  • 原任务书:docs/tasks/TASK-release-path-production-20261014.md(产品负责人 2026-10-14 在 issue #74 再次确认授权修改四个生产工作流)
  • 被验 SHA:00e6efdbfa3d97b0aad764865321bc00fb1cee13(codex/release-path-production-20261014)
  • 执行方:Grok,同一分支续做(先 merge 最新 origin/staging,不改写已推历史)
  • 红线不变:仍只改原任务书授权的四个工作流;不改 staging 工作流、gated-paths.txt、is-docs-only-range.sh;不点任何生产按钮

1. 验收结论:发布规则本身成立,三处阻断首发

已确认成立(不需要改):正向路径要求 R 有精确 SHA 的 staging push 门禁、R 或 H 有手动发布门禁、main == staging、R..H 只含文档;变更前复核用的是 R 门禁产物里的 is-docs-only-range.sh 与 gated-paths.txt;staging 工作流零改动;AGENTS.md 只动了授权的 §2.4、§2.5、§2.7。

B1 · Python 测试在 Linux 上全红(会让发布门禁红)

tests/test_resolve_release_revision.py 第 13–14 行写死 PYTHON = ROOT/".venv"/"Scripts"/"python.exe" 和 D:\Program Files\Git\bin\bash.exe。Claude 在 Linux 全量 pytest:该文件 7 条里 6 条失败(python.exe: No such file or directory)。release-quality-gate.yml 跑全树 pytest,runbook 第 3 步会红。

  • 修:用 sys.executable;bash 用 shutil.which("bash"),Windows 再回落到 Git Bash。Linux 与 Windows 都要过。

B2 · 主机模式的迁移演练跑不通,且会在生产库上留下一份生产数据副本

deploy/rehearse-production-migrations.sh:

  • run_node_sql(约 88–137 行)在主机上跑 node + import pg,连 @postgres:5432(约 253 行)——这个主机名只在 Docker 网络里有;生产主机按规矩不装 node / node_modules、不构建。计数步骤失败退出 1,清理步骤(约 142 行)也用同一个函数,同样失败只打警告 → rehearse_<时间戳> 库连同恢复出来的生产数据留在生产 PostgreSQL 上,与 runbook「演练库会删掉」矛盾。
  • 恢复用 --no-owner --no-acl,对象归 POSTGRES_USER,而迁移以 role=schema_owner 执行,ALTER 可能报 "must be owner";ACL 没恢复,第 316–325 行的权限检查看到的不是生产真实授权,「退出 4 = BUG-1063 授权缺失」不可靠。
  • 修:
    1. 主机模式下所有 SQL 都走 docker compose exec / docker run 进 postgres 或 web 容器执行(与第 271 行 --entrypoint node 一致),不依赖主机 node。
    2. 清理放 trap,并且清理失败要非零退出并大字提示「演练库未删除,请手动 DROP DATABASE rehearse_xxx」,不得只打警告。
    3. 恢复后先把对象属主改成 schema_owner(或以 restore 后的属主执行迁移),并说明权限检查的口径;若做不到「看到生产真实授权」,就把「退出 4」的含义在脚本头和 runbook 里改成如实描述。
    4. 本地模式的连接串拒绝带 ? 查询参数(?database= / ?host= 能覆盖库名守卫)。
    5. runbook 第 5 步列的通过标准(归档会话前后数、自镜像前后数、NOTICE 计数)脚本并不打印:要么脚本打印,要么 runbook 删掉,二者必须一致。
  • 验收:新增或扩展 tests/test_rehearse_production_migrations.py:主机模式不调用主机 node(用假 docker 记录调用);清理失败时退出码非零;带查询参数的 URL 被拒。

B3 · runbook 的失败回退走不通

  • deploy-production.yml 回滚分支(约 126–137 行)仍要求 main 头 H 有一次 staging push 门禁成功记录;而本单要解决的正是「H 只多了文档、没有门禁记录」的情况——此时 first 返回 null、jq -e 失败,runbook 约 107 行依赖的回滚会被拒。
  • 修:回滚分支对 controller 的门禁查找改用与正向相同的规则(resolve-release-revision.sh 解析出的 R),或在 H 无门禁时用 R 的门禁产物;回滚的「目标 SHA 必须在已审 main 历史里」等原有检查不放宽。加合同测试锁住。
  • runbook 约 106 行「从恢复点整库恢复」没有给出工具和步骤:写清用哪个脚本 / 命令、需要哪个文件(recovery_reference 结尾就是备份文件名)、恢复后怎么核对。

2. 非阻断但这轮一并改

  1. frontend/tests/staging-backend-workflows.test.ts:迁移与恢复两条用例把工作流里的门禁断言换成了检查脚本文本,没有任何断言锁住三个工作流里的 CHECK_RELEASE_GATE=true——删掉它会让正向路径失去发布门禁要求而测试仍绿。补上这三处断言(三栏写明)。
  2. frontend/src/modules/identity/config.ts 约 101 行用原始字符串比 AUTH_USER_ORIGIN,https://jyotisha.chat/(带斜杠)会漏过「生产拒绝测试验证码」。改为与 readOrigin 规范化后的值比较,并加一条带斜杠的测试。
  3. resolve-release-revision.sh 的正向判定用的是 H 自己检出里的 gated-paths.txt;虽然变更前有 R 产物复核兜底,但 recovery 工作流没有复核。请在 recovery 的判定里同样用 R 产物(或在 PROGRESS 写明为何恢复点可以接受)。

3. 验收标准

  • Linux:python3 -m pytest tests/test_resolve_release_revision.py tests/test_rehearse_production_migrations.py -q 全绿;Claude 全量 pytest 与 staging 基线逐条比对无新增;前端全量 npm test 无新增。
  • bash -n 全部脚本通过。
  • runbook 每一步与工作流 / 脚本输出逐条一致(Claude 逐条对照)。
  • 仍未点任何生产按钮。

4. 让步顺序

B1、B2、B3 都不可让;第 2 节第 1、2 条不可让,第 3 条可写理由不改。