mihir2007/Cyber-Risk
0
1"""2run_simulation.py3------------------4Standalone terminal runner for the CRQ platform. Executes the full pipeline5end-to-end against the SQLite database, without needing the FastAPI server:6 7 1. Initializes the SQLite database (creates tables if missing).8 2. Seeds synthetic enterprise data (idempotent).9 3. Runs a 10,000-iteration Monte Carlo simulation and prints the10 aggregate Enterprise Risk (EAL, VaR 95/99) in ₹.11 4. Runs the PuLP budget optimizer for a ₹50,00,000 budget and prints12 the chosen controls, total spent, and ROSI.13 5. Verifies the run was persisted to `SimulationRun` by querying SQLite14 directly and printing the stored record.15 16Usage:17 python run_simulation.py18"""19 20from __future__ import annotations21 22from database import SessionLocal, init_db23from models import Asset, SecurityControl, SimulationRun24from optimizer import optimize_budget_allocation25from quant_engine import run_enterprise_simulation26from seeder import seed_database27 28DEMO_BUDGET_INR = 5_000_000.0 # ₹50,00,00029 30 31def _format_inr(amount: float) -> str:32 """Formats a rupee amount with Indian-style comma grouping, e.g. ₹1,23,45,678.90."""33 is_negative = amount < 034 amount = abs(amount)35 integer_part, _, decimal_part = f"{amount:.2f}".partition(".")36 37 if len(integer_part) > 3:38 last_three = integer_part[-3:]39 remaining = integer_part[:-3]40 grouped = []41 while len(remaining) > 2:42 grouped.insert(0, remaining[-2:])43 remaining = remaining[:-2]44 if remaining:45 grouped.insert(0, remaining)46 integer_part = ",".join(grouped + [last_three])47 48 sign = "-" if is_negative else ""49 return f"{sign}₹{integer_part}.{decimal_part}"50 51 52def main() -> None:53 print("=" * 78)54 print(" AI-Powered Continuous Cyber Risk Quantification (CRQ) Platform")55 print(" Standalone Simulation Runner")56 print("=" * 78)57 58 # --- Step 1: Initialize database ------------------------------------- #59 print("\n[1/5] Initializing SQLite database (cyber_risk.db)...")60 init_db()61 print(" Tables created/verified.")62 63 db = SessionLocal()64 try:65 # --- Step 2: Seed synthetic data ---------------------------------- #66 print("\n[2/5] Seeding synthetic enterprise telemetry...")67 summary = seed_database(db)68 print(69 f" Inserted: {summary['assets']} assets, "70 f"{summary['vulnerabilities']} vulnerabilities, "71 f"{summary['controls']} security controls "72 "(0 values mean already seeded)."73 )74 75 assets = db.query(Asset).all()76 all_controls = db.query(SecurityControl).all()77 print(f" Total assets in DB: {len(assets)} | Total controls in DB: {len(all_controls)}")78 79 # --- Step 3: Monte Carlo enterprise risk simulation ---------------- #80 print("\n[3/5] Running 10,000-iteration Monte Carlo enterprise risk simulation...")81 active_controls = [c for c in all_controls if c.is_active]82 result = run_enterprise_simulation(db, assets, active_controls, persist=True)83 84 print(f" Expected Annual Loss (EAL): {_format_inr(result.total_eal_inr)}")85 print(f" Value at Risk (95% confidence): {_format_inr(result.var_95_inr)}")86 print(f" Value at Risk (99% confidence): {_format_inr(result.var_99_inr)}")87 print(88 f" Estimated Regulatory Fine Exposure (95th pct): "89 f"{_format_inr(result.total_regulatory_fine_exposure_inr)}"90 )91 92 print("\n Top 5 riskiest assets by EAL:")93 top_5 = sorted(result.per_asset_results, key=lambda r: r.eal_inr, reverse=True)[:5]94 for rank, r in enumerate(top_5, start=1):95 print(96 f" {rank}. {r.hostname:<24} ({r.tier:<8}) "97 f"lambda={r.annual_event_frequency:5.2f}/yr EAL={_format_inr(r.eal_inr)}"98 )99 100 # --- Step 4: Budget-constrained optimization ------------------------ #101 print(f"\n[4/5] Running PuLP 0/1 knapsack budget optimizer for {_format_inr(DEMO_BUDGET_INR)}...")102 opt_result = optimize_budget_allocation(db, assets, all_controls, DEMO_BUDGET_INR)103 104 selected_codes = {c.code for c in opt_result.selected_controls}105 for control in all_controls:106 control.is_active = control.code in selected_codes107 db.commit()108 109 print(f" Baseline EAL: {_format_inr(opt_result.baseline_eal_inr)}")110 print(f" Projected EAL: {_format_inr(opt_result.projected_eal_inr)}")111 print(f" Net Risk Reduction (Delta EAL): {_format_inr(opt_result.net_risk_reduction_inr)}")112 print(f" Total Spent: {_format_inr(opt_result.total_spent_inr)}")113 print(f" Remaining Budget: {_format_inr(opt_result.remaining_budget_inr)}")114 print(f" ROSI: {opt_result.rosi_percent:.2f}%")115 print("\n Selected controls:")116 for control in opt_result.selected_controls:117 mv = opt_result.control_marginal_values[control.code]118 print(119 f" - {control.code:<24} {control.name:<48} "120 f"cost={_format_inr(control.cost_inr):>18} "121 f"marginal_dEAL={_format_inr(mv.adjusted_value_inr)}"122 )123 124 # Persist the optimizer run as well.125 import json as _json126 127 opt_run_record = SimulationRun(128 total_eal_inr=opt_result.projected_eal_inr,129 var_95_inr=result.var_95_inr,130 var_99_inr=result.var_99_inr,131 allocated_budget_inr=DEMO_BUDGET_INR,132 selected_controls_json=_json.dumps(sorted(selected_codes)),133 )134 db.add(opt_run_record)135 db.commit()136 db.refresh(opt_run_record)137 138 # --- Step 5: Verify persistence ------------------------------------- #139 print("\n[5/5] Verifying SimulationRun persistence in SQLite...")140 stored_run = (141 db.query(SimulationRun)142 .order_by(SimulationRun.timestamp.desc())143 .first()144 )145 if stored_run is None:146 print(" ERROR: No SimulationRun record found!")147 else:148 print(" Latest stored SimulationRun record:")149 print(f" id = {stored_run.id}")150 print(f" timestamp = {stored_run.timestamp}")151 print(f" total_eal_inr = {_format_inr(stored_run.total_eal_inr)}")152 print(f" var_95_inr = {_format_inr(stored_run.var_95_inr)}")153 print(f" var_99_inr = {_format_inr(stored_run.var_99_inr)}")154 print(f" allocated_budget_inr = {_format_inr(stored_run.allocated_budget_inr or 0.0)}")155 print(f" selected_controls_json = {stored_run.selected_controls_json}")156 157 total_runs = db.query(SimulationRun).count()158 print(f"\n Total SimulationRun records in database: {total_runs}")159 160 finally:161 db.close()162 163 print("\n" + "=" * 78)164 print(" Simulation complete.")165 print("=" * 78)166 167 168if __name__ == "__main__":169 main()170 