diff --git a/src/koru/init_host_environment.py b/src/koru/init_host_environment.py index a0595c4d..23e30b04 100644 --- a/src/koru/init_host_environment.py +++ b/src/koru/init_host_environment.py @@ -6,7 +6,6 @@ """ -import grp import json import os import shutil @@ -16,6 +15,11 @@ from pathlib import Path from typing import Any +if sys.platform != "win32": + import grp as _grp +else: + _grp = None # type: ignore[assignment] + from koru.ide_runtime import build_host_setup_report from koru.runtime import runtime_dir @@ -69,7 +73,7 @@ def _uinput_snapshot() -> dict[str, Any]: except OSError as exc: return {"present": True, "stat_error": str(exc)} try: - group_name = grp.getgrgid(st.st_gid).gr_name + group_name = _grp.getgrgid(st.st_gid).gr_name if _grp is not None else str(st.st_gid) except (KeyError, OSError): group_name = str(st.st_gid) return { diff --git a/tests/test_init.py b/tests/test_init.py index 310c2d02..eef0dba0 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -26,7 +26,8 @@ refresh_init_agent_lane, resolve_project_agent_lane, ) -from koru.init_host_environment import _parse_os_release_line +import koru.init_host_environment as _ihe_mod +from koru.init_host_environment import _parse_os_release_line, _uinput_snapshot from koru.policy import load_policy from koru.runtime import planfile_dir, runtime_dir @@ -42,6 +43,23 @@ def test_parse_os_release_line(self) -> None: self.assertIsNone(_parse_os_release_line("MALFORMED")) self.assertIsNone(_parse_os_release_line("=missing-key")) + def test_grp_sentinel_matches_platform(self) -> None: + """_grp must be None on Windows and the real grp module elsewhere.""" + import sys + + if sys.platform == "win32": + self.assertIsNone(_ihe_mod._grp) + else: + import grp + + self.assertIs(_ihe_mod._grp, grp) + + def test_uinput_snapshot_absent_device(self) -> None: + """_uinput_snapshot returns present=False when /dev/uinput does not exist.""" + result = _uinput_snapshot() + # On CI / Windows / macOS /dev/uinput is absent; the function must not raise. + self.assertIn("present", result) + def _detach_ci_env() -> dict[str, str]: """Remove CI markers so IDE folder detection is deterministic in tests."""