"""GRC 자동화 — Governance Risk Compliance""" from __future__ import annotations import json, logging from datetime import datetime from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query from pydantic import BaseModel from core.auth import get_current_user, require_admin_role from models import User logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/grc", tags=["GRC 자동화"]) _policies: list[dict] = [] _risks: list[dict] = [] _pid = 0; _rid = 0 class PolicyCreate(BaseModel): title: str; category: str = "security"; content: str = ""; version: str = "1.0" class RiskCreate(BaseModel): title: str; likelihood: int = 3; impact: int = 3; mitigation: str = "" @router.get("/policies") async def list_policies(category: str = Query(None), user: User = Depends(get_current_user)): items = _policies if not category else [p for p in _policies if p["category"] == category] return {"total": len(items), "items": items} @router.post("/policies") async def create_policy(body: PolicyCreate, user: User = Depends(require_admin_role)): global _pid; _pid += 1 draft = body.content if not draft: try: import httpx async with httpx.AsyncClient(timeout=10) as c: r = await c.post("http://localhost:11434/api/generate", json={ "model": "llama3", "stream": False, "prompt": f"다음 IT 보안 정책을 한국어로 3개 항목으로 작성하라: {body.title}"}) draft = r.json().get("response", f"{body.title} 정책 초안") except Exception: draft = f"{body.title}: 정책 내용을 입력하세요." p = {"id": _pid, "title": body.title, "category": body.category, "content": draft, "version": body.version, "status": "draft", "created_by": user.username, "created_at": datetime.utcnow().isoformat()} _policies.append(p); return p @router.put("/policies/{pid}") async def update_policy(pid: int, body: PolicyCreate, user: User = Depends(require_admin_role)): for p in _policies: if p["id"] == pid: p.update({"title": body.title, "category": body.category, "content": body.content, "version": body.version}); return p raise HTTPException(404, "정책 없음") @router.get("/risk-matrix") async def risk_matrix(user: User = Depends(get_current_user)): m = {"critical": [], "high": [], "medium": [], "low": []} for r in _risks: s = r["risk_score"] if s >= 20: m["critical"].append(r) elif s >= 12: m["high"].append(r) elif s >= 6: m["medium"].append(r) else: m["low"].append(r) return {"total": len(_risks), "matrix": m} @router.post("/risk-assessment") async def create_risk(body: RiskCreate, user: User = Depends(require_admin_role)): global _rid; _rid += 1 s = body.likelihood * body.impact lv = "CRITICAL" if s >= 20 else "HIGH" if s >= 12 else "MEDIUM" if s >= 6 else "LOW" r = {"id": _rid, "title": body.title, "likelihood": body.likelihood, "impact": body.impact, "risk_score": s, "level": lv, "mitigation": body.mitigation, "status": "open", "created_at": datetime.utcnow().isoformat()} _risks.append(r); return r @router.get("/compliance") async def compliance_summary(user: User = Depends(get_current_user)): crit = sum(1 for r in _risks if r.get("level") == "CRITICAL") score = max(0, 100 - crit * 10) return {"policies": {"total": len(_policies), "active": sum(1 for p in _policies if p.get("status") == "active")}, "risks": {"total": len(_risks), "critical": crit}, "compliance_score": score, "grade": "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D"} @router.post("/audit-report") async def audit_report(standard: str = Query("CSAP"), user: User = Depends(require_admin_role)): crit = sum(1 for r in _risks if r.get("level") == "CRITICAL") score = max(0, 100 - crit * 10) return {"standard": standard, "generated_at": datetime.utcnow().isoformat(), "summary": {"total_policies": len(_policies), "total_risks": len(_risks), "critical_risks": crit, "compliance_score": score}, "findings": [f"CRITICAL 리스크 {crit}건", f"{standard} 준수율 {score}%"], "recommendations": ["CRITICAL 리스크 즉시 완화 조치 필요"] if crit else ["컴플라이언스 상태 양호"]} @router.get("/templates") async def policy_templates(user: User = Depends(get_current_user)): return {"templates": [ {"id": 1, "name": "SSH root 접속 금지 정책", "category": "security"}, {"id": 2, "name": "비밀번호 90일 주기 변경 정책", "category": "access"}, {"id": 3, "name": "미사용 계정 30일 비활성화 정책", "category": "access"}, {"id": 4, "name": "서버 패치 30일 내 적용 정책", "category": "operation"}, {"id": 5, "name": "백업 7일 보관 확인 정책", "category": "operation"}, ]} @router.get("/dashboard") async def grc_dashboard(user: User = Depends(get_current_user)): crit = sum(1 for r in _risks if r.get("level") == "CRITICAL") score = max(0, 100 - crit * 10) return {"compliance_score": score, "grade": "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D", "policies": len(_policies), "risks": len(_risks), "critical_risks": crit, "recent_policies": _policies[-3:][::-1], "top_risks": sorted(_risks, key=lambda x: x["risk_score"], reverse=True)[:3]}