reguai-engine / src /reasoning /framework_crosswalk.py
gitmodelmujtaba's picture
Deploy ReguAI: Neuro-Symbolic AI GRC & Automated Conformity Assessment Engine
99102a1 verified
Raw
History Blame Contribute Delete
5.57 kB
"""
Multi-Framework Regulatory Harmonization Crosswalk.
Projects EU AI Act (Regulation EU 2024/1689) conformity findings onto:
- NIST AI RMF 1.0 (GOVERN, MAP, MEASURE, MANAGE)
- ISO/IEC 42001:2023 (Clauses & Annex A Controls)
- GDPR (Regulation EU 2016/679)
"""
import json
from pathlib import Path
from typing import Dict, List, Any, Optional
from pydantic import BaseModel, Field
from src.core.config import BENCHMARKS_DIR
from src.core.models import ValidationViolation
class FrameworkControlStatus(BaseModel):
control_id: str
control_name: str
target_framework: str
status: str # "SATISFIED", "NON_COMPLIANT", "NOT_EVALUATED"
eu_ai_act_article: str
relationship_type: str
semantic_rationale: str
audit_guidance: str
class FrameworkSummary(BaseModel):
total_mapped_controls: int
satisfied_controls_count: int
non_compliant_controls_count: int
conformity_percentage: float
controls: List[FrameworkControlStatus] = Field(default_factory=list)
class MultiFrameworkCrosswalkResult(BaseModel):
frameworks: Dict[str, FrameworkSummary] = Field(default_factory=dict)
high_level_summary: str = ""
class MultiFrameworkCrosswalk:
def __init__(self, mappings_path: Optional[Path] = None):
self.mappings_file = mappings_path or (BENCHMARKS_DIR / "rules" / "cross_regulatory_frameworks.json")
self.mappings: List[Dict[str, Any]] = []
self._load_mappings()
def _load_mappings(self) -> None:
if self.mappings_file.exists():
with open(self.mappings_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.mappings = data.get("mappings", [])
else:
self.mappings = []
def harmonize(
self,
violations: List[ValidationViolation],
all_evaluated_articles: Optional[List[str]] = None,
) -> MultiFrameworkCrosswalkResult:
"""
Projects EU AI Act conformity assessment results across target frameworks.
"""
violation_articles = set(v.regulatory_article.strip() for v in violations)
# Normalize: e.g. "Article 9(2)" -> "Article 9" prefix match
def is_article_violated(article_name: str) -> bool:
for v_art in violation_articles:
if article_name.startswith(v_art) or v_art.startswith(article_name):
return True
return False
framework_controls: Dict[str, List[FrameworkControlStatus]] = {
"NIST AI RMF 1.0": [],
"ISO/IEC 42001:2023": [],
"GDPR (EU 2016/679)": [],
}
for m in self.mappings:
target_fw = m.get("target_framework", "Unknown")
eu_art = m.get("eu_ai_act_article", "")
has_violation = is_article_violated(eu_art)
status = "NON_COMPLIANT" if has_violation else "SATISFIED"
ctrl_status = FrameworkControlStatus(
control_id=m.get("target_control_id", ""),
control_name=m.get("target_control_name", ""),
target_framework=target_fw,
status=status,
eu_ai_act_article=eu_art,
relationship_type=m.get("relationship_type", "EXACT_EQUIVALENT"),
semantic_rationale=m.get("semantic_rationale", ""),
audit_guidance=m.get("audit_guidance", ""),
)
if target_fw in framework_controls:
framework_controls[target_fw].append(ctrl_status)
else:
framework_controls.setdefault(target_fw, []).append(ctrl_status)
framework_summaries: Dict[str, FrameworkSummary] = {}
total_satisfied = 0
total_controls = 0
for fw_name, ctrls in framework_controls.items():
tot = len(ctrls)
sat = sum(1 for c in ctrls if c.status == "SATISFIED")
non = sum(1 for c in ctrls if c.status == "NON_COMPLIANT")
pct = round((sat / tot * 100.0), 1) if tot > 0 else 100.0
total_satisfied += sat
total_controls += tot
framework_summaries[fw_name] = FrameworkSummary(
total_mapped_controls=tot,
satisfied_controls_count=sat,
non_compliant_controls_count=non,
conformity_percentage=pct,
controls=ctrls,
)
overall_pct = round((total_satisfied / total_controls * 100.0), 1) if total_controls > 0 else 100.0
summary_text = (
f"Multi-framework crosswalk mapped across {len(framework_summaries)} international frameworks: "
f"{total_satisfied}/{total_controls} controls satisfied ({overall_pct}% alignment). "
f"NIST AI RMF: {framework_summaries.get('NIST AI RMF 1.0', FrameworkSummary(total_mapped_controls=0, satisfied_controls_count=0, non_compliant_controls_count=0, conformity_percentage=0.0)).conformity_percentage}%, "
f"ISO 42001: {framework_summaries.get('ISO/IEC 42001:2023', FrameworkSummary(total_mapped_controls=0, satisfied_controls_count=0, non_compliant_controls_count=0, conformity_percentage=0.0)).conformity_percentage}%, "
f"GDPR: {framework_summaries.get('GDPR (EU 2016/679)', FrameworkSummary(total_mapped_controls=0, satisfied_controls_count=0, non_compliant_controls_count=0, conformity_percentage=0.0)).conformity_percentage}%."
)
return MultiFrameworkCrosswalkResult(
frameworks=framework_summaries,
high_level_summary=summary_text,
)