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:
+32
-9
@@ -106,13 +106,29 @@ def _get_sync_engine():
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def db_setup():
|
||||
"""Drop and recreate all tables once per test session."""
|
||||
"""Drop and recreate all tables once per test session.
|
||||
|
||||
Uses SET lock_timeout to prevent deadlocks when multiple test processes
|
||||
try to DROP SCHEMA simultaneously. Falls back to TRUNCATE if DROP fails.
|
||||
"""
|
||||
sync_eng = _get_sync_engine()
|
||||
with sync_eng.connect() as conn:
|
||||
# Drop all tables and types
|
||||
conn.execute(text("DROP SCHEMA public CASCADE;"))
|
||||
conn.execute(text("CREATE SCHEMA public;"))
|
||||
conn.execute(text("GRANT ALL ON SCHEMA public TO leocrm;"))
|
||||
# Set a short lock timeout to prevent deadlocks
|
||||
conn.execute(text("SET lock_timeout = '5s';"))
|
||||
try:
|
||||
conn.execute(text("DROP SCHEMA IF EXISTS public CASCADE;"))
|
||||
conn.execute(text("CREATE SCHEMA public;"))
|
||||
conn.execute(text("GRANT ALL ON SCHEMA public TO leocrm;"))
|
||||
except Exception:
|
||||
# If DROP SCHEMA deadlocks, fall back to TRUNCATE all tables
|
||||
conn.rollback()
|
||||
conn.execute(text("SET lock_timeout = '5s';"))
|
||||
conn.execute(text(
|
||||
"DO $$ DECLARE r RECORD; BEGIN "
|
||||
"FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname='public') "
|
||||
"LOOP EXECUTE 'TRUNCATE TABLE public.' || quote_ident(r.tablename) || ' CASCADE'; "
|
||||
"END LOOP; END $$;"
|
||||
))
|
||||
conn.commit()
|
||||
sync_eng.dispose()
|
||||
|
||||
@@ -126,12 +142,19 @@ def db_setup():
|
||||
asyncio.get_event_loop().run_until_complete(_create())
|
||||
yield
|
||||
|
||||
# Cleanup after session
|
||||
# Cleanup after session — use TRUNCATE instead of DROP to avoid deadlocks
|
||||
sync_eng = _get_sync_engine()
|
||||
with sync_eng.connect() as conn:
|
||||
conn.execute(text("DROP SCHEMA public CASCADE;"))
|
||||
conn.execute(text("CREATE SCHEMA public;"))
|
||||
conn.execute(text("GRANT ALL ON SCHEMA public TO leocrm;"))
|
||||
conn.execute(text("SET lock_timeout = '5s';"))
|
||||
try:
|
||||
conn.execute(text(
|
||||
"DO $$ DECLARE r RECORD; BEGIN "
|
||||
"FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname='public') "
|
||||
"LOOP EXECUTE 'TRUNCATE TABLE public.' || quote_ident(r.tablename) || ' CASCADE'; "
|
||||
"END LOOP; END $$;"
|
||||
))
|
||||
except Exception:
|
||||
pass
|
||||
conn.commit()
|
||||
sync_eng.dispose()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user