7.5 KiB
AiderHeal 110 主機部署 SOP(ADR-020)
解決 2026-05-03 發現的 AiderHeal 100% no-op 根因:110 主機上
AIDER_REPO_PATH(/home/wooo/ewoooc) 不存在,所有cd立刻失敗,|| true吞掉錯誤後整條 pipeline 走完卻 0 次 push。本 SOP 設定一次後永久生效,需統帥手動執行(牽涉 SSH key 部署 + Gitea push 權限驗證)。
前置確認
| # | 檢查項 | 命令 |
|---|---|---|
| 1 | 110 主機可達 | ssh wooo@192.168.0.110 hostname |
| 2 | 110 上是否已有 ~/.ssh/autoheal_id_ed25519 |
ssh wooo@192.168.0.110 'ls -la ~/.ssh/autoheal*' |
| 3 | 188 容器內 config/autoheal_id_ed25519 是否存在 |
ssh ollama@192.168.0.188 'ls -la /home/ollama/momo-pro-system/config/autoheal*' |
| 4 | Gitea 上該 ssh key 是否已加為 deploy key(write 權限) | Gitea → wooo/ewoooc → Settings → Deploy Keys |
若 #2 #3 都 OK 且 #4 已加 → 直接跳到「步驟 2 clone repo」
若 #2 缺 key → 走「步驟 1 部署 SSH Key」
若 #4 沒加 → 走「步驟 3 加 Gitea Deploy Key」
步驟 1:部署 SSH Key 到 110 主機
容器內已有的 key 同步到 110,作為 110 push 回 Gitea 的身份。
# 從 188 取出私鑰(container mount 點)
ssh ollama@192.168.0.188 'cat /home/ollama/momo-pro-system/config/autoheal_id_ed25519' \
| ssh wooo@192.168.0.110 'umask 077 && cat > ~/.ssh/autoheal_id_ed25519'
# 取公鑰
ssh ollama@192.168.0.188 'cat /home/ollama/momo-pro-system/config/autoheal_id_ed25519.pub' \
| ssh wooo@192.168.0.110 'cat > ~/.ssh/autoheal_id_ed25519.pub'
# 設權限
ssh wooo@192.168.0.110 'chmod 600 ~/.ssh/autoheal_id_ed25519 && chmod 644 ~/.ssh/autoheal_id_ed25519.pub'
# 在 ~/.ssh/config 加 host alias 讓 git 自動用此 key
ssh wooo@192.168.0.110 'cat >> ~/.ssh/config << "EOF"
Host gitea-autoheal
HostName 192.168.0.110
Port 3022
User git
IdentityFile ~/.ssh/autoheal_id_ed25519
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config'
Port 3022 確認:用
ssh wooo@192.168.0.110 'docker ps | grep gitea'看 Gitea SSH port,預設 3022 但可能不同。
步驟 2:在 110 上 clone repo 到 /home/wooo/ewoooc(直接 SSH clone)
注意:從一開始就用 SSH clone,避免 HTTP clone 在 private repo 卡帳密 prompt + 跟步驟 1 部署的 key 不關聯。先確認 Gitea SSH port(預設 3022 但可能被改):
ssh wooo@192.168.0.110 'docker ps --format "{{.Ports}}" | grep gitea'從輸出找到
0.0.0.0:NNN->22/tcp的 NNN 即為 Gitea SSH port。下方用 3022 為例,請依實況替換。
ssh wooo@192.168.0.110 << 'EOF'
set -e
cd ~
# 防呆:如果 ewoooc 已存在但不是 git repo(可能舊垃圾),先備份
if [ -d ewoooc ] && [ ! -d ewoooc/.git ]; then
mv ewoooc ewoooc.bak.$(date +%s)
fi
# 直接 SSH clone(複用步驟 1 部署的 key + ~/.ssh/config 的 gitea-autoheal alias)
if [ ! -d ewoooc/.git ]; then
git clone gitea-autoheal:wooo/ewoooc.git ewoooc
fi
cd ewoooc
# 設 git identity 讓 AiderHeal commit 有可識別作者
git config user.name "AiderHeal"
git config user.email "autoheal@wooo.work"
# 確認 remote 走 SSH(gitea-autoheal alias 自帶正確 port + key)
git remote -v
git log --oneline -3
EOF
驗證:應印出 origin gitea-autoheal:wooo/ewoooc.git(fetch+push 兩行)和最近 3 個 commit。
若 clone 失敗報
Permission denied (publickey):步驟 3 的 Gitea Deploy Key 還沒加或沒勾 write access,先回去處理步驟 3。
步驟 3:在 Gitea 加 Deploy Key(若 #4 沒加)
- 取公鑰:
ssh wooo@192.168.0.110 'cat ~/.ssh/autoheal_id_ed25519.pub' - Gitea Web UI:
- 開
http://192.168.0.110:3001/wooo/ewoooc/settings/keys - Add Deploy Key
- Title:
AiderHeal 110 host - Key: 貼上 #1 的公鑰
- 勾選
Allow write access(必要!否則只能 fetch 不能 push) - Add Key
- 開
步驟 4:端到端驗證
4a. 110 上手動測試 push 鏈
ssh wooo@192.168.0.110 << 'EOF'
cd ~/ewoooc
git fetch origin main
git status
EOF
預期:fetch 不報錯,status 顯示 Your branch is up to date。
4b. 從 188 容器測試 SSH 鏈(模擬 AiderHeal preflight)
早期版本曾用
docker exec ... bash -c "ssh ... \"...\""三層引號,內層雙引號會被中層吃掉,導致&& echo PREFLIGHT_OK變成本地 echo 而非 remote echo —— 永遠 false positive。改用 heredoc + 單引號嵌套保護:
ssh ollama@192.168.0.188 << 'OUTER'
docker exec momo-pro-system bash -c '
ssh -i /app/config/autoheal_id_ed25519 \
-o StrictHostKeyChecking=no \
wooo@192.168.0.110 "test -d /home/wooo/ewoooc/.git && echo PREFLIGHT_OK"
'
OUTER
預期輸出:PREFLIGHT_OK(從遠端 110 印出,非本地)。
驗證真假:故意把 path 寫錯一個字母,應該 0 輸出(不該印 PREFLIGHT_OK)。
4c. 觸發 AiderHeal pipeline 觀察
任意推一個會被 Hermes 找到 finding 的 commit(或統帥 push 一個下次自然有 finding 的 commit),等 2 分鐘後查:
# 看是否有 AiderHeal 簽名的新 commit
git fetch origin main && git log --pretty='%h | %an | %s' origin/main -5
預期:看到 author 是 AiderHeal 或 commit message 開頭 fix(autoheal): 的新 commit。
4d. 看容器 log
ssh ollama@192.168.0.188 'docker logs momo-pro-system --since 10m 2>&1 | grep -E "event=(heal_start|aider_exec|push_ok|preflight_failed|setup_failed)"'
預期:event=heal_start → event=aider_exec(停 10–60s)→ event=push_ok 連貫出現,不應看到 event=preflight_failed。
故障排除
| 症狀 | 可能原因 | 排查 |
|---|---|---|
event=preflight_failed |
110 上 ~/ewoooc 不存在 / 不是 git repo |
重跑步驟 2 |
event=setup_failed 顯示 Permission denied (publickey) |
Gitea deploy key 未加 / write 權限沒勾 | 檢查步驟 3 |
event=push_failed 顯示 remote: hook declined |
Gitea 設 protected branch | 在 Gitea 把 main 從 protected 移除(或加 deploy key 為例外) |
event=no_diff 但 aider 確實看到問題 |
aider 模型品質不佳(qwen2.5-coder:7b 太小) | 改 AIDER_MODEL env,例如 ollama/deepseek-coder-v2:16b;需 110 上有對應 model |
event=diff_too_large 連續發生 |
finding 牽涉檔案 > 50 行修改 | 調 AIDER_MAX_DIFF_LINES env,但建議保留 50 作 ADR-020 安全網 |
安全護欄回顧(ADR-020)
| L | 機制 | 觸發點 |
|---|---|---|
| L0 | preflight 路徑檢查 | aider_heal_executor.py:execute_code_fix 白名單通過後 |
| L1 | 檔案白名單 ^(services|routes|database)/(?:[a-zA-Z0-9_]+/)*[a-zA-Z0-9_]+\.py$,允許子目錄但不允許 tests/ |
ALLOWED_FILE_PATTERN |
| L2 | diff > 50 行拒絕 push | AIDER_MAX_DIFF_LINES |
| L3 | 每小時最多 5 次 CODE_FIX | _enforce_rate_limit |
| L4 | health check 失敗自動 git revert | _revert_last_commit |
| L5 | Telegram 通知(成功/失敗/回滾) | _notify_telegram → EventRouter |
主開關:CODE_REVIEW_AUTO_FIX_ENABLED=false(docker-compose env)即時切斷整條鏈。
完成後更新
- 110 上
~/ewoooc存在且git remote -v顯示走 SSH push - Gitea deploy key 已加,write access 勾選
- 步驟 4b 印出
PREFLIGHT_OK - 至少一次自然觸發 AiderHeal 後看到
fix(autoheal):commit - 通知 Claude 把 memory
feedback_code_review_autoheal.md的「待觀察」段刪掉,標記 AiderHeal 執行層也驗證完成