riskengine / src /bmc /api.py
datavorous's picture
intial commit
28779c1 verified
Raw
History Blame Contribute Delete
1.78 kB
from dataclasses import asdict
import asyncio
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, HttpUrl
from starlette.concurrency import run_in_threadpool
from .engine import assess
from .fetcher import ProfileNotFound, fetch_profile
from .link_resolver import resolve_link
app = FastAPI(title="BMC RiskEngine API", version="1.0.0")
class AssessRequest(BaseModel):
bmc_url: HttpUrl
class ErrorResponse(BaseModel):
detail: str
class AssessResponse(BaseModel):
risk_score: int
risk_level: str
recommended_action: str
evidence: list
limitations: list
async def _analyze(bmc_url: str):
profile = await run_in_threadpool(fetch_profile, bmc_url)
resolved_links = []
# for link in profile.external_links:
# resolved = await run_in_threadpool(resolve_link, link)
# resolved_links.append(resolved)
tasks = [run_in_threadpool(resolve_link, link) for link in profile.external_links]
resolved_links = await asyncio.gather(*tasks)
assessment = assess(profile, resolved_links)
return asdict(assessment)
@app.post(
"/assess", response_model=AssessResponse, responses={404: {"model": ErrorResponse}}
)
async def assess_profile(payload: AssessRequest):
try:
result = await _analyze(str(payload.bmc_url))
except ProfileNotFound as exc:
raise HTTPException(status_code=404, detail="Profile not found") from exc
except Exception as exc:
# TODO: need to log real exceptions
raise HTTPException(status_code=500, detail="Internal server error") from exc
return result
@app.get("/", response_model=dict)
async def root():
return {
"message": "Welcome to the BMC RiskEngine API. Use the /assess endpoint to evaluate a BMC profile."
}