"""Synthetic tests for the WAPT package; no Windows registry is accessed.""" import importlib.util import json import os from pathlib import Path import sys import tempfile import types import unittest from unittest import mock ROOT = Path(__file__).resolve().parents[1] REGISTRY = {} WRITES = [] DELETES = [] HKLM = 'synthetic-HKLM' class RegistryHandle: def __init__(self, root, path): self.address = (root, path) def __enter__(self): return self.address def __exit__(self, *args): return False def registry_set(root, path, name, value, type=None): REGISTRY.setdefault((root, path), {})[name] = value WRITES.append((root, path, name, value, type)) def _load_setup_module(): helpers = types.ModuleType('setuphelpers') helpers.HKEY_LOCAL_MACHINE = HKLM helpers.KEY_ALL_ACCESS = 0xF003F helpers.REG_DWORD = 4 helpers.makepath = lambda *parts: os.path.join(*(str(part) for part in parts)) helpers.programdata = lambda: tempfile.gettempdir() helpers.mkdirs = lambda path: os.makedirs(path, exist_ok=True) helpers.isfile = os.path.isfile helpers.remove_file = lambda path: os.remove(path) if os.path.exists(path) else None helpers.json_write_file = lambda path, data, **kwargs: Path(path).write_text( json.dumps(data, **kwargs), encoding='utf-8') helpers.json_load_file = lambda path: json.loads(Path(path).read_text(encoding='utf-8')) helpers.reg_key_exists = lambda root, path: (root, path) in REGISTRY helpers.reg_value_exists = lambda root, path, name: name in REGISTRY.get((root, path), {}) helpers.reg_openkey_noredir = lambda root, path, **kwargs: RegistryHandle(root, path) helpers.reg_getvalue = lambda key, name, default=None: REGISTRY.get(key, {}).get(name, default) helpers.registry_set = registry_set def delete_value(key, name): DELETES.append((key[0], key[1], name)) REGISTRY.get(key, {}).pop(name, None) helpers.reg_delvalue = delete_value with mock.patch.dict(sys.modules, {'setuphelpers': helpers}): spec = importlib.util.spec_from_file_location('hardening_setup', ROOT / 'setup.py') module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module setup = _load_setup_module() class HardeningSetupTests(unittest.TestCase): def setUp(self): REGISTRY.clear() WRITES.clear() DELETES.clear() self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.state_dir = Path(self.temp.name) / 'Comitari' / 'HardeningSafe' self.state_file = self.state_dir / 'original-values.json' self.programdata_patch = mock.patch.object(setup, 'programdata', lambda: self.temp.name) self.programdata_patch.start() self.addCleanup(self.programdata_patch.stop) def _seed(self, setting, value): address = (HKLM, setup._registry_path(setting['Path'])) REGISTRY.setdefault(address, {})[setting['Name']] = value def test_install_saves_originals_once_before_applying_dwords(self): setting = setup.SETTINGS[0] self._seed(setting, 0) setup.install() state = json.loads(self.state_file.read_text(encoding='utf-8')) self.assertEqual(len(state), 5) self.assertEqual(state[0]['Value'], 0) self.assertTrue(state[0]['Exists']) self.assertEqual(state[0]['Target'], 1) self.assertEqual(len(WRITES), 5) self.assertTrue(all(write[4] == setup.REG_DWORD for write in WRITES)) self._seed(setting, 7) setup.install() state_again = json.loads(self.state_file.read_text(encoding='utf-8')) self.assertEqual(state_again[0]['Value'], 0) def test_audit_is_read_only_and_reports_noncompliance(self): setup.install() self.assertEqual(setup.audit(), 'OK') before = list(WRITES) self._seed(setup.SETTINGS[1], 0) self.assertEqual(setup.audit(), 'WARNING') self.assertEqual(WRITES, before) def test_audit_read_error_is_not_reported_as_healthy(self): with mock.patch.object(setup, 'reg_key_exists', side_effect=PermissionError): self.assertEqual(setup.audit(), 'WARNING') def test_uninstall_restores_owned_values_and_preserves_external_changes(self): existing = setup.SETTINGS[0] absent = setup.SETTINGS[1] externally_changed = setup.SETTINGS[2] self._seed(existing, 0) setup.install() self._seed(externally_changed, 77) setup.uninstall() self.assertEqual(REGISTRY[(HKLM, setup._registry_path(existing['Path']))][existing['Name']], 0) self.assertNotIn(absent['Name'], REGISTRY[(HKLM, setup._registry_path(absent['Path']))]) self.assertEqual(REGISTRY[(HKLM, setup._registry_path(externally_changed['Path']))] [externally_changed['Name']], 77) self.assertIn((HKLM, setup._registry_path(absent['Path']), absent['Name']), DELETES) self.assertTrue(self.state_file.is_file()) def test_uninstall_without_baseline_refuses_changes(self): with self.assertRaisesRegex(RuntimeError, 'No saved baseline'): setup.uninstall() self.assertEqual(WRITES, []) self.assertEqual(DELETES, []) def test_invalid_baseline_refuses_all_registry_changes(self): self.state_dir.mkdir(parents=True) self.state_file.write_text(json.dumps([{'Path': 'HKLM:\\SOFTWARE\\Elsewhere', 'Name': 'Synthetic', 'Exists': False, 'Value': None, 'Target': 1}]), encoding='utf-8') with self.assertRaisesRegex(RuntimeError, 'incomplete'): setup.uninstall() self.assertEqual(WRITES, []) self.assertEqual(DELETES, []) def test_failure_to_persist_baseline_prevents_registry_modification(self): with mock.patch.object(setup, 'json_write_file', side_effect=OSError('synthetic disk error')): with self.assertRaises(OSError): setup.install() self.assertEqual(WRITES, []) def test_no_powershell_or_child_process_dependency_remains(self): source = (ROOT / 'setup.py').read_text(encoding='utf-8').lower() self.assertNotIn('subprocess', source) self.assertNotIn('powershell.exe', source) self.assertNotIn('hardening.ps1', source) if __name__ == '__main__': unittest.main()