From fa96466a50c5d55fab1a35e323d8aa08e0178c8e Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Fri, 31 Jul 2026 09:43:29 +0200 Subject: [PATCH] gate: fresh session per plugin activation to isolate RLS errors --- app/main.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/app/main.py b/app/main.py index be7e79d..27069af 100644 --- a/app/main.py +++ b/app/main.py @@ -220,28 +220,26 @@ async def lifespan(app: FastAPI): logger.info(f"Plugin {name} is inactive — skipping activation") continue - # Activate plugin with tenant context set for each tenant + # Activate plugin with a FRESH session per plugin to avoid RLS state leakage # RLS fail-closed requires app.current_tenant_id for tenant-table writes. - # Plugin activation may fail on duplicate cron job inserts — this is - # harmless since cron jobs already exist from previous startups. - try: - for tenant_id in all_tenant_ids: - try: - await set_tenant_context(db, tenant_id) - await plugin.on_activate(db, container, event_bus) - await db.flush() - except Exception as exc: - logger.warning(f"[STARTUP] Plugin {name} activation issue for tenant {tenant_id}: {exc}") - await db.rollback() - db.expunge_all() # Clear pending objects from failed INSERT - break - except Exception as exc: - logger.warning(f"[STARTUP] Plugin {name} activation failed: {exc}") - await db.rollback() - db.expunge_all() + # Plugin activation may fail on duplicate cron job inserts — this is harmless + # since cron jobs already exist from previous startups. + plugin_activated = False + for tenant_id in all_tenant_ids: + try: + async with async_session() as plugin_db: + await set_tenant_context(plugin_db, tenant_id) + await plugin.on_activate(plugin_db, container, event_bus) + await plugin_db.flush() + await plugin_db.commit() + plugin_activated = True + except Exception as exc: + logger.warning(f"[STARTUP] Plugin {name} activation issue for tenant {tenant_id}: {exc}") + break - plugin_record.status = "active" - logger.info(f"[STARTUP] Activated plugin: {name}") + if plugin_activated: + plugin_record.status = "active" + logger.info(f"[STARTUP] Activated plugin: {name}") try: await db.commit()