From 7397ec30cd39299486434f1483896daeacf8f1ac Mon Sep 17 00:00:00 2001 From: PTah Date: Sun, 21 Jun 2026 20:49:01 +1000 Subject: [PATCH] fix(winrm): resolve System32 path for cmd test on minimal PATH (0.20.25) WinRM run_cmd(hostname) failed on hosts where System32 is not in PATH. --- backend/app/services/winrm_connect.py | 24 +++++++++++++++++++++++- backend/app/version.py | 2 +- backend/tests/test_health.py | 4 ++-- backend/tests/test_winrm_connect.py | 8 ++++++++ frontend/package.json | 4 ++-- frontend/src/version.ts | 2 +- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/backend/app/services/winrm_connect.py b/backend/app/services/winrm_connect.py index 52836e3..80feb68 100644 --- a/backend/app/services/winrm_connect.py +++ b/backend/app/services/winrm_connect.py @@ -211,6 +211,28 @@ def _finalize_winrm_run( ) +_SYSTEM32_CMDS = { + "hostname": "hostname.exe", + "qwinsta": "qwinsta.exe", + "logoff": "logoff.exe", +} + + +def _resolve_winrm_cmd(remote_cmd: str) -> str: + """WinRM cmd shell may have minimal PATH — use explicit System32 for built-ins.""" + text = remote_cmd.strip() + if not text: + return text + parts = text.split(None, 1) + name = parts[0].lower() + rest = parts[1] if len(parts) > 1 else "" + exe = _SYSTEM32_CMDS.get(name) + if exe: + suffix = f" {rest}" if rest else "" + return f"%SystemRoot%\\System32\\{exe}{suffix}" + return text + + def run_winrm_ps( *, target: str, @@ -269,7 +291,7 @@ def run_winrm_cmd( target = target.strip() try: session, winrm = _winrm_session(target, user, password, timeout_sec=timeout_sec) - result = session.run_cmd(remote_cmd) + result = session.run_cmd(_resolve_winrm_cmd(remote_cmd)) except winrm.exceptions.WinRMTransportError as exc: detail = str(exc) hint = "" diff --git a/backend/app/version.py b/backend/app/version.py index 789d830..5b0e255 100644 --- a/backend/app/version.py +++ b/backend/app/version.py @@ -1,5 +1,5 @@ """Единый источник версии SAC (API, health, логи, OpenAPI).""" APP_NAME = "Security Alert Center" -APP_VERSION = "0.20.24" +APP_VERSION = "0.20.25" APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}" diff --git a/backend/tests/test_health.py b/backend/tests/test_health.py index 5b65cf4..e305aa6 100644 --- a/backend/tests/test_health.py +++ b/backend/tests/test_health.py @@ -4,6 +4,6 @@ from app.version import APP_NAME, APP_VERSION, APP_VERSION_LABEL def test_version_constants(): - assert APP_VERSION == "0.20.22" + assert APP_VERSION == "0.20.25" assert APP_NAME == "Security Alert Center" - assert APP_VERSION_LABEL == "Security Alert Center v.0.20.22" + assert APP_VERSION_LABEL == "Security Alert Center v.0.20.25" diff --git a/backend/tests/test_winrm_connect.py b/backend/tests/test_winrm_connect.py index 778a628..a6ae234 100644 --- a/backend/tests/test_winrm_connect.py +++ b/backend/tests/test_winrm_connect.py @@ -95,6 +95,14 @@ def test_rdp_bundle_zip_roundtrip(tmp_path: Path, monkeypatch): assert get_rdp_bundle_zip(token) == zip_bytes +def test_resolve_winrm_cmd_uses_system32_for_builtins(): + from app.services.winrm_connect import _resolve_winrm_cmd + + assert _resolve_winrm_cmd("hostname") == "%SystemRoot%\\System32\\hostname.exe" + assert _resolve_winrm_cmd("qwinsta") == "%SystemRoot%\\System32\\qwinsta.exe" + assert _resolve_winrm_cmd("logoff 2 /v") == "%SystemRoot%\\System32\\logoff.exe 2 /v" + + def test_run_winrm_rdp_monitor_update_downloads_bundle_from_sac(tmp_path: Path): repo = tmp_path / "repo" repo.mkdir() diff --git a/frontend/package.json b/frontend/package.json index 6ee3e93..5239301 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ -{ +{ "name": "sac-ui", "private": true, - "version": "0.11.2", + "version": "0.11.3", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/version.ts b/frontend/src/version.ts index b1997aa..02349b5 100644 --- a/frontend/src/version.ts +++ b/frontend/src/version.ts @@ -1,4 +1,4 @@ /** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */ export const APP_NAME = "Security Alert Center"; -export const APP_VERSION = "0.20.24"; +export const APP_VERSION = "0.20.25"; export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;