from __future__ import annotations from pathlib import Path from typing import Any, Dict, List import yaml ROOT = Path(__file__).resolve().parents[2] FRAMEWORK_ROOT = ROOT / "07-framework-security" THREAT_INTEL_ROOT = ROOT / "08-threat-intel" REGISTRY_ROOT = THREAT_INTEL_ROOT / "registry" ADVISORIES_DIR = REGISTRY_ROOT / "advisories" SYSTEMS_DIR = REGISTRY_ROOT / "systems" TRIAGE_DIR = REGISTRY_ROOT / "triage" GENERATED_DIR = THREAT_INTEL_ROOT / "generated" SECURE_CODE_ROOT = ROOT / "05-defense" / "secure-code" SOURCE_MAP_PATH = THREAT_INTEL_ROOT / "source-map.yaml" STATE_DIR = Path.home() / ".local" / "state" / "websafe-intel" STATE_PATH = STATE_DIR / "state.json" def load_source_map() -> Dict[str, Any]: with SOURCE_MAP_PATH.open("r", encoding="utf-8") as handle: data = yaml.safe_load(handle) if not isinstance(data, dict) or "systems" not in data: raise ValueError("source-map.yaml must contain a top-level 'systems' list") systems = data["systems"] if not isinstance(systems, list): raise ValueError("'systems' must be a list") return data def get_systems_by_group(source_map: Dict[str, Any]) -> Dict[str, List[Dict[str, Any]]]: groups: Dict[str, List[Dict[str, Any]]] = {} for system in source_map["systems"]: output_dir = Path(system["output_dir"]) parts = output_dir.parts if len(parts) < 3: raise ValueError(f"output_dir too short for system {system['system_id']}") group = parts[1] groups.setdefault(group, []).append(system) return groups