diff --git a/docs/adr/ADR-013-aiops-autoheal.md b/docs/adr/ADR-013-aiops-autoheal.md index 53c08d9..878a5f6 100644 --- a/docs/adr/ADR-013-aiops-autoheal.md +++ b/docs/adr/ADR-013-aiops-autoheal.md @@ -30,7 +30,7 @@ Exception → Incident(DB) → PlayBook 匹配 → Auto-Heal 執行 → HealLog( | `services/auto_heal_service.py` | Service | 核心引擎(分類、匹配、執行、沉澱) | | `database/manager.py` | 修改 | 加入 `_init_autoheal_tables()` | | `scheduler.py` | 修改 | 三個核心任務植入 `handle_exception` | -| `requirements.txt` | 修改 | 加入 `paramiko` | +| `utils/ssh_helper.py` | Helper | 共用 CLI `ssh` 執行層,供 AutoHeal / AiderHeal 使用 | ### PlayBook 動作類型 @@ -60,7 +60,7 @@ Exception → Incident(DB) → PlayBook 匹配 → Auto-Heal 執行 → HealLog( ## 取捨 -**優先使用 paramiko** 而非 subprocess + CLI ssh,原因是在容器內環境控制更精準,且支援跳板機 ProxyJump。若 paramiko 未安裝則自動降級到 CLI ssh(向後相容)。 +2026-05-13 實作修訂:現行程式碼已標準化到 `utils/ssh_helper.py`,以 CLI `ssh` + `ProxyJump` 參數組裝執行,AutoHeal 與 AiderHeal 共用同一層;因此 `paramiko` 不再是 runtime 依賴。若未來要重新引入 Paramiko,必須同時補回 helper 實作、requirements 與回歸測試。 --- diff --git a/docs/memory/claude_inventory_validation_20260513.md b/docs/memory/claude_inventory_validation_20260513.md index 141487b..bbc63d2 100644 --- a/docs/memory/claude_inventory_validation_20260513.md +++ b/docs/memory/claude_inventory_validation_20260513.md @@ -45,6 +45,7 @@ - `aiops-core/requirements.txt` 已不存在,`aiops-core/README.md` 已標記此目錄只保留歷史 stub,不應安裝或部署。 - V2 提到的「死依賴」不可整批刪:`beautifulsoup4` 用於多個 crawler、`google-api-python-client` 用於 Google Drive、`google-generativeai` 用於 Gemini paths、`python-pptx` 用於 PPT generator、`matplotlib` 用於 Telegram/圖表/PPT。 - `tests/test_requirements_pinning.py` 已鎖住上述被 V2 誤列的 runtime dependencies:套件需留在 `requirements.txt`,且至少一個 runtime import 證據仍存在。 +- `paramiko` 已確認沒有 runtime import;ADR-013 現行實作改以 `utils/ssh_helper.py` 組 CLI `ssh`,因此已從 `requirements.txt` 移除並補測試防止依賴殘影回來。 - Telegram `momo:eig:` callback 已在 `routes/openclaw_bot_routes.py` 與 `services/telegram_bot_service.py` 實作並有 webhook 測試覆蓋,不是未實作缺口。 - Telegram `date_*` / `goal_*` 不是死 callback handler:按鈕先送 `await:*` 進入輸入等待狀態,使用者下一則文字才由 pending action 消費;`tests/test_openclaw_bot_menu_keyboards.py` 與 `tests/test_openclaw_bot_routes_webhook.py` 已覆蓋。 - `services/ai_automation_smoke_service.py` 不是死 service:`run_scheduler.py` 每日 09:10 掛 `run_ai_smoke_daily_summary_task()`,該 task 會呼叫 `send_smoke_daily_summary()`;`tests/test_ai_automation_smoke_service.py` 與 `tests/test_ai_automation_metrics.py` 已覆蓋。 diff --git a/requirements.txt b/requirements.txt index 5059a5f..78464ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,6 @@ lxml>=6.1.0 prometheus-client>=0.25.0 python-telegram-bot[job-queue]>=20.0 pgvector>=0.2 -paramiko>=5.0.0 # ADR-013: AIOps SSH 跳板修復 python-pptx>=1.0.2 # ADR-014: PPT 簡報系統 matplotlib>=3.9.4 # 圖表生成(日報/週報/月報) matplotlib-inline>=0.2.2 # Jupyter 相容層(可選) diff --git a/tests/test_requirements_pinning.py b/tests/test_requirements_pinning.py index 50f0af5..635f065 100644 --- a/tests/test_requirements_pinning.py +++ b/tests/test_requirements_pinning.py @@ -76,3 +76,13 @@ def test_audit_flagged_runtime_dependencies_have_import_evidence(): missing_evidence.append(package) assert missing_evidence == [] + + +def test_cli_ssh_helper_replaces_legacy_paramiko_dependency(): + requirements = _requirement_names() + helper_source = (ROOT / "utils" / "ssh_helper.py").read_text(encoding="utf-8") + + assert "paramiko" not in requirements + assert "subprocess.run" in helper_source + assert '"ssh"' in helper_source + assert "paramiko" not in helper_source