Seguridad y multi-tenancy
El aislamiento entre tenants es no negociable (Ley 1581 de Colombia). Se aplica defensa en profundidad con dos capas independientes.
Capa 1 — TenantMiddleware
Sección titulada «Capa 1 — TenantMiddleware»El api-gateway valida el JWT (HS256, AUTH_JWT_SECRET), extrae y valida el workspace_id
(UUID) y lo inyecta en el contexto. Sin token válido: 401/403.
Capa 2 — Row Level Security real
Sección titulada «Capa 2 — Row Level Security real»Las tablas tenant-scoped tienen políticas RLS (workspace_id = auth.workspace_id()). Pero hay
un detalle crítico: la imagen oficial de Postgres crea al usuario de la app como superusuario,
y los superusuarios ignoran RLS aun con FORCE.
Por eso, para cada request con contexto de tenant, el pool de conexiones:
- Hace
SET ROLE bongga_app— un rol no-superusuario (migración0029). - Fija
bongga.current_workspace_id(GUC) queauth.workspace_id()lee.
Bajo ese rol las políticas sí aplican, aunque la app olvide filtrar. Las rutas de sistema /
pre-auth (boot, login, OTP, resolución de webhook) hacen RESET ROLE y corren con el rol
privilegiado. Es un cambio monótono: sin contexto de workspace se comporta como antes; con
contexto la RLS se aplica de verdad.
BYOK (Bring Your Own Key)
Sección titulada «BYOK (Bring Your Own Key)»El cliente trae su propia API key de IA (OpenAI/Anthropic) y paga su WhatsApp/Meta directo. Bongga no absorbe costos de IA ni de conversaciones Meta. Las keys se guardan cifradas en reposo (AES-256-GCM) y se inyectan en runtime.
Baseline OWASP
Sección titulada «Baseline OWASP»- Headers seguros (
X-Content-Type-Options,X-Frame-Options, CSP, HSTS). - CORS con allowlist explícita (no
*en producción). - Rate limit por IP y por
workspace_id; límite de tamaño de body. - Webhooks firmados (HMAC) — WhatsApp y Mercado Pago.
- Secrets solo por variables de entorno (nunca en código);
gitleaksen pre-commit. - Logging estructurado con
request_idyworkspace_id.