import json import logging import os import sys from pathlib import Path from typing import Callable, Optional, TypeVar import aiofiles T = TypeVar("T") logger = logging.getLogger(__name__) PROTECTED_KEYS = [ "APPNAME", "LOG_LEVEL", "PATH_EXCLUSION_CONST", "MIN_FILES_FOR_PATH", "VT_THREAT_TOLERANCE", "POLICY_MAP_ENF_AUD" ] _protected_config = {} async def get_system_config_path() -> Path: bundled_dir = Path(getattr(sys, '_MEIPASS', '')) bundled_path = bundled_dir / "system_config.json" if bundled_path.exists(): return bundled_path return Path(__file__).parent.parent / "system_config.json" async def load_protected_config() -> dict: global _protected_config try: config_path = await get_system_config_path() async with aiofiles.open(config_path, "r") as f: content = await f.read() system_config = json.loads(content) except FileNotFoundError: logging.warning("⚠️ system_config.json not found. Using built-in defaults.") system_config = { "APPNAME": "AirlockTools", "PATH_EXCLUSION_CONST": 4, "MIN_FILES_FOR_PATH": 4, "VT_THREAT_TOLERANCE": 4, "POLICY_MAP_ENF_AUD": { "enforced_id": "audit_id" } } _protected_config = {key: system_config[key] for key in PROTECTED_KEYS if key in system_config} return _protected_config async def get_protected_value(key: str, cast_type: Callable[[str], T] = str, default: Optional[T] = None) -> Optional[T]: value = _protected_config.get(key) if value is None: logging.warning(f"Protected config key '{key}' not found.") return default try: if isinstance(value, str): value = value.strip("'\"") return cast_type(value) except (ValueError, TypeError): logging.warning(f"Invalid value for protected key '{key}': {value}. Expected type {cast_type.__name__}.") return default async def get_protected_json(key: str, default: str = "{}") -> dict: raw = _protected_config.get(key, default) if isinstance(raw, dict): return raw try: return json.loads(raw) except json.JSONDecodeError: try: escaped = raw.encode('unicode_escape').decode('utf-8') return json.loads(escaped) except Exception as e: logging.error(f"Failed to parse protected JSON key '{key}': {e}") return json.loads(default) async def load_env_json(key: str, default: str): raw = os.getenv(key, default) try: return json.loads(raw) except json.JSONDecodeError: try: escaped = raw.encode('unicode_escape').decode('utf-8') return json.loads(escaped) except Exception as e: logging.error(f"Failed to parse {key}: {e}") return json.loads(default) async def load_env(key: str, cast_type: Callable[[str], T] = str, default: Optional[T] = None) -> Optional[T]: value = os.getenv(key) if value is None: logger.warning(f"Environment variable '{key}' not set.") return default try: value = value.strip("'\"") return cast_type(value) except (ValueError, TypeError): logger.warning(f"Invalid value for env var '{key}': {value}. Expected type {cast_type.__name__}.") return default