fix(asset_scanner): Gap 1 修正 — 嚴格 IPv4 判斷 + 清理重複 host asset
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Audit 1 發現 bug:
原 code: if host_ip.replace('.', '').isdigit() → IP 判斷
導致 labels.host='125' (短名) 被誤當 IP → 建 host/125 (錯)
同時 blackbox-icmp instance='192.168.0.112' 無 port → split 失敗 → 漏建
新增 _is_valid_ipv4(s):
嚴格 4 段 + 每段 0-255 整數
避免短名 '125' / hostname 'cadvisor-110' / 超界 '256' 誤判
_collect_prometheus_targets 流程改:
1. 先從 instance 抽 (IP:port 形式 或純 IP)
instance_host = instance.split(':')[0] if ':' in instance else instance
2. 用 _is_valid_ipv4 嚴格驗證
3. labels.host 不再當 fallback (短名不可靠)
DB 清理 (266 筆):
- 10 asset_relationship 指向短名 host
- 140 asset_coverage_snapshot 7 維 × 4 短名 host
- 112 asset_compliance_snapshot 7 維 × 4 短名 × 幾 run
- 4 asset_inventory 短名 host (host/110 / 112 / 125 / 188)
預期下次 scan (1h):
- host/192.168.0.112 + host/192.168.0.121 補進 (原漏,blackbox-icmp 無 port)
- 不再有短名 host asset
6/6 單元測試通過:
_is_valid_ipv4('192.168.0.125')=True
_is_valid_ipv4('125')=False ← 關鍵修復
_is_valid_ipv4('cadvisor-110')=False
_is_valid_ipv4('192.168.0.256')=False (超界)
_is_valid_ipv4('')=False
_is_valid_ipv4('192.168.1')=False (3 段)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -491,6 +491,28 @@ async def _collect_all_k8s_assets() -> tuple[list[dict[str, Any]], list[dict[str
|
||||
return assets, relationships
|
||||
|
||||
|
||||
def _is_valid_ipv4(s: str) -> bool:
|
||||
"""嚴格 IPv4 判斷: 4 段 + 每段 0-255 整數.
|
||||
|
||||
避免 '125' (短名) / 'cadvisor-110' (hostname) 被誤判為 IP.
|
||||
"""
|
||||
if not s or s.count(".") != 3:
|
||||
return False
|
||||
parts = s.split(".")
|
||||
if len(parts) != 4:
|
||||
return False
|
||||
for p in parts:
|
||||
if not p or not p.isdigit():
|
||||
return False
|
||||
try:
|
||||
n = int(p)
|
||||
except ValueError:
|
||||
return False
|
||||
if n < 0 or n > 255:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def _collect_prometheus_targets() -> tuple[list[dict[str, Any]], list[dict[str, str]]]:
|
||||
"""
|
||||
從 Prometheus /api/v1/targets 發現所有被監控的 host-install service + 主機.
|
||||
@@ -523,12 +545,14 @@ async def _collect_prometheus_targets() -> tuple[list[dict[str, Any]], list[dict
|
||||
if not instance or not job:
|
||||
continue
|
||||
|
||||
# 解析 host IP — 優先 labels.host,其次 instance 的 IP 前綴
|
||||
host_ip = labels.get("host") or ""
|
||||
if not host_ip and ":" in instance:
|
||||
host_ip = instance.split(":")[0]
|
||||
# 只處理看起來是 IP 的 host (避免 'alertmanager' / 'argocd-server' 等 K8s DNS)
|
||||
if not host_ip or not host_ip.replace(".", "").isdigit():
|
||||
# 2026-04-19 Audit 1 修: 嚴格 IPv4 判斷
|
||||
# 原 code bug: labels.host="125" (短名) 被 "125".replace(".","").isdigit()=True 誤判 IP
|
||||
# 修: 優先從 instance 抽 IP (IP:port 形式或純 IP 無 port),嚴格 4 段 0-255 驗證
|
||||
# labels.host 可能是短名不可靠,只信 instance
|
||||
instance_host = instance.split(":")[0] if ":" in instance else instance
|
||||
host_ip = instance_host if _is_valid_ipv4(instance_host) else ""
|
||||
|
||||
if not host_ip:
|
||||
# target instance 不是 IP 形式 → 建 third_party_service asset 但 host 留空
|
||||
asset_key = f"prometheus_target/{job}/{instance}"
|
||||
assets.append({
|
||||
|
||||
Reference in New Issue
Block a user