from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.utils import get_openapi from fastapi_pagination import add_pagination from app.api.router import router as api_router from app.config import settings from app.core.redis_sse_bridge import RedisSSEBridge from app.core.throttle import GlobalRateLimitMiddleware from app.utils.helpers import create_initial_admin from shared.logging import get_logger logger = get_logger(__name__) redis_sse_bridge = RedisSSEBridge(settings.redis_url) @asynccontextmanager async def lifespan(_app: FastAPI): logger.info("Starting Backend...") try: await create_initial_admin() await redis_sse_bridge.start() except Exception as e: logger.exception("Failed to initialize the application: %s", e) raise e yield logger.info("Shutting down reNgine Backend...") await redis_sse_bridge.stop() app = FastAPI( title=settings.APP_NAME, version=settings.APP_VERSION, lifespan=lifespan, ) add_pagination(app) def custom_openapi(): if app.openapi_schema: return app.openapi_schema openapi_schema = get_openapi( title=settings.APP_NAME, version=settings.APP_VERSION, description="reNgine 3.0 - Attack Surface Management Platform", routes=app.routes, ) openapi_schema["components"]["securitySchemes"] = { "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "Enter your JWT token from /auth/login", } } app.openapi_schema = openapi_schema return app.openapi_schema app.openapi = custom_openapi if "*" in settings.CORS_ORIGINS: msg = "CORS_ORIGINS must be an explicit allowlist (no '*') when credentials are enabled" raise ValueError(msg) app.add_middleware(GlobalRateLimitMiddleware) app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(api_router, prefix=settings.API_V1_PREFIX) @app.get("/") async def root(): logger.debug("Root endpoint accessed") return { "message": "Welcome to reNgine API", "version": settings.APP_VERSION, "docs": "/docs", }