Phase 1: Fix all critical release blockers (B1-B10)
B1: Remove duplicate get_redis() — singleton no longer overwritten B2: Plugin routes now enforce activation status via require_active_plugin() B3: Fix UploadFile ForwardRef error — remove functools.wraps from wrap_plugin_route B4: DMS upload uses true streaming via save_stream() instead of RAM accumulation B5: Worker on_startup registers plugin event handlers + webhook dispatcher B6: Implement send_password_reset_email job, remove raw token logging B7: Webhook SSRF protection (IP validation, no redirects), secret removed from response B8: RLS repair migration 0044 + separate crm_runtime DB user (NOSUPERUSER, NOBYPASSRLS) B9: Fix .env.docker.example AUTH_SECRET → SECRET_KEY B10: Remove Redis default password, remove exposed DB/Redis ports Also: add frontend_url to config, add SMTP settings to .env.docker.example, update prestart.sh to use MIGRATION_DATABASE_URL for alembic.
This commit is contained in:
+15
-5
@@ -6,7 +6,7 @@ import time
|
||||
import traceback
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi import FastAPI, HTTPException, Request, Depends
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
@@ -208,6 +208,11 @@ async def lifespan(app: FastAPI):
|
||||
init_permission_registry(active_plugin_names)
|
||||
logger.info("Permission registry initialized with %d active plugins", len(active_plugin_names))
|
||||
|
||||
# Register webhook dispatcher on the event bus
|
||||
from app.core.webhook_dispatcher import register_webhook_event_handlers
|
||||
register_webhook_event_handlers(event_bus)
|
||||
logger.info("Webhook event handlers registered")
|
||||
|
||||
# Register field definitions from active plugins only
|
||||
from app.core.permission_registry import get_permission_registry
|
||||
for name in active_plugin_names:
|
||||
@@ -368,9 +373,10 @@ def create_app() -> FastAPI:
|
||||
app.include_router(errors.router)
|
||||
|
||||
# ── Register plugin routes for all built-in plugins ──
|
||||
# Routes are registered here (before app start); activation status
|
||||
# is enforced at runtime via require_permission and plugin checks.
|
||||
# Routes are registered at app creation time so OpenAPI docs are complete.
|
||||
# Activation status is enforced per-request via require_active_plugin().
|
||||
import importlib
|
||||
from app.deps import require_active_plugin
|
||||
# Discover all built-in plugin modules and register their routes
|
||||
plugin_modules = [
|
||||
"app.plugins.builtins.tags",
|
||||
@@ -399,6 +405,7 @@ def create_app() -> FastAPI:
|
||||
for attr_name in dir(mod):
|
||||
attr = getattr(mod, attr_name)
|
||||
if isinstance(attr, type) and hasattr(attr, "manifest") and hasattr(attr.manifest, "routes"):
|
||||
plugin_name = getattr(attr.manifest, "name", mod_name.split(".")[-1])
|
||||
for route_def in attr.manifest.routes:
|
||||
try:
|
||||
router_module = importlib.import_module(route_def.module)
|
||||
@@ -407,13 +414,16 @@ def create_app() -> FastAPI:
|
||||
for route in router.routes:
|
||||
if hasattr(route, 'endpoint'):
|
||||
route.endpoint = wrap_plugin_route(route.endpoint)
|
||||
app.include_router(router)
|
||||
# Add active-plugin check as a router-level dependency
|
||||
app.include_router(
|
||||
router,
|
||||
dependencies=[Depends(require_active_plugin(plugin_name))],
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error(f"Failed to register route {route_def.module}.{route_def.router_attr}: {exc}")
|
||||
break
|
||||
except Exception as exc:
|
||||
logger.error(f"Failed to register plugin routes for {mod_name}: {exc}")
|
||||
# Do NOT register plugin routes here — lifespan() handles it for active plugins only
|
||||
|
||||
# ── Serve frontend static files (SPA) ──────────────────────────────
|
||||
# Mount built frontend assets (JS, CSS, images)
|
||||
|
||||
Reference in New Issue
Block a user