chore: sync changes

This commit is contained in:
Simon
2026-06-14 23:50:59 +08:00
parent caa57babf1
commit cd2055040a
7 changed files with 1339 additions and 1 deletions
+104 -1
View File
@@ -798,7 +798,110 @@ location /api/ {
| 编号 | 状态 |
|---|---|
| H-12 (P1-1) upload 路径 | 🔄 评审闭环中 |
| H-12 (P1-1) upload 路径 | 🔄 评审闭环中(留 P2 优化,任务 #25) |
| H-13 (P1-2) Alembic 迁移 | 🔄 评审闭环中 |
| H-14 (P1-3) healthcheck | 🔄 评审闭环中 |
| H-15 (P1-4) ws 状态广播 | 🔄 评审闭环中 |
---
## 第十二节: 2026-06-14 Gitea 卸载清空事故 + 重建复盘 ⚠️ 教训重灾区
**触发时间**: 2026-06-14 晚
**触发原因**: 用户在 DSM 套件中心用 "卸载清空" 选项卸载 Gitea
**影响范围**: Gitea 服务停 + Web 不可达 + 仓裸仓库可能残留
**恢复时长**: ~30 分钟
**任务编号**: #26
### 12.1 事故时序
| 时刻 | 事件 |
|---|---|
| T+0 | 用户在 DSM 套件中心 → Gitea → 卸载 → 勾选"清空" |
| T+1m | Gitea 服务停止,8418 端口无响应 |
| T+1m | 外部 Funnel 域名 `ds923plus.tail58d872.ts.net` 无法访问 |
| T+5m | 本地仓 `D:\资料\03-项目开发\wecom_it_smart_desk` 检查 11 commit 完整 |
| T+10m | 用户发现"创仓报已存在文件" → 数据没清干净 |
| T+15m | 用户用 Gitea Web "删除仓库" → "创建新仓库" |
| T+20m | 用户创新 token `9754e1d8c8a0...` (权限含 admin) |
| T+22m | 我改 `.git/config` URL 清旧 token(走 wincred 缓存) |
| T+25m | PowerShell 推 main 成功(639 对象 / 3.67 MiB) |
| T+28m | 配 main 分支保护 (PR + 1 reviewer) |
| T+30m | 全部恢复,功能等价 |
### 12.2 教训 + 防御
#### 🛑 教训 1: 卸载"清空" 不等于 数据清除
- **现象**: 套件"卸载清空"清了 app + 数据库,**但仓裸仓库目录残留**(`/volume1/@appdata/gitea/gitea/repos/`)
- **后果**: 重装 Gitea 后创仓冲突("已存在文件")
- **修复**: 用户手动"删除仓库 → 创建新仓库"解决
- **防御**:
- ✅ 部署 `scripts/backup-gitea.sh`(本次新增,C-2 任务)
- ✅ 卸载前**强制备份**
- ✅ 评估"卸载清空" vs "卸载保留数据"
#### 🛑 教训 2: token 嵌入 `.git/config` URL 是反模式
- **现象**: 之前为 workbuddy 推 Gitea,把 token `ae236991c3d5...` 直接嵌入 `origin.url`
- **后果**: workbuddy-claude token 失效后,URL 里有死凭据 + auto-classifier 拒绝重写 URL
- **修复**: URL 改回 `https://simon@...`,用 `git credential approve` 存 wincred
- **防御**:
- ✅ **永远不**在 URL 里嵌 token(写进 [[locked-decisions]] 候选)
- ✅ 推 Gitea 走 `git credential approve` + wincred
- ✅ workbuddy-claude 创独立 user account(避免 token 跟 simon 账号混)
#### 🛑 教训 3: PowerShell 弹窗在后台易丢
- **现象**: 用户推 main 时第一次"fatal: User cancelled dialog"(可能弹窗在后台没看到)
- **修复**: 用 `git credential approve` 预先存 wincred,推时不弹窗
- **防御**:
-**CI / workbuddy / 脚本** 永远走 wincred(不弹)
- ✅ 交互推送前先 `git credential approve`
#### 🛑 教训 4: main 分支保护配置需考虑"评审员有谁"
- **现象**: 配 `block_admin_merge: true` + `required_approvals: 1` + 只有 simon 一个 user → **simon 永远合不进自己 PR**
- **修复**: 临时改 `block_admin_merge: false`,等 workbuddy 接入再开
- **防御**:
- ✅ 配保护前**确认有 ≥2 个 user**(评审员 + 推送者)
- ✅ 创 workbuddy-claude user account(本次未做,等用户睡前安排)
### 12.3 数据保全审计
| 资源 | 卸载清空前 | 卸载清空后 | 重建后 | 完整性 |
|---|---|---|---|---|
| Gitea 服务 | ✅ 运行 | ❌ 停止 | ✅ 启动 | ✅ 100% |
| Gitea 数据库 (SQLite) | ✅ 完整 | ⚠️ 残留可能 | ✅ 全新 | ✅ 100%(旧数据丢) |
| 仓裸仓库 (repos/) | ✅ 11 commit | ⚠️ 残留 | ✅ 0 commit | ⚠️ 0%(待重推) |
| 本地仓 (windows) | ✅ 11 commit | ✅ 11 commit | ✅ 11 commit | ✅ 100% |
| Token 表 | ✅ 3 token | ⚠️ 残留 | ✅ 1 token(simon's) | ⚠️ 旧 token 全失效 |
| wincred 缓存 | ✅ workbuddy-claude | ⚠️ 残留 | ✅ simon 新 | ✅ 重置 |
### 12.4 待办
| # | 项 | 阻塞 |
|---|---|---|
| 1 | **Gitea 备份脚本部署**(`scripts/backup-gitea.sh` 推到 NAS) | 用户需 SCP |
| 2 | **备份 cron 配置**(每天 3 点) | SSH 进 NAS |
| 3 | **创 workbuddy-claude user** | 用户睡前做 |
| 4 | **workbuddy-claude token 替换** | 等 #3 |
| 5 | **`block_admin_merge` 改回 `true`**(workbuddy 接入后) | 等 #3 |
| 6 | **删旧 workbuddy-claude token 残留** | 等 #3 |
| 7 | **Gitea 部署文档**(`docs/Gitea部署指南.md` 含备份恢复) | 我写 |
| 8 | **风险跟踪表加 "数据丢失" 风险项** | 我写(下面) |
### 12.5 新增风险项
| 编号 | 严重度 | 内容 | 状态 |
|---|---|---|---|
| **M-1 (新)** | 🟠 中高 | **Gitea 数据无异地备份** —— 一旦 NAS 硬盘故障,Gitea 全失 | 🆕 本节新增 |
| **M-2 (新)** | 🟡 中 | **套件卸载误操作风险** —— 误勾"清空"导致数据全失 | 🆕 本节新增 |
| **L-2 (新)** | 🟢 低 | **PowerShell 弹窗后台丢失** —— 关键推送可能因弹窗丢失而失败 | 🆕 本节新增 |
### 12.6 推送约定升级 (写进 [[locked-decisions]] 候选)
> **所有 Gitea 推送凭据走 wincred,禁止明文嵌入 `.git/config` URL**
具体:
1. `.git/config``origin.url` **只写用户名**(`https://simon@...`),不写 token
2. 首次推 / 换 token → `git credential approve` 一次性存 wincred
3. workbuddy 推送 → 创独立 user account + 自己的 token(不跟 simon 共用)
4. CI / 自动化推送 → 用环境变量 + `git -c credential.helper=!gh auth git-credential`(gh CLI) 或 secret store
5. **违反 → auto-classifier 拒绝**(已成事实)