Implement row-level security (RLS) context management for database sessions. Refactor invoice processing and reverting tasks to utilize scoped database sessions with RLS context. Update middleware to extract and set company ID from requests. Enhance task dispatching to propagate RLS context via Celery headers. Update architecture documentation to reflect RLS implementation details.

This commit is contained in:
2026-04-24 18:01:46 -05:00
parent 7acf77994f
commit 73a6d92863
13 changed files with 1052 additions and 306 deletions

View File

@@ -3,6 +3,8 @@ from typing import Any
from celery import Task
from sqlalchemy.orm import Session
from core.database import rls_company_var, rls_tenant_var
from .service import TaskTrackerService
@@ -21,7 +23,25 @@ def track_and_dispatch(
task_id: str | None = None,
meta_payload: dict[str, Any] | None = None,
):
celery_task = task.apply_async(args=args or [], kwargs=kwargs or {}, task_id=task_id)
# Propaga contexto RLS vía Celery headers (leídos en task_prerun) y
# ContextVars (para modo eager, donde before_task_publish no dispara).
headers = {"rls_tenant_id": str(int(tenant_id))}
if company_id is not None:
headers["rls_company_id"] = str(int(company_id))
token_t = rls_tenant_var.set(int(tenant_id))
token_c = rls_company_var.set(int(company_id) if company_id is not None else None)
try:
celery_task = task.apply_async(
args=args or [],
kwargs=kwargs or {},
task_id=task_id,
headers=headers,
)
finally:
rls_tenant_var.reset(token_t)
rls_company_var.reset(token_c)
tracker = TaskTrackerService(db)
tracker.register_dispatch(
task_id=celery_task.id,