fix(code-review): P0-1 action fallback 語意修正 + P1-2 reason enum + P2-2 secops 清洗
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 10m7s

Code Review 發現 (2026-04-17 首席架構師審查):

P0-1 auto_approve.py 條件 1d 語意修正:
- 原:用 `action` 變數(已 fallback = action or kubectl_command)做 kubectl 判斷
  → action="" + kubectl_command="kubectl get pods" → action="kubectl get pods" → 1d 通過
  → _kubectl_cmd 與 action 同值(重複判斷同一來源),掩蓋 action 本身是自然語言的情況
- 修:改用 proposal_data.get("action", "") 原始值(_raw_action)
  → 直接檢查 action 欄位本身,邏輯語意明確

P1-2 auto_approve.py NO_EXECUTABLE_ACTION 新增:
- 新增 AutoApproveReason.NO_EXECUTABLE_ACTION enum 值
- 條件 1d 改用此 reason(原 NO_PLAYBOOK 語意為「無匹配 Playbook」,不適用此場景)
- 避免污染 KM 飛輪學習資料的根因分類(ADR-068)

P2-2 decision_manager.py secops 分支:
- threat_behavior 改用 _parse_debate_summary → 取 diagnosis 欄位
- 與 BUG-A/BUG-C 修復一致,不再傾倒完整 debate_summary 前 150 字

ADR-082: Phase 2 多 Agent 協作
2026-04-17 ogt + Claude Sonnet 4.6(亞太): Code Review 後修正

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-17 15:18:54 +08:00
parent b80836329e
commit 1ae9e9f389
3 changed files with 152 additions and 5 deletions

View File

@@ -50,6 +50,7 @@ class AutoApproveReason(str, Enum):
CRITICAL_OPERATION = "critical_operation" # 關鍵操作
LOW_TRUST = "low_trust" # 信任不足
NO_PLAYBOOK = "no_playbook" # 無匹配 Playbook
NO_EXECUTABLE_ACTION = "no_executable_action" # action 為自然語言,無法執行
LOW_SUCCESS_RATE = "low_success_rate" # Playbook 成功率不足
INSUFFICIENT_HISTORY = "insufficient_history" # 執行歷史不足
@@ -294,13 +295,17 @@ class AutoApprovePolicy:
# 根因Solver 經 OpenClaw Nemo 路徑輸出「重啟 Crash Looping Pod」等自然語言
# action 非空 → 條件 1c 通過 → auto_approved=True
# 但 kubectl_command 為空 → 實際無法執行 → incident 卡在 investigating
# 修復:action 必須含 kubectl 關鍵字才可自動執行,否則降級人工審核
# 修復:直接讀 proposal_data["action"] 原始值(非 fallback 後的 action 變數)
# 避免「action 空 → fallback 成 kubectl_command → action 含 kubectl → 誤放行」
# Code Review 2026-04-17: P0-1 修正 action fallback 語意混淆
# P1-2 改用 NO_EXECUTABLE_ACTION避免污染 KM 飛輪學習資料)
_raw_action = proposal_data.get("action", "") or ""
_kubectl_cmd = proposal_data.get("kubectl_command", "") or ""
_has_kubectl = "kubectl" in action.lower() or "kubectl" in _kubectl_cmd.lower()
_has_kubectl = "kubectl" in _raw_action.lower() or "kubectl" in _kubectl_cmd.lower()
if not _has_kubectl:
return self._reject(
reason=AutoApproveReason.NO_PLAYBOOK,
detail=f"Action '{action[:60]}' is natural language — no kubectl command, requires human review",
reason=AutoApproveReason.NO_EXECUTABLE_ACTION,
detail=f"Action '{_raw_action[:60] or _kubectl_cmd[:60]}' is natural language — no kubectl command, requires human review",
risk_level=risk_level,
trust_score=trust_score,
confidence=confidence,

View File

@@ -381,7 +381,7 @@ async def _push_decision_to_telegram(
alertname=_alertname,
threat_level=_threat_level,
resource=target[:60],
threat_behavior=reasoning[:150] if reasoning else description[:150],
threat_behavior=_smt(_parse_debate_summary(reasoning).get("diagnosis") or reasoning, 150) if reasoning else description[:150],
)
elif _alert_category == "business":
# TYPE-6B業務/FinOps 資訊告警 — 發到 SRE 群組(無審核按鈕)(ADR-075 Step-5)