ADR-033: CI completamente offline — cero descargas durante la ejecución¶
Estado: aceptado
Contexto¶
El pipeline de CI actual (docs-ci.yml) ejecuta varios pasos en un contenedor Docker pre-construido. Durante la ejecución:
mkdocs buildconstruye el sitio a partir de los archivos del repositoriolycheeverifica enlaces (tanto internos como externos)validate_metadata.pyycheck_orphan_pages.pyvalidan el contenido
Todas las herramientas están pre-instaladas en la imagen Docker (ci-docs:latest). Sin embargo, lychee realiza peticiones HTTP a enlaces externos durante la verificación, lo que implica acceso a internet.
Además, la generación de contenido dinámico (generate_dynamic_content.py) usa git log para extraer novedades, lo cual funciona offline sobre el historial local.
Decisión¶
-
Cero descargas: ninguna etapa del CI debe ejecutar
pip install,apt-get,curl,wget,git clone,git fetch,git pullni cualquier comando que requiera acceso a red para obtener dependencias o herramientas. Todo el software necesario debe estar pre-instalado en la imagen Docker. -
Imagen Docker como fuente única de herramientas:
scripts/validate_metadata.pyyscripts/check_orphan_pages.pyse copian en la imagen durante su construcción, no se obtienen del checkout. Esto asegura que el CI funcione incluso si el commit no incluye esos scripts. -
Contenido generado en el build, no en el repositorio: el contenido dinámico (
_includes/) se genera durante el build mediantegenerate_dynamic_content.py, pero se almacena fuera dedocs/para que MkDocs no lo trate como páginas y no genere advertencias de enlaces rotos en modo--strict. -
Lychee como paso opcional con degradación: la verificación de enlaces externos requiere acceso a internet por naturaleza. Si el entorno CI está offline,
lycheefallará en enlaces externos pero no debe bloquear el despliegue. Para entornos completamente aislados, se usarálychee --offline(solo enlaces internos). -
Principio de portabilidad: la imagen Docker debe poder reconstruirse desde cero en cualquier máquina con acceso a internet, y una vez construida, el CI debe ejecutarse sin acceso a red.
Alternativas consideradas¶
A. Descargar dependencias en cada ejecución del CI¶
Usar pip install -r requirements.txt en el paso de CI en lugar de pre-instalar en la imagen Docker.
Descartada: añade latencia innecesaria, depende de PyPI externo, y viola el principio de cero descargas durante la ejecución.
B. Usar GitHub Actions con setup-python¶
Delegar la instalación de herramientas al runner de CI en cada ejecución.
Descartada: no es aplicable (usamos Forgejo Actions con imagen propia), y viola el mismo principio.
C. No verificar enlaces externos¶
Eliminar lychee del pipeline.
Descartada: la verificación de enlaces es valiosa. Se mantiene con la opción de modo offline cuando sea necesario.
Consecuencias¶
Positivas¶
- CI determinista: cada ejecución usa exactamente las mismas versiones de herramientas
- Rápido: sin pasos de instalación, el CI arranca inmediatamente
- Portable: la imagen Docker contiene todo lo necesario
- Resiliente: el CI funciona incluso si PyPI, GitHub o cualquier CDN externa están caídos
Negativas¶
- Imagen más grande: la imagen Docker incluye todas las dependencias (~500 MB)
- Actualización manual: cambiar una versión de herramienta requiere reconstruir y subir la imagen
- Lychee limitado offline: sin internet, solo verifica enlaces internos
Neutrales¶
- Los scripts (
validate_metadata.py,check_orphan_pages.py) deben mantenerse sincronizados entre el repositorio y la imagen Docker - El contenido dinámico generado depende de
git log, que funciona offline sobre el historial clonado durante el checkout
Verificación¶
| Check | ¿Requiere internet? | Modo offline |
|---|---|---|
properdocs build --strict |
No | ✅ Funciona |
generate_dynamic_content.py |
No | ✅ Usa git log local |
validate_metadata.py |
No | ✅ Solo lee archivos |
check_orphan_pages.py |
No | ✅ Solo lee archivos |
lychee (enlaces internos) |
No | ✅ lychee --offline |
lychee (enlaces externos) |
Sí | ⚠️ Requiere red |