import hashlib import io import json import zipfile from pathlib import Path import pytest from app.registry_service import RegistryService, RegistryValidationError def minimal_xlsx(marker: str = "v1") -> bytes: buffer = io.BytesIO() with zipfile.ZipFile(buffer, "w") as archive: archive.writestr("[Content_Types].xml", "") archive.writestr("xl/workbook.xml", f"{marker}") return buffer.getvalue() def make_legacy_config(root: Path) -> None: names = { "Windows_Checklist.xlsx": "windows_config.json", "CentOS_Checklist_NEW.xlsx": "centos_config_new.json", "RHEL_Checklist_NEW.xlsx": "rhel_config_new.json", "Ubuntu_Checklist_NEW.xlsx": "ubuntu_config_new.json", "Oracle_Linux_Checklist.xlsx": "oracle_linux_config.json", } for checklist, rules in names.items(): (root / checklist).write_bytes(minimal_xlsx(checklist)) (root / rules).write_text('{"rules": []}', encoding="utf-8") def test_seed_migrates_five_operating_system_profiles_and_aliases(tmp_path): make_legacy_config(tmp_path) service = RegistryService(tmp_path / "registry", legacy_config_root=tmp_path) registry = service.seed_legacy_profiles() assert len(registry["categories"]) == 1 assert len(registry["categories"][0]["components"]) == 5 assert service.resolve(os_type="redhat")["profile"]["id"] == "rhel-baseline" resolved = service.resolve(os_type="windows") assert resolved["version"]["active"] is True assert Path(resolved["checklist_path"]).is_file() def test_create_version_validates_payloads_and_records_sha256(tmp_path): make_legacy_config(tmp_path) service = RegistryService(tmp_path / "registry", legacy_config_root=tmp_path) service.seed_legacy_profiles() checklist = minimal_xlsx("v2") rules = b'{"rules": [{"id": "A"}]}' version = service.create_version("ubuntu-baseline", "2.0", checklist, rules) assert version["checksums"]["checklist"] == hashlib.sha256(checklist).hexdigest() assert json.loads(Path(service.root / version["artifacts"]["rules"]).read_text())["rules"][0]["id"] == "A" with pytest.raises(RegistryValidationError): service.create_version("ubuntu-baseline", "bad", b"not xlsx", rules) def test_activation_and_rollback_are_versioned_and_persistent(tmp_path): make_legacy_config(tmp_path) service = RegistryService(tmp_path / "registry", legacy_config_root=tmp_path) service.seed_legacy_profiles() service.create_version("centos-baseline", "2.0", minimal_xlsx("v2"), b'{"rules": []}') service.activate_version("centos-baseline", "2.0") assert service.resolve(profile_id="centos-baseline")["version"]["version"] == "2.0" service.rollback("centos-baseline") assert service.resolve(profile_id="centos-baseline")["version"]["version"] == "legacy-1" def test_rejects_bad_ids_duplicates_and_checksum_tampering(tmp_path): make_legacy_config(tmp_path) service = RegistryService(tmp_path / "registry", legacy_config_root=tmp_path) service.seed_legacy_profiles() with pytest.raises(RegistryValidationError): service.create_category("../escape", "Escape") with pytest.raises(RegistryValidationError): service.create_component("operating-systems", "windows", "Duplicate") resolved = service.resolve(os_type="ubuntu") Path(resolved["checklist_path"]).write_bytes(b"tampered") with pytest.raises(RegistryValidationError, match="checksum"): service.resolve(os_type="ubuntu")