# Gitea Secret paste 完整性检查清单

## 为什么有这份清单

Gitea web UI 的 Secret 编辑弹窗在 paste 多行 secret（特别是 SSH private key / 证书 / 长 token）时，**实际值可能跟看到的不一致**：

- 中间某行被剪贴板换行符吃掉 → key 解析报 `error in libcrypto`
- 末尾没回车留空行 → openssh 拒绝最后一行
- 浏览器自动 trim 空白 → 关键 padding 丢失

症状传到下游会变成"CI step silent hang"（ssh `publickey` auth fail → 降级 `password` prompt → step 超时），日志几乎为零字节。一旦 secret 损坏，下游所有用此 secret 的 workflow 都会间歇性失败、定位极慢。

## 本地预校验（必做）

把 paste 候选先写到本地临时文件，**用 ssh-keygen 校验 fingerprint** 与原 key 一致后再贴到 Gitea：

```bash
# 1. 把要 paste 的内容（含 BEGIN/END 行 + 末尾空行）写本地临时文件
cat > /tmp/secret-check.txt << 'EOF'
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
EOF

# 2. 校验 fingerprint（应与本机 ssh-add -l 输出一致）
ssh-keygen -lf /tmp/secret-check.txt

# 3. 跟原 key fingerprint 比对
ssh-keygen -lf ~/.ssh/your_original_key
```

两个 fingerprint **完全相同**才能继续。任一字符串不同 → paste 损坏，重新 copy。

## Paste 操作清单

- [ ] 在本地临时文件用 `ssh-keygen -lf` 校验 fingerprint
- [ ] 用 `wc -l` 数行数：私钥首尾各一行 + payload 行（OpenSSH 64 列 base64）
- [ ] 在 Gitea Secret 编辑框 paste 整段
- [ ] **paste 后在最后一行 END 后按一次回车留一个空行**（OpenSSH 解析要求）
- [ ] 保存
- [ ] **立刻**触发一个最小 workflow（如 `workflow_dispatch` 一个只跑 `ssh -o BatchMode=yes <host> true` 的 job）验证 key 工作
- [ ] **不要**等到下次正常 PR 才发现 secret 坏了

## 删除 / 验证后清理

```bash
shred -u /tmp/secret-check.txt
```

不要把临时文件留着 — 私钥落盘超过几分钟就要当作泄漏处理。

## 如果 CI 报 publickey auth fail

按 #273 评论 5 "ssh hang 诊断 5 步 SOP" 走：

1. CI log size < 5 KB → step 还没启动 / 或 stdout 没流出
2. Runner 机 `ps -ef --forest | grep ssh` 看 ssh client 进程
3. Runner 机 `lsof -p <ssh_pid> -i` 看 socket state（`CLOSE_WAIT` = 对端已关）
4. 目标机 `/var/log/auth.log` grep runner IP 看 sshd negotiate 错误
5. 从另一台机器用同一 private key 手动复现，缩小问题到 client / server / 网络

## 关联

- 工单 [#273](http://43.130.59.228/FFAIWorkspace/workspace/issues/273) 评论 5 完整 saga
- `.learnings/2026-05-10-gitea-1.26-upgrade-and-act-runner-compat-saga.md`
- `docs/ops/02-gitea-config.md` Gitea 平台总入口
