| """ |
| SOC Dashboard API Server |
| Thin FastAPI wrapper around the existing OrchestratorCoordinator. |
| Run: python server.py β http://localhost:8000 |
| """ |
|
|
| import os |
| import sys |
| import json |
| import asyncio |
| import uvicorn |
| from pathlib import Path |
| from fastapi import FastAPI, Request |
| from fastapi.responses import HTMLResponse, JSONResponse |
| from fastapi.middleware.cors import CORSMiddleware |
|
|
| |
| PROJECT_ROOT = Path(__file__).resolve().parent |
| if str(PROJECT_ROOT) not in sys.path: |
| sys.path.insert(0, str(PROJECT_ROOT)) |
|
|
| from dotenv import load_dotenv |
| load_dotenv(PROJECT_ROOT / ".env") |
|
|
| if "GOOGLE_API_KEY" in os.environ and "GEMINI_API_KEY" not in os.environ: |
| os.environ["GEMINI_API_KEY"] = os.environ["GOOGLE_API_KEY"] |
|
|
| from src.agents.orchestrator.agent import OrchestratorCoordinator |
|
|
| app = FastAPI(title="Security Triage Fleet β SOC Dashboard") |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| orchestrator = OrchestratorCoordinator() |
|
|
| |
| @app.get("/", response_class=HTMLResponse) |
| async def serve_dashboard(): |
| html_path = PROJECT_ROOT / "dashboard.html" |
| return HTMLResponse(content=html_path.read_text(encoding="utf-8")) |
|
|
|
|
| |
| @app.post("/api/simulate") |
| async def run_simulation(request: Request): |
| """ |
| Accepts a JSON body with a 'prompt' field (the target context). |
| Runs the 3-phase pipeline and returns the simulation report. |
| """ |
| try: |
| api_key = request.headers.get("X-API-Key") |
| body = await request.json() |
| prompt = body.get("prompt", "") |
| if not prompt: |
| return JSONResponse( |
| status_code=400, |
| content={"error": "Missing 'prompt' field in request body."} |
| ) |
|
|
| if not api_key: |
| api_key = body.get("api_key") |
|
|
| result_json = await orchestrator.invoke(prompt, api_key=api_key) |
| return JSONResponse(content=json.loads(result_json)) |
|
|
| except Exception as e: |
| return JSONResponse( |
| status_code=500, |
| content={"error": str(e), "type": type(e).__name__} |
| ) |
|
|
|
|
| |
| @app.post("/api/approve") |
| async def approve_hitl(request: Request): |
| """ |
| Re-runs the simulation with 'approve' in the prompt so the orchestrator |
| triggers the Green Team remediation phase. |
| """ |
| try: |
| api_key = request.headers.get("X-API-Key") |
| body = await request.json() |
| original_prompt = body.get("prompt", "") |
| approved = body.get("approved", False) |
|
|
| if not api_key: |
| api_key = body.get("api_key") |
|
|
| if approved: |
| prompt_with_approval = f"{original_prompt}\napprove" |
| else: |
| |
| return JSONResponse(content={ |
| "simulation_outcome": "DENIED", |
| "message": "HITL approval denied. Simulation halted at Phase 2." |
| }) |
|
|
| result_json = await orchestrator.invoke(prompt_with_approval, api_key=api_key) |
| return JSONResponse(content=json.loads(result_json)) |
|
|
| except Exception as e: |
| return JSONResponse( |
| status_code=500, |
| content={"error": str(e), "type": type(e).__name__} |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββ") |
| print("β Security Triage Fleet β SOC Dashboard β") |
| print("β http://localhost:8000 β") |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββ") |
| uvicorn.run(app, host="0.0.0.0", port=8000) |
|
|