ADR-086: Telegram 通知卡片 UI 清洗規範 - _parse_debate_summary() 設計決定與各 TYPE 欄位清洗規則 - TYPE-3 鍵盤重構:批准/拒絕永遠第一行 - 技術債:_parse_debate_summary 提升模組層級(P1-1) ADR-087: AutoApprove 安全強化 — kubectl 強制執行閘門 - 條件 1d 設計:_raw_action 語意 + NO_EXECUTABLE_ACTION reason - Solver Nemo 格式 kubectl 驗證 - 降級指令改為真實 kubectl 唯讀調查 - min_trust_score=0 保留理由記錄(TrustEngine 記憶體持久化技術債) - P0-2 風險記錄:kubectl exec 未加入 _DESTRUCTIVE_PATTERNS 2026-04-17 ogt + Claude Sonnet 4.6(亞太): Session 技術債清理 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
4.6 KiB
Markdown
119 lines
4.6 KiB
Markdown
# ADR-087: AutoApprove 安全強化 — kubectl 強制執行閘門
|
||
|
||
**狀態**: 已接受
|
||
**日期**: 2026-04-17
|
||
**作者**: ogt + Claude Sonnet 4.6
|
||
**關聯**: ADR-070(全自動 AIOps 閉環)、ADR-082(多 Agent 協作)
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
Phase 2 多 Agent 協作(ADR-082)Solver Agent 透過 OpenClaw 的 openclaw_nemo provider 產出修復方案時,有兩條路徑:
|
||
|
||
1. **標準格式**:`{"candidates": [{"action": "kubectl rollout restart ...", ...}]}`
|
||
2. **Nemo 格式**:`{"action_title": "重啟 Crash Looping Pod", "confidence": 0.85}`
|
||
|
||
Nemo 格式的 `action_title` 是自然語言描述,不是可執行的 kubectl 指令。
|
||
|
||
### 問題一:auto_approve 誤放行自然語言 action
|
||
|
||
原有條件:
|
||
- 條件 1c:`action` 為空 → 拒絕
|
||
- 條件 1d(無):未驗證 action 是否可執行
|
||
|
||
結果:Solver Nemo 路徑輸出「重啟 Crash Looping Pod」→ 條件 1c 通過(非空)→ 自動批准 → `kubectl_command` 欄位為空 → 實際無法執行 → incident 卡在 INVESTIGATING 狀態。
|
||
|
||
### 問題二:Solver 降級動作為自然語言
|
||
|
||
`_default_action_for_category()` 回傳:
|
||
- `"restart_pod"`、`"check_disk_usage"` 等非 kubectl 字串
|
||
|
||
這些字串通過條件 1c(非空),但無法被執行層使用。
|
||
|
||
---
|
||
|
||
## 決策
|
||
|
||
### 1. 條件 1d:kubectl 格式強制閘
|
||
|
||
位置:`auto_approve.py:evaluate()`,在條件 1c 之後、條件 2 之前。
|
||
|
||
```python
|
||
# 條件 1d: 自然語言描述不可自動執行
|
||
_raw_action = proposal_data.get("action", "") or "" # 原始值,不 fallback
|
||
_kubectl_cmd = proposal_data.get("kubectl_command", "") or ""
|
||
_has_kubectl = "kubectl" in _raw_action.lower() or "kubectl" in _kubectl_cmd.lower()
|
||
if not _has_kubectl:
|
||
return self._reject(
|
||
reason=AutoApproveReason.NO_EXECUTABLE_ACTION,
|
||
detail=f"Action '{_raw_action[:60]}' is natural language — no kubectl command",
|
||
...
|
||
)
|
||
```
|
||
|
||
**設計要點**:
|
||
- 使用 `proposal_data.get("action", "")` 原始值(非 line 232 已 fallback 的 `action` 變數),避免 fallback 語意混淆(Code Review P0-1)
|
||
- 新增 `AutoApproveReason.NO_EXECUTABLE_ACTION` enum 值,與 `NO_PLAYBOOK`(無匹配 Playbook)語意分離,防止污染 KM 飛輪學習資料分類(Code Review P1-2)
|
||
|
||
### 2. Solver Nemo 格式:kubectl 驗證
|
||
|
||
位置:`solver_agent.py:_extract_candidates()`
|
||
|
||
```python
|
||
if "action_title" in parsed and "candidates" not in parsed:
|
||
action_title = str(parsed.get("action_title", ""))
|
||
if "kubectl" not in action_title.lower():
|
||
return [] # → 觸發 _degraded_plan,輸出真實 kubectl 調查指令
|
||
```
|
||
|
||
### 3. 降級指令改為真實 kubectl
|
||
|
||
`_default_action_for_category()` 改為按類別回傳唯讀調查指令:
|
||
|
||
| Category | 降級指令 |
|
||
|----------|---------|
|
||
| pod/kube/crash | `kubectl get pods -n awoooi-prod -o wide` |
|
||
| disk/storage/pvc | `kubectl exec -n awoooi-prod deployment/postgresql -- df -h` |
|
||
| cpu/load | `kubectl top pods -n awoooi-prod --sort-by=cpu` |
|
||
| memory/oom | `kubectl top pods -n awoooi-prod --sort-by=memory` |
|
||
| network/connect | `kubectl get services -n awoooi-prod` |
|
||
| default | `kubectl get pods -n awoooi-prod` |
|
||
|
||
**設計原則**:降級指令均為唯讀調查操作,無副作用,blast_radius=20(低)。
|
||
|
||
---
|
||
|
||
## min_trust_score 設計決定
|
||
|
||
`min_trust_score: int = 0` 保持不變。
|
||
|
||
**理由**:TrustEngine 資料儲存於記憶體(`_trust_records` dict),Pod 重啟後歸零。若將門檻提高至 0.8,每次 Pod 重啟後所有動作都無法自動執行,直到累積足夠歷史記錄。這在生產環境中不可接受。
|
||
|
||
**正確方向**:將 TrustEngine 持久化至 PostgreSQL(已列為 Phase 3.5 技術債)。
|
||
|
||
---
|
||
|
||
## 後果
|
||
|
||
- 自然語言 action 不再通過 auto_approve,強制走 TYPE-3 人工審核
|
||
- Solver 降級路徑輸出真實 kubectl 調查指令,可被 auto_approve 正確評估
|
||
- `NO_EXECUTABLE_ACTION` reason 與 `NO_PLAYBOOK` 區分,KM 飛輪學習資料分類正確
|
||
|
||
---
|
||
|
||
## 已知風險 (P0-2 — 下次 Security Review)
|
||
|
||
`kubectl exec` 指令(降級路徑中的 disk 類別)被允許通過條件 1d,但 `kubectl exec` 可以在容器內執行任意命令。目前降級指令固定為 `df -h`(唯讀),但若未來 LLM 輸出包含 `kubectl exec` 的高風險變體,現有 `_DESTRUCTIVE_PATTERNS` 不包含 `exec` 關鍵字,可能漏過。
|
||
|
||
**建議**:下次 Security Review 時評估是否將 `kubectl exec` 加入 `_DESTRUCTIVE_PATTERNS` 或獨立 allow-list。
|
||
|
||
---
|
||
|
||
## 相關 Commits
|
||
|
||
| Commit | 說明 |
|
||
|--------|------|
|
||
| `93205ce` | P1 kubectl gate + P2 Nemo path 強制 |
|
||
| `fb225c5` | Code Review P0-1 action fallback + P1-2 NO_EXECUTABLE_ACTION enum |
|