0.6.2 (2026-09-26)¶
Release de endurecimiento: cierra huecos de seguridad en la API (confirmación de contraseña, CORS, CSP, límites de peticiones y auditoría), corrige el versionado que reportaba valores antiguos y devuelve el reporte de cobertura a los tests.
💥 Cambios incompatibles¶
PUT /api/v1/users/change-passwordahora exigecurrent_password. Antes bastaba con un token válido para fijar una contraseña nueva; ahora hay que confirmar la actual. Los clientes deben enviar ese campo junto anew_password.- Las cuentas que solo entran con un proveedor externo reciben 403 en ese endpoint. Su contraseña almacenada es un valor aleatorio que nadie conoce, así que no hay nada que confirmar: para crear una contraseña de acceso por correo usan el flujo de recuperación, que prueba el control de la dirección.
Alcance real de este cambio: el frontend incluido en esta versión ya envía el campo, así que actualizando todo junto la aplicación no se rompe. El impacto se limita a los consumidores directos de la API (scripts o integraciones) y a los despliegues donde frontend y backend se publican por separado — en ese caso conviene desplegar el frontend primero, porque un frontend anterior contra este backend seguiría recibiendo 400.
🔒 Seguridad¶
- Confirmación de contraseña actual en el cambio de contraseña, verificada en el servidor. Un token robado ya no permite fijar una contraseña y quedarse con la cuenta.
- CORS restringido a métodos y cabeceras explícitos, en lugar de comodines que aceptaban cualquier cabecera personalizada.
- Content-Security-Policy con política restrictiva en las respuestas del API cuando la aplicación corre en producción.
- Límites de peticiones por IP en los puntos expuestos: registro (20/hora), solicitudes de recuperación de contraseña (10/hora), verificación MFA (10 cada 5 minutos) y el endpoint público de renderizado (60/minuto). Todos responden
429con cabeceraRetry-After. - Tope de 100 000 caracteres en el código fuente que acepta el endpoint público de renderizado, que se ejecuta sin autenticación y sin consumir recursos del renderizador.
- El borrado de cuenta ya no devuelve el detalle interno del error: el mensaje al cliente es genérico y la excepción queda registrada en el servidor.
- Auditoría completa: los cuatro eventos que estaban definidos y nunca se registraban ahora se emiten — solicitud de recuperación de contraseña, MFA activado, MFA desactivado y cuenta eliminada.
🐛 Correcciones¶
- La versión que reportaba la API era incorrecta:
GET /anunciaba0.6.0con la 0.6.1 ya publicada. Ahora informa la versión real, igual que Swagger y el registro de Sentry. - Faltaba la sección
## [0.6.0]del CHANGELOG (su contenido estaba fusionado bajo 0.6.1) y la entrada de 0.6.1 no aparecía en la navegación de la documentación. - El reporte de cobertura no se generaba:
pytest.inianulaba en silencio la configuración depyproject.toml. La cobertura vuelve a medirse en cada corrida. backend/run-tests.shfallaba con--unity--integration(el flag se pasaba duplicado) y no podía ejecutarse dentro del contenedor porque arrancaba con#!/bin/bashy la imagen no incluye bash.- Un test de propiedades del chat de IA fallaba con entradas que contenían un marcador de fin en español: las precondiciones del test solo contemplaban los marcadores en inglés, mientras el extractor normaliza ambos idiomas. El test ahora cubre las cinco variantes.
- El escenario de MongoDB externo arrancaba el servidor de desarrollo: el
docker-compose.ymlforzabauvicorn --reloady nunca ejecutabastart.sh, así que ignorabaWORKERSy corría sin el trabajador de producción. Ahora arranca gunicorn (2 workers por defecto). - El instalador invitaba a abrir
/docsen instalaciones en modo producción, donde Swagger y ReDoc están desactivados por diseño. Ahora lo advierte y explica cómo habilitarlos. - Modo oscuro en la vista de planes del panel: los textos de la tabla de precios de cada plan (moneda y monto) y los modales de crear/editar plan usaban colores claros sin variante oscura, así que quedaban casi invisibles sobre la tarjeta oscura. Ahora respetan el tema.
📝 Documentación¶
- Publicar en un dominio: qué ajustar antes de exponer una instalación —
BACKEND_CORS_ORIGINS,FRONTEND_URLyVITE_API_URL, que sin cambios dejan el CORS y los retornos de Stripe apuntando alocalhost. Documentado enINSTALL.mdydeploy/README.md, con acceso desde los READMEs de cada escenario. - Plataformas gestionadas (DigitalOcean App Platform y similares): variables en el panel de la plataforma, frontend y backend como apps separadas,
KROKI_URLque debe ser alcanzable fuera de Docker, y la advertencia de que sin bind mounts cada cambio exige un nuevo build y despliegue.
🧪 Pruebas¶
- Umbral de cobertura del 45% en la corrida completa (base medida: 49.4%). Los subsets (
-m unit,-k …) quedan exentos a propósito, porque una suite parcial no puede alcanzar un umbral de todo el proyecto. - 29 pruebas nuevas: limitador compartido de ventana deslizante, throttling HTTP en registro, recuperación y MFA, tope de payload justo en el límite y por encima, y una prueba por evento de auditoría.
🔧 Interno¶
scripts/check-version.sh: verificación fail-closed de todos los archivos que llevan el número de versión (código, configuración, documentación, release notes, navegación y CHANGELOG). El checklist deVERSIONING.mdlo exige antes de cualquier merge de release.- Limitador de ventana deslizante compartido en
app/core/rate_limit.py, reutilizado por los módulos de usuarios, MFA y diagramas en lugar de duplicar la lógica.