Compatibilidad y política de soporte¶
Qué versiones están probadas, qué significa "soportada", y qué pasa cuando publicas una versión nueva.
Matriz de compatibilidad¶
Medida, no supuesta. La tabla se genera con
python tools/compat_matrix.py, que crea un entorno virtual por cada
combinación, instala el paquete y comprueba que el middleware:
- se puede añadir a la app,
- bloquea un ataque (403),
- deja pasar una petición legítima (200),
- y pone las cabeceras de seguridad también en el rechazo.
Además, en cada combinación se ejecuta el test diferencial del body
(tools/diferencial_body.py): la misma petición con y sin middleware, contra
Starlette y FastAPI, para comprobar que el middleware y la aplicación
interpretan el body igual. Es el mismo código que corre en la suite, así que
lo que se mide en cada versión es exactamente lo que se mide en la última.
Starlette¶
| Versión | Ataque y 200 | Diferencial del body |
|---|---|---|
| 0.23.0 (mínimo) | ✅ | ✅ |
| 0.27.0 | ✅ | ✅ |
| 0.37.0 | ✅ | ✅ |
| 0.41.3 | ✅ | ✅ |
| 0.46.2 | ✅ | ✅ |
| última (1.10.0) | ✅ | ✅ |
El mínimo es 0.23.0. Antes era 0.37.0, y eso rompía a quien usara
FastAPI 0.103.x: al instalar Gatekeeper, pip subía Starlette por encima de
0.28 y FastAPI dejaba de funcionar. El middleware solo usa
MutableHeaders, JSONResponse y los tipos ASGI, que son estables desde hace
años.
FastAPI¶
| Versión | Starlette que trae | Ataque y 200 | Diferencial del body |
|---|---|---|---|
| 0.103.2 | 0.27.0 | ✅ | ✅ |
| 0.110.3 | 0.37.2 | ✅ | ✅ |
| 0.115.6 | 0.41.3 | ✅ | ✅ |
| última (0.162.0) | 1.10.0 | ✅ | ✅ |
Python¶
| Versión | Probada en CI |
|---|---|
| 3.10 | ✅ (mínimo declarado) |
| 3.11 | ✅ |
| 3.12 | ✅ |
| 3.13 | ✅ |
| 3.14 | ✅ (local, no en CI) |
Servidores ASGI¶
| Servidor | Probado en CI |
|---|---|
| uvicorn | ✅ |
| hypercorn | ✅ |
| daphne | ✅ |
Probados como procesos reales con peticiones HTTP por socket
(tests/test_servidores_asgi.py), no solo con TestClient.
Redis (para el rate limit compartido)¶
| Versión | Probada |
|---|---|
| 5.0 | ✅ |
| 7.2 | ✅ |
Dependencias opcionales¶
| Extra | Versión mínima | Para qué |
|---|---|---|
yaml |
PyYAML 6 | Config.from_yaml() |
redis |
redis 5.0 | Rate limit compartido entre workers |
servers |
— | hypercorn y daphne, para las pruebas |
Por qué no hay cota superior de Starlette
Acotarla rompería instalaciones legítimas: el middleware no usa ninguna API que haya cambiado, así que subir la versión de Starlette no debería romper nada. Si algún día lo hace, se verá en los tests de la matriz.
Qué significa "soportada"¶
Una versión está soportada si:
| Correcciones de seguridad | ✅ se aplican |
| Correcciones de errores | ✅ se aplican |
| Nuevas funcionalidades | ✅ se aplica |
| Compatibilidad hacia atrás | ✅ se mantiene dentro de la major |
| Soporte de bugs sin corregir | ❌ no se promete |
"soportada" significa que no se rompe a propósito. No significa que responda en un plazo concreto.
Versiones mantenidas¶
| Rama | Estado | Recibe |
|---|---|---|
| 0.4.x | Activa | Todo: seguridad, errores, nuevas features |
| 0.3.x | Histórica (nunca publicada en PyPI) | Solo correcciones de seguridad críticas |
| 0.2.x | Histórica (nunca publicada en PyPI) | Solo correcciones de seguridad críticas |
| 0.1.x | Histórica (nunca publicada en PyPI) | Nada |
Al sacar la 0.5.0, la 0.4.x pasa a histórica y la 0.3.x deja de recibir correcciones. Eso se anuncia en el CHANGELOG y en las release notes.
Por qué la serie publicada empieza en 0.4.0
Las versiones 0.1.x a 0.3.x nunca se publicaron en PyPI: el paquete se
instalaba desde el repositorio. Empezar la serie publicada en 0.4.0 evita
la confusión de "instalo gatekeeper-asgi==0.3.1 y no existe". Los
números de versión antiguos siguen siendo válidos en el CHANGELOG, como
historial.
Una major es un corte
Al cambiar de major (0.3 → 0.4), se puede cambiar la configuración por defecto, quitar opciones o cambiar el comportamiento. Por eso hay notas de migración y por eso la versión menor (0.3.1 → 0.3.2) no rompe nada: solo añade y corrige.
Compatibilidad de la API¶
Gatekeeper sigue SemVer:
- PATCH (0.3.1 → 0.3.2): correcciones y añadidos. No se rompe nada.
- MINOR (0.3.x → 0.4.0): features nuevas. Se puede depreciar algo (con aviso en el CHANGELOG y en la documentación), pero no se quita.
- MAJOR (0.x → 1.0): se puede quitar lo deprecado.
Qué se considera "API pública"¶
Lo que se puede usar desde fuera del paquete:
gatekeeper.Config |
Sus campos y sus valores por defecto |
gatekeeper.GatekeeperMiddleware |
El middleware y su constructor |
gatekeeper.scan, scan_all, scan_detailed |
Las funciones de escaneo |
gatekeeper.RULES, PACK_NAMES |
Los nombres de las familias |
La CLI: gatekeeper report |
Su interfaz y el formato JSON |
| Los eventos de auditoría | Sus nombres y sus campos |
| El formato del YAML de configuración | Las claves y sus valores |
Lo que no es API pública (puede cambiar sin aviso en una minor):
- Los detalles de
src/gatekeeper/que no estén en la lista de arriba. - El texto exacto de los patrones de las reglas.
- El orden de las familias en
RULES. - Los mensajes de los logs (el formato JSON sí es API).
- Los detalles del informe de
gatekeeper report(el JSON sí).
Los patrones de las reglas son implementacion, no API
Una regla puede cambiar para detectar mejor una evasion. Eso cambia qué se bloquea. Si dependes de un patrón concreto, dependes de una implementación: no es una API estable.
Depreciaciones¶
- Se anuncian en el CHANGELOG bajo "Deprecated".
- La documentación dice qué usar en su lugar.
- Se quitan una major después, como mínimo.
Notas de migración¶
Las cambios que rompen compatibilidad se documentan aquí, en el CHANGELOG y en las release notes del tag.
0.4.x¶
| Cambio | Qué hacer |
|---|---|
| El mínimo de Starlette baja a 0.23 | Ninguno. Antes (0.37) rompía FastAPI 0.103.x: al instalar Gatekeeper, pip subía Starlette y FastAPI dejaba de funcionar |
| Las cabeceras de seguridad también van en los rechazos (403/413/429/503) | Ninguno. Solo se añaden cabeceras. Si tu app las ponía también, la suya gana (el middleware no pisa lo que ya venía) |
| El puntero JSON se recorta a 256 caracteres | Si parseas punteros completos, deja de poder contar con la ruta entera. exclude_fields sigue funcionando |
Nuevo extra servers (hypercorn, daphne) |
Ninguno. Es opcional |
Sobre el recorte del puntero JSON
Un JSON con más de 64 niveles de anidamiento produce punteros recortados
(/bio/…/nivel). El motivo es un DoS medido: sin recorte, un body de 83
KiB consumía 193,6 MiB. exclude_fields sigue funcionando (compara por
el primer y el último segmento). Ver
SECURITY_REVIEW.md.
0.3.x (nunca publicada en PyPI)¶
| Cambio | Qué hacer |
|---|---|
monitor_only registra sin bloquear |
Ninguno: es opt-in |
inspect_cross_carrier combina query y body |
Ninguno: es opt-in |
trust_proxy desactivado por defecto |
Si usas un proxy: trust_proxy=True y trusted_proxy_cidrs con tus redes |
exclude_fields acepta globs |
Los nombres exactos siguen funcionando |
La política de deprecación se aplica desde 0.3
Antes de 0.3 no había releases en PyPI, así que no había a quién deprecar. Desde 0.3.0, cada cambio incompatible tiene que venir con su nota de migración.
Proceso de release¶
- Preparar: actualizar el CHANGELOG (mover "Sin publicar" a la versión
nueva), actualizar el número de versión en
pyproject.toml. - Verificar: el CI tiene que estar verde (tests, cobertura, corpus, auditoría de dependencias, paquete).
- Etiquetar:
git tag -a vX.Y.Z -m "Gatekeeper X.Y.Z"y subirlo (git push origin vX.Y.Z). - Publicar: crear la release en GitHub con ese tag (o publicarla desde
la CLI con
gh release create vX.Y.Z). El workflowpublicar.ymlconstruye el wheel y el sdist y los sube a PyPI con Trusted Publishing (OIDC). No hay ningún token en los secretos del repositorio. - Anunciar: release notes en GitHub con los puntos de la tabla de migración.
El tag NO publica: la release sí
publicar.yml se activa con release: published (o a mano con
workflow_dispatch), no con un tag. Si solo haces git push origin
v0.4.1 no se publica nada: hay que crear la release en GitHub. El
workflow comprueba que el tag coincida con la versión de pyproject.toml
y falla si no, así que un tag equivocado no puede publicar una versión
que no es.
Reproducir una publicación en local¶
python -m build
twine check dist/*
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
Prueba primero en TestPyPI: es una instalación de verdad, sin consecuencias.
Cómo reportar un problema¶
- Errores y features: GitHub Issues.
- Vulnerabilidades: canal privado, ver SECURITY.md. No abras un issue público con un fallo explotable.
- Falsos positivos: valen como issue. Di el campo, la regla que saltó y el patrón de la petición. Con eso se puede ajustar.
Un falso positivo con detalle se arregla rápido
El evento de auditoría lleva rule, field y pattern: con eso se sabe
exactamente qué firió y dónde. gatekeeper report lo agrega.
Limitaciones conocidas¶
- La detección por regex tiene falsos positivos y negativos: se miden y se publican, no se ocultan.
multipart/form-datay los cuerpos binarios no se inspeccionan.- Las reglas propias del usuario no están acotadas contra ReDoS.
- El rate limit en memoria se multiplica por el número de workers.
- No sustituye a consultas parametrizadas, autenticación ni autorización.
La lista completa, con el porqué de cada una, está en Modelo de amenazas y en SECURITY_REVIEW.md.