fix: skip invalid/unresolvable SSH targets before connect (0.11.2)

Do not use human display_name as SSH host; skip short names that do not resolve on SAC (ubabuba -> IPv4 only).
This commit is contained in:
PTah
2026-06-20 00:39:29 +10:00
parent 2e839e0b16
commit 6fea8262fb
5 changed files with 75 additions and 6 deletions
+42 -2
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import re
import socket
from dataclasses import dataclass
@@ -9,6 +10,7 @@ from app.models import Host
SSH_MONITOR_UPDATE_SCRIPT = "/opt/scripts/update_ssh_monitor.sh"
SSH_OUTPUT_MAX_LEN = 12_000
_IPV4_RE = re.compile(r"^\d{1,3}(?:\.\d{1,3}){3}$")
class LinuxAdminNotConfiguredError(Exception):
@@ -39,6 +41,32 @@ def is_linux_host(host: Host) -> bool:
return (host.product or "").strip() == "ssh-monitor"
def _is_ipv4(value: str) -> bool:
return bool(_IPV4_RE.match(value.strip()))
def _looks_like_ssh_hostname(value: str) -> bool:
"""Короткое имя или FQDN; не человекочитаемый display_name вроде «Ubabuba Kalina (10.10.36.9)»."""
text = value.strip()
if not text or " " in text or "(" in text or ")" in text:
return False
if _is_ipv4(text):
return True
if len(text) > 253:
return False
return all(ch.isalnum() or ch in ".-_" for ch in text)
def _ssh_name_resolves(name: str) -> bool:
if _is_ipv4(name):
return True
try:
socket.getaddrinfo(name.strip(), 22, type=socket.SOCK_STREAM)
return True
except OSError:
return False
def iter_ssh_targets(host: Host) -> list[str]:
if not is_linux_host(host):
raise HostNotLinuxError("Host is not Linux")
@@ -50,14 +78,26 @@ def iter_ssh_targets(host: Host) -> list[str]:
text = (value or "").strip()
if not text or text.casefold() in seen:
return
if not _looks_like_ssh_hostname(text):
return
if not _ssh_name_resolves(text):
return
seen.add(text.casefold())
ordered.append(text)
add(host.hostname)
add(host.display_name)
inventory = host.inventory if isinstance(host.inventory, dict) else {}
computer_name = inventory.get("computer_name")
if isinstance(computer_name, str):
add(computer_name)
if host.display_name and _looks_like_ssh_hostname(host.display_name):
add(host.display_name)
add(host.ipv4)
if not ordered:
raise HostTargetMissingError("Host has no hostname or IPv4 for SSH")
raise HostTargetMissingError("Host has no resolvable hostname or IPv4 for SSH")
return ordered
+1 -1
View File
@@ -1,5 +1,5 @@
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
APP_NAME = "Security Alert Center"
APP_VERSION = "0.11.1"
APP_VERSION = "0.11.2"
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"