fix(flywheel): unblock action safety and Claude fallback
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 9m45s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 9m45s
This commit is contained in:
@@ -33,6 +33,7 @@ from src.core.config import settings
|
||||
from src.core.redis_client import get_redis
|
||||
from src.models.incident import Incident
|
||||
from src.models.playbook import SymptomPattern
|
||||
from src.services.action_parser import parse_kubectl_action
|
||||
from src.services.auto_approve import get_auto_approve_policy
|
||||
from src.services.openclaw import get_openclaw
|
||||
from src.services.playbook_service import get_playbook_service
|
||||
@@ -52,19 +53,6 @@ def _fire_and_forget(coro) -> asyncio.Task:
|
||||
task.add_done_callback(_background_tasks.discard)
|
||||
return task
|
||||
|
||||
# P1 fix 2026-04-11: kubectl action dangerous char whitelist
|
||||
# 2026-04-25 ogt + Claude Sonnet 4.6: 補允許 K8s resource type keyword
|
||||
# LLM 常輸出 "kubectl rollout restart deployment clickhouse" (含 deployment 關鍵字)
|
||||
# 原 pattern 只允許 verb 後直接接名稱,導致 _action_safe=False → 全部被攔截 → 飛輪 0
|
||||
# 修法:在名稱前加可選的 resource type group (deployment/pod/service/...)
|
||||
import re as _re_module
|
||||
_ALLOWED_KUBECTL_PATTERN = _re_module.compile(
|
||||
r"^kubectl\s+(rollout restart|rollout undo|scale|delete pod|get|describe|logs)"
|
||||
r"\s+(?:(?:deployment|pod|pods|service|services|statefulset|sts|daemonset|ds|svc|configmap|cm)\s+)?"
|
||||
r"[a-zA-Z0-9_./-]+(\s+(-n|--namespace)\s+[a-zA-Z0-9_-]+)?$",
|
||||
_re_module.ASCII,
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Phase 31 (ADR-067 2026-04-10): Log 異常摘要 — NemoTron deepseek-r1:14b
|
||||
@@ -1944,15 +1932,17 @@ class DecisionManager:
|
||||
# 另外:若 target 等於 alertname,代表 LLM 把告警名稱填入 deployment_name,也拒絕
|
||||
_alertname = incident.signals[0].labels.get("alertname", "") if incident.signals else ""
|
||||
_target_is_alertname = bool(_alertname and _target == _alertname)
|
||||
# P1 fix 2026-04-11: kubectl action 危險字元白名單 — 防止 && || ; > | 注入
|
||||
_action_safe = bool(_ALLOWED_KUBECTL_PATTERN.match(action.strip()))
|
||||
# SPF-2: structured kubectl parser replaces the old single-regex guard.
|
||||
_action_parse = parse_kubectl_action(action.strip())
|
||||
_action_safe = _action_parse.ok
|
||||
if "unknown" in action or _re.search(r"[<{][^>}]+[>}]", action) or _target_is_alertname or not _action_safe:
|
||||
logger.warning(
|
||||
"auto_execute_blocked_unresolved_placeholder",
|
||||
incident_id=incident.incident_id,
|
||||
action=action,
|
||||
target=_target,
|
||||
reason="action 含未解析的 placeholder、unknown、target==alertname、或危險字元,拒絕執行",
|
||||
parser_reason=_action_parse.reason,
|
||||
reason="action 含未解析的 placeholder、unknown、target==alertname、或未通過 kubectl action parser,拒絕執行",
|
||||
)
|
||||
# Safety guard 攔截 → 降級為人工審核,而非「修復失敗」
|
||||
# 2026-04-11 Claude Sonnet 4.6: 不發 ❌ 失敗訊息,改發人工審核卡片
|
||||
|
||||
Reference in New Issue
Block a user