Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32b238cf86 | ||
|
|
168e4dde19 | ||
|
|
2d41338897 |
@@ -339,6 +339,8 @@
|
||||
| `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-beta-safety-net-20261014.md` | — | **内测安全网**:每日备份 + 恢复演练、探活告警、本地错误汇总、日志轮转、按 requestId 查日志。**等发布通路单合入、#58 合入后开工** | 待前置 | — |
|
||||
| `TASK-beta-safety-net-fix-20261015.md` | — | **#75 产品选 A**:授权新增每日备份定时工作流,但每日备份不得改写 `recovery-baseline.env`(恢复点仍只手动创建);另记 `daily-backup-latest.env` | 待领取 | `codex/beta-safety-net-20261014` |
|
||||
| `TASK-beta-safety-net-fix2-20261015.md` | — | **#75 修复单 2**:生产侧全过;飞书测试 env 文件权限 0644 在 Linux 上失败(会挡发布门禁);新测试不在 quick 门禁;磁盘 ≥70% 后备份静默停摆;监控脚本缺 sudo 与 env 文件 | 待领取 | `codex/beta-safety-net-20261014` |
|
||||
| `TASK-beta-capacity-20261014.md` | — | **内测容量**:按用户限流、重计算短排队与对话重试、兑换码当邀请码、staging 10/20 并发压测。**等 #58 合入后开工,压测等 #57 合入** | 待前置 | — |
|
||||
| `TASK-beta-capacity-fix-20261015.md` | — | **#76 第 1 次打回**:`a54f75e5` 限流与短排队逻辑通过;源码文本断言未跟改、插入新测试使隐私白名单行号错位 | 待领取 | `codex/beta-capacity-20261014` |
|
||||
| `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` 为准) |
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# TASK · 内测安全网修复单(issue #75,产品选 A)
|
||||
|
||||
- 日期:2026-10-15
|
||||
- 原任务书:`docs/tasks/TASK-beta-safety-net-20261014.md`
|
||||
- 被验 SHA:`53d8df257ddef8918034acef36df0b4b7daade2c`(`codex/beta-safety-net-20261014`)
|
||||
- 执行方:Grok,同一分支续做(先 merge 最新 `origin/staging`,不改写已推历史)
|
||||
- **决策记录**:产品负责人 2026-10-15 在 issue #75 选 **A**——**授权新增定时工作流 `.gitea/workflows/backup-production-daily.yml`**(每天北京时间 04:00 自动连生产做加密备份),但**每日备份不得改动「当前恢复点」记录**。恢复点仍只由产品负责人手动点「Create production recovery」创建。仍不改已有四个生产工作流的语义;仍不点任何生产按钮。
|
||||
|
||||
## 1. 问题
|
||||
|
||||
`deploy/run-production-recovery.sh` 无论由谁调用,结尾都会无条件写 `$DEPLOY_PATH/.state/recovery-baseline.env`(`RECOVERY_REFERENCE`、`RECOVERY_SHA256`、`RECOVERY_FORMAT=2` 等)。发布、迁移、回退都读这份文件当「当前恢复点」。每日备份复用这个脚本,于是每天 04:00 都会把它换成当天的自动备份——产品负责人上线前手动建的恢复点,隔一夜就被替换。
|
||||
|
||||
## 2. 修法要求
|
||||
|
||||
1. **每日备份不写 `recovery-baseline.env`**:`RECOVERY_BASENAME_PREFIX=production-daily` 时(或新增一个明确的模式参数,二选一,写进 PROGRESS),脚本仍完整执行「导出 → 加密 → 还原核对(含 #74 的表权限、列权限、属主三项比对)→ 写 `*-restore-verify.json`」,但**跳过写 `recovery-baseline.env`**,并在输出里打印 `baseline_updated=false`。手动恢复点路径行为不变,打印 `baseline_updated=true`。
|
||||
2. 每日备份的核对结果单独记录:在 `$DEPLOY_PATH/.state/` 下另写一个 `daily-backup-latest.env`(只含文件名、sha256、校验时间、格式版本,不含数据、不含密钥),供告警 / 运维查看;发布、迁移、回退工作流**不得**读取它。
|
||||
3. 合同测试(`tests/test_beta_safety_net.py` 或 `frontend/tests/staging-backend-workflows.test.ts`):
|
||||
- 每日模式下 `recovery-baseline.env` 不被创建或修改(用临时目录 + 假 docker 跑脚本,断言文件 mtime / 内容不变);
|
||||
- 手动模式下仍会写,且含 `RECOVERY_FORMAT=2`;
|
||||
- 三个读取恢复点的生产工作流 / 脚本不引用 `daily-backup-latest.env`。
|
||||
4. runbook 与 `deploy/README.md`:写清「每日备份只做存档与核对,不是发布用的恢复点;上线前仍要手动点 Create production recovery」。
|
||||
5. 清理脚本只删 `production-daily-*` 前缀的文件(原任务书已要求)——再确认不会删 `production-pre-migration-*` 手动恢复点。
|
||||
|
||||
## 3. 验收
|
||||
|
||||
- Claude 会对本单做完整验收(上一轮在发现定时工作流后就停下等拍板,其余部分尚未逐行验):逐行看新工作流与各脚本、跑 `tests/test_beta_safety_net.py`、Python 全量、前端全量、`docker compose config`。
|
||||
- 交回前本机跑:`python -m pytest tests/test_beta_safety_net.py tests/test_repo_privacy_markers.py -q`、`npx tsx --test tests/runtime-sources-no-test-imports.test.ts tests/staging-backend-workflows.test.ts`。
|
||||
|
||||
## 4. 让步顺序
|
||||
|
||||
无。
|
||||
@@ -0,0 +1,45 @@
|
||||
# TASK · 内测安全网修复单 2(issue #75)
|
||||
|
||||
- 日期:2026-10-15
|
||||
- 前序:`TASK-beta-safety-net-20261014.md`、`TASK-beta-safety-net-fix-20261015.md`(产品选 A)
|
||||
- 被验 SHA:`5c0d895391b5d0806c98de669a2e9cdcd61e3335`(`codex/beta-safety-net-20261014`)
|
||||
- 执行方:Grok,同一分支续做(先 merge 最新 `origin/staging`,不改写已推历史)
|
||||
- 红线不变:仍不改已有四个生产工作流与 staging 工作流、`gated-paths.txt`、`is-docs-only-range.sh`;不点生产按钮
|
||||
|
||||
## 1. 验收结论:面向生产的部分全部过;一条阻断 + 三条要一起修
|
||||
|
||||
已确认成立:每日工作流只从 main 跑、与恢复点工作流同一把锁 / 同样的密钥处理、不回显密钥;每日模式**任何路径都不写** `recovery-baseline.env`(只有手动分支写),失败时什么状态都不写;`daily-backup-latest.env` 只有 4 个键;发布 / 迁移 / 回退不读它;手动恢复点(含 `RECOVERY_FORMAT=2` 与权限比对)不变;清理脚本只认 `^production-daily-\d{8}T\d{6}Z\.dump\.enc$` 的普通文件,碰不到 `production-pre-migration-*`;错误分类只外发校验过的 errorCode / 路由 / UUID,不发用户内容;compose 只加了 6 个服务一致的 `logging`。
|
||||
|
||||
### B1(阻断)· 测试在 Linux 上失败
|
||||
|
||||
`tests/test_beta_safety_net.py` 约 616–634 行 `test_feishu_payload_keeps_only_allowed_fields`:约 76–77 行用 `write_text` 写 `monitor.env`,默认权限 0644;`deploy/monitor/notify-feishu.sh` 约 18–23 行在 Linux 上拒绝非 0600 的环境文件 → 退出 1。macOS / Windows 上跳过了这项检查所以没发现。`release-quality-gate.yml` 在 Linux 上跑全树 pytest,提升 main 会被它挡住。
|
||||
- 修:测试里写完后 `os.chmod(env_file, 0o600)`。脚本里的检查是对的,不改。
|
||||
|
||||
### N1 · 新测试不进 staging 门禁
|
||||
|
||||
`scripts/run_quality_gate.py` 的 quick 清单(约 55–90 行)没有 `tests/test_beta_safety_net.py`,合同只在发布时才跑——B1 就是这样漏过去的。把它加进 quick 清单。
|
||||
|
||||
### N2 · 磁盘 ≥70% 后备份静默停摆
|
||||
|
||||
`run-production-recovery.sh` 约 149–153 行磁盘 ≥70% 拒绝;`backup-production-daily.yml` 约 145–146 行只在备份成功后才清理旧文件 → 一旦到 70%,旧文件永不清理、每天都失败;磁盘告警 80% 才响,也没人检查 `daily-backup-latest.env` 有多旧。
|
||||
- 修:清理放在备份**之前**(或 `if: always()`);`healthcheck-alert.sh` 增加「最近一次每日备份超过 36 小时」告警(读 `daily-backup-latest.env` 的 `verified_at`)。加测试。
|
||||
|
||||
### N3 · 两个监控脚本在生产主机上大概率跑不起来
|
||||
|
||||
`deploy/monitor/error-digest.sh` 约 54–59 行、`deploy/find-request-log.sh` 约 300–307 行直接调 `docker`,其它生产脚本与恢复演练都用 `sudo -n docker`;也没导出 `DATABASE_ENV_FILE`,`docker-compose.postgres.yml` 会回落到不存在的 `../.env.staging.database`,Compose 拒绝加载。错误汇总由 cron 每 5 分钟跑,会每次失败、什么都不发。
|
||||
- 修:统一 `sudo -n docker`,显式传入生产的 compose 文件与 env 文件路径(与 `run-production-deploy.sh` 同一写法);测试断言命令行形状。
|
||||
|
||||
## 2. 顺手修(不阻断,一并做)
|
||||
|
||||
- `notify-feishu.sh` 约 96–101 行:`curl` 加 `--fail`,并检查飞书返回体里的 `code == 0`;失败时不记成「已发送」。
|
||||
- `error-digest.sh`:同一类告警 30 分钟内不重复发。
|
||||
- `find-request-log.sh`:真实路径按时间戳排序(去掉 compose 前缀后再排),与 README 说法一致。
|
||||
|
||||
## 3. 验收标准
|
||||
|
||||
- Linux:`python3 -m pytest tests/test_beta_safety_net.py -q` 全绿;Claude 全量 pytest、前端全量无新增;`bash -n` 全过;quick 门禁包含新测试。
|
||||
- 交回前本机跑上面那条 pytest(Windows 上请用 WSL 或在测试里显式断言 0600 已生效)。
|
||||
|
||||
## 4. 让步顺序
|
||||
|
||||
B1、N1、N3 不可让;N2 的「过旧告警」可写理由后让;第 2 节可让。
|
||||
Reference in New Issue
Block a user