feat: RDG qwinsta/logoff via WinRM on client workstation (0.11.6)

SAC resolves internal_ip to a registered Windows host and runs qwinsta/logoff synchronously over WinRM instead of queueing commands to the gateway agent.
This commit is contained in:
2026-06-20 15:36:12 +10:00
parent 2eb06acb5b
commit 75f4c475df
13 changed files with 612 additions and 174 deletions
+55
View File
@@ -0,0 +1,55 @@
"""Tests for RDG client workstation lookup."""
from datetime import datetime, timezone
from app.models import Host
from app.services.rdg_client_host import find_windows_host_by_ipv4, resolve_client_workstation
def test_find_windows_host_by_ipv4(db_session):
host = Host(
hostname="Andrisonova-PC",
os_family="windows",
product="rdp-login-monitor",
ipv4="192.168.160.113",
)
db_session.add(host)
db_session.commit()
found = find_windows_host_by_ipv4(db_session, "192.168.160.113")
assert found is not None
assert found.hostname == "Andrisonova-PC"
def test_resolve_client_workstation_from_event(db_session):
from app.models import Event
ws = Host(
hostname="Andrisonova-PC",
os_family="windows",
product="rdp-login-monitor",
ipv4="192.168.160.113",
)
gw = Host(hostname="K6A-DC3", os_family="windows", product="rdp-login-monitor", ipv4="192.168.160.40")
db_session.add_all([ws, gw])
db_session.commit()
event = Event(
event_id="ev-1",
host_id=gw.id,
occurred_at=datetime(2026, 6, 20, tzinfo=timezone.utc),
received_at=datetime(2026, 6, 20, tzinfo=timezone.utc),
category="auth",
type="rdg.connection.disconnected",
severity="info",
title="303",
summary="",
payload={},
details={"user": r"B26\user", "internal_ip": "192.168.160.113", "rdg_flap": True},
)
db_session.add(event)
db_session.commit()
client = resolve_client_workstation(db_session, event)
assert client.id == ws.id
assert client.hostname == "Andrisonova-PC"