fix(backend): non-login SSH and strict loginctl parse, SSH retry (0.20.31)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-22 10:54:56 +10:00
parent a51a585b14
commit 54c1d96933
7 changed files with 246 additions and 43 deletions
+34 -3
View File
@@ -35,6 +35,21 @@ SESSION_EVENT_TYPES_LINUX = frozenset(
)
SESSION_EVENT_TYPES_WINDOWS = frozenset({"rdp.login.success"})
_LOGIND_SESSION_ID_RE = re.compile(r"^\d+$|^c\d+$", re.IGNORECASE)
_LOGIND_USER_RE = re.compile(r"^[a-z_][a-z0-9._-]*$", re.IGNORECASE)
_LOGIND_STATES = frozenset(
{
"active",
"online",
"closing",
"opening",
"degraded",
"lingering",
"preparing",
"unknown",
}
)
@dataclass(frozen=True)
class HostSessionRow:
@@ -78,14 +93,27 @@ def is_windows_host_event(event: Event) -> bool:
return host is not None and is_windows_host(host)
def _looks_like_loginctl_row(parts: list[str]) -> bool:
if len(parts) < 6:
return False
sid, uid, user, state = parts[0], parts[1], parts[2], parts[5].lower()
if not _LOGIND_SESSION_ID_RE.match(sid):
return False
if not uid.isdigit():
return False
if not _LOGIND_USER_RE.match(user):
return False
return state in _LOGIND_STATES
def parse_loginctl_sessions(stdout: str) -> list[HostSessionRow]:
rows: list[HostSessionRow] = []
for line in stdout.splitlines():
text = line.strip()
if not text:
if not text or text.startswith("SESSION"):
continue
parts = text.split()
if len(parts) < 3:
if not _looks_like_loginctl_row(parts):
continue
sid, user = parts[0], parts[2]
tty = parts[4] if len(parts) > 4 and parts[4] != "-" else None
@@ -143,7 +171,7 @@ def list_linux_sessions(host: Host, cfg: LinuxAdminConfig) -> tuple[list[HostSes
if not is_linux_host(host):
raise SshHostNotLinuxError("Host is not Linux")
targets = iter_ssh_targets(host)
cmd = "loginctl list-sessions --no-legend --no-pager 2>/dev/null || who -u"
cmd = "loginctl list-sessions --no-legend --no-pager"
last: SshCommandResult | None = None
for target in targets:
result = run_ssh_command(
@@ -154,6 +182,7 @@ def list_linux_sessions(host: Host, cfg: LinuxAdminConfig) -> tuple[list[HostSes
connect_timeout_sec=15,
command_timeout_sec=45,
need_root=True,
login_shell=False,
)
last = result
if result.ok and result.stdout.strip():
@@ -184,6 +213,7 @@ def terminate_linux_session(
connect_timeout_sec=15,
command_timeout_sec=45,
need_root=True,
login_shell=False,
)
last = result
if result.ok:
@@ -286,6 +316,7 @@ def _terminate_linux_user_sessions(host: Host, cfg: LinuxAdminConfig, user: str)
connect_timeout_sec=15,
command_timeout_sec=45,
need_root=True,
login_shell=False,
)
last = result
if result.ok: