Saltar a contenido

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 build construye el sitio a partir de los archivos del repositorio
  • lychee verifica enlaces (tanto internos como externos)
  • validate_metadata.py y check_orphan_pages.py validan 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

  1. Cero descargas: ninguna etapa del CI debe ejecutar pip install, apt-get, curl, wget, git clone, git fetch, git pull ni cualquier comando que requiera acceso a red para obtener dependencias o herramientas. Todo el software necesario debe estar pre-instalado en la imagen Docker.

  2. Imagen Docker como fuente única de herramientas: scripts/validate_metadata.py y scripts/check_orphan_pages.py se 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.

  3. Contenido generado en el build, no en el repositorio: el contenido dinámico (_includes/) se genera durante el build mediante generate_dynamic_content.py, pero se almacena fuera de docs/ para que MkDocs no lo trate como páginas y no genere advertencias de enlaces rotos en modo --strict.

  4. 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, lychee fallará en enlaces externos pero no debe bloquear el despliegue. Para entornos completamente aislados, se usará lychee --offline (solo enlaces internos).

  5. 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) ⚠️ Requiere red