Spaces:
Running
Running
| """ | |
| ReguAI CLI: Automated CI/CD Regulatory Conformity Gate & Audit Runner. | |
| Evaluates model cards, system specifications, and documentation for EU AI Act, | |
| NIST AI RMF, and ISO 42001 compliance, outputting SARIF, JSON, or Annex IV reports. | |
| """ | |
| import sys | |
| import os | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| from typing import List, Optional | |
| if hasattr(sys.stdout, "reconfigure"): | |
| sys.stdout.reconfigure(encoding="utf-8", errors="replace") | |
| if hasattr(sys.stderr, "reconfigure"): | |
| sys.stderr.reconfigure(encoding="utf-8", errors="replace") | |
| from src.engine import ReguAIEngine | |
| from src.core.models import ConformityReport | |
| from src.triage.sarif_exporter import SarifExporter | |
| def render_terminal_summary(report: ConformityReport, target_path: str) -> str: | |
| """Renders an executive terminal compliance summary.""" | |
| status_symbol = "[PASS]" if report.overall_conforms else "[FAIL]" | |
| lines = [ | |
| "=" * 78, | |
| f" REGUAI REGULATORY AUDIT REPORT: {report.system_metadata.name}", | |
| "=" * 78, | |
| f"Target Specification : {target_path}", | |
| f"System Identifier : {report.system_metadata.system_id} (v{report.system_metadata.version})", | |
| f"Risk Classification : {report.system_metadata.eu_risk_classification}", | |
| f"Conformity Status : {status_symbol} ({report.conformity_score:.1f}%)", | |
| f"Requirements Passed : {report.passed_requirements_count} / {report.total_requirements_evaluated}", | |
| f"Digital Audit Token : {report.provenance.digital_signature}", | |
| "-" * 78, | |
| ] | |
| if report.violations: | |
| lines.append(f"CRITICAL LEGAL VIOLATIONS ({len(report.violations)}):") | |
| for idx, v in enumerate(report.violations, 1): | |
| lines.append(f" {idx}. [{v.regulatory_article}] {v.message}") | |
| lines.append(f" Remediation: {v.remediation_guidance}") | |
| lines.append(f" Reference : {v.normative_reference}") | |
| lines.append("-" * 78) | |
| if report.warnings: | |
| lines.append(f"ADVISORY WARNINGS ({len(report.warnings)}):") | |
| for idx, w in enumerate(report.warnings, 1): | |
| lines.append(f" {idx}. [{w.regulatory_article}] {w.message}") | |
| lines.append("-" * 78) | |
| if report.fine_exposure and report.fine_exposure.get("total_potential_fine_eur", 0) > 0: | |
| fine = report.fine_exposure | |
| lines.append(f"EU AI ACT ARTICLE 99 MAXIMUM FINE LIABILITY:") | |
| lines.append(f" Statutory Fine Exposure: €{fine['total_potential_fine_eur']:,.2f}") | |
| lines.append(f" Severity Bracket : {fine.get('severity_bracket', 'Standard')}") | |
| lines.append("-" * 78) | |
| return "\n".join(lines) | |
| def audit_target(args: argparse.Namespace) -> int: | |
| """Executes conformity audit on single file or directory.""" | |
| target = Path(args.target) | |
| if not target.exists(): | |
| print(f"Error: Target path '{target}' does not exist.", file=sys.stderr) | |
| return 2 | |
| files_to_audit: List[Path] = [] | |
| if target.is_dir(): | |
| for ext in ("*.json", "*.md", "*.yaml", "*.yml"): | |
| files_to_audit.extend(target.glob(ext)) | |
| else: | |
| files_to_audit.append(target) | |
| if not files_to_audit: | |
| print(f"Error: No JSON, Markdown, or YAML specifications found in '{target}'.", file=sys.stderr) | |
| return 2 | |
| engine = ReguAIEngine() | |
| overall_exit_code = 0 | |
| all_reports: List[ConformityReport] = [] | |
| for file_path in files_to_audit: | |
| report = engine.evaluate_system( | |
| input_data=file_path, | |
| auditor_id=args.auditor or "reguai_ci_cd", | |
| annual_turnover_eur=args.turnover, | |
| is_sme=args.sme, | |
| ) | |
| all_reports.append(report) | |
| if not report.overall_conforms: | |
| overall_exit_code = 1 | |
| # Format output | |
| if args.format == "text": | |
| print(render_terminal_summary(report, str(file_path))) | |
| elif args.format == "json": | |
| print(json.dumps(report.model_dump(), indent=2)) | |
| elif args.format == "markdown": | |
| print(engine.report_generator.generate_markdown_report(report)) | |
| elif args.format == "sarif": | |
| sarif_doc = SarifExporter.generate_sarif(report, target_file_path=str(file_path)) | |
| print(json.dumps(sarif_doc, indent=2)) | |
| # Output file artifacts if requested | |
| if args.sarif_out: | |
| SarifExporter.export_sarif_json( | |
| report, | |
| output_file_path=args.sarif_out, | |
| target_file_path=str(file_path), | |
| ) | |
| if args.format == "text": | |
| print(f" [+] SARIF report written to: {args.sarif_out}") | |
| if args.json_out: | |
| p = Path(args.json_out) | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| p.write_text(json.dumps(report.model_dump(), indent=2), encoding="utf-8") | |
| if args.format == "text": | |
| print(f" [+] JSON report written to: {args.json_out}") | |
| if args.md_out: | |
| p = Path(args.md_out) | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| md_content = engine.report_generator.generate_markdown_report(report) | |
| p.write_text(md_content, encoding="utf-8") | |
| if args.format == "text": | |
| print(f" [+] Annex IV Markdown written to: {args.md_out}") | |
| if args.bom_out: | |
| p = Path(args.bom_out) | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| bom_content = engine.report_generator.generate_cyclonedx_bom(report) | |
| p.write_text(json.dumps(bom_content, indent=2), encoding="utf-8") | |
| if args.format == "text": | |
| print(f" [+] CycloneDX AI-BOM written to: {args.bom_out}") | |
| if args.fail_on_violation and overall_exit_code != 0: | |
| return 1 | |
| return 0 | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| prog="reguai", | |
| description="ReguAI: Neuro-Symbolic AI GRC & Deterministic Conformity Assessment Engine", | |
| ) | |
| subparsers = parser.add_subparsers(dest="command", help="Available commands") | |
| # Audit sub-command | |
| audit_parser = subparsers.add_parser("audit", help="Audit model card or system spec against EU AI Act") | |
| audit_parser.add_argument("target", help="Path to specification file or directory") | |
| audit_parser.add_argument("--format", choices=["text", "json", "markdown", "sarif"], default="text", help="Output format") | |
| audit_parser.add_argument("--fail-on-violation", action="store_true", help="Exit with code 1 if violations are detected") | |
| audit_parser.add_argument("--auditor", default="ci_cd_automated_gate", help="Auditor / pipeline identifier") | |
| audit_parser.add_argument("--turnover", type=float, default=0.0, help="Annual turnover in EUR for fine calculation") | |
| audit_parser.add_argument("--sme", action="store_true", help="Whether developer is SME under Art 99(6)") | |
| audit_parser.add_argument("--sarif-out", help="File path to write SARIF 2.1.0 output") | |
| audit_parser.add_argument("--json-out", help="File path to write JSON report output") | |
| audit_parser.add_argument("--md-out", help="File path to write Annex IV Markdown output") | |
| audit_parser.add_argument("--bom-out", help="File path to write CycloneDX AI-BOM output") | |
| # Benchmark sub-command | |
| benchmark_parser = subparsers.add_parser("benchmark", help="Run regulatory extraction and triage benchmark") | |
| # Version sub-command | |
| subparsers.add_parser("version", help="Print ReguAI version") | |
| args = parser.parse_args() | |
| if args.command == "audit": | |
| sys.exit(audit_target(args)) | |
| elif args.command == "benchmark": | |
| from evaluate_benchmark import run_benchmark | |
| run_benchmark() | |
| sys.exit(0) | |
| elif args.command == "version": | |
| print("ReguAI Neuro-Symbolic GRC Engine v0.1.0") | |
| sys.exit(0) | |
| else: | |
| parser.print_help() | |
| sys.exit(0) | |
| if __name__ == "__main__": | |
| main() | |