Incidente s58 — Help Widget incomunicado tras endurecimiento CF Access (s57)
Incidente s58 — Help Widget incomunicado tras endurecimiento CF Access (s57)
Resumen ejecutivo
El 12 de mayo de 2026 (sesión 58), Edu detectó que el Help Widget de CreaRack Pro estaba completamente incomunicado en producción. Los síntomas eran:
- “Could not connect to the assistant” al hacer preguntas al asistente IA.
- “El panel no muestra documentación” al abrir la lista de artículos.
Sin afectación a usuarios reales — Edu lo detectó antes de que cargara ningún usuario. Resuelto en la misma sesión mediante PR #26 (hotfix d20).
Línea temporal
| Hora (aprox.) | Evento |
|---|---|
| s57 (11-12 mayo) | Se elimina bypass-everyone de las apps CF Access “Workspace MCP API” y “API Biblioteca”. Service Token distribuido a 8 workflows + 6 scripts + crons. |
| s57 | core/api_help.py y scripts/harness/bib_report_check.py NO incluidos en el audit de callers. |
| s58 inicio | Edu detecta síntomas al usar el Help Widget en PROD. |
| s58 — PR #26 | Hotfix: _workspace_headers() inyecta CF Access headers cuando están configurados. |
| Post-merge | Edu configura CF_ACCESS_CLIENT_ID + CF_ACCESS_CLIENT_SECRET en Dokploy y redeploya PROD. |
Causa raíz
En s57 se endureció CF Access (quitar bypass-everyone) en dos apps:
- “Workspace MCP API” — proxea
workspace.crearack.com/api/mcp/* - “API Biblioteca” — proxea
workspace.crearack.com/api/biblioteca/*
El audit de callers de s57 cubrió correctamente los callers batch (5 sitios: GitHub workflows, scripts CLI, crons). Pero omitió los callers Django runtime de PROD:
core/api_help.py→ 3 llamadas: proxybib_ask(/api/mcp), traducciones EN (/api/biblioteca/wiki-titles), lista artículos (/api/biblioteca/wiki).scripts/harness/bib_report_check.py→ 2 llamadas:/api/biblioteca/recent-reportsy/api/biblioteca/skip-log.
A partir de s57, todas esas llamadas devolvían 403/302 porque no presentaban CF-Access-Client-Id + CF-Access-Client-Secret.
Impacto
| Dimensión | Detalle |
|---|---|
| Severidad | Alta (funcionalidad core del Help Widget completamente rota en PROD) |
| Afectación usuarios | Nula (detectado antes de carga real de usuarios) |
| Duración | Desde s57 hasta fix en s58 (~1 sesión de trabajo) |
| Componentes afectados | Help Widget (proxy bib_ask, lista artículos, traducciones), pre-commit hook bib_report_check |
Fix aplicado (PR #26)
core/api_help.py — _workspace_headers()
def _workspace_headers():
token = getattr(settings, "WORKSPACE_MCP_TOKEN", "")
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
cf_id = getattr(settings, "CF_ACCESS_CLIENT_ID", "")
cf_secret = getattr(settings, "CF_ACCESS_CLIENT_SECRET", "")
if cf_id and cf_secret:
headers["CF-Access-Client-Id"] = cf_id
headers["CF-Access-Client-Secret"] = cf_secret
return headers
Un solo helper cubre los 3 callers del Help Widget que usaban _workspace_headers().
scripts/harness/bib_report_check.py — _cf_access_headers()
Helper análogo que lee CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET de env vars y los inyecta en las 2 funciones que llaman a la API Biblioteca.
Settings y compose
config/settings/base.py: declaraCF_ACCESS_CLIENT_IDyCF_ACCESS_CLIENT_SECRET(default vacío → compatible con dev local).compose.yml+compose.prod.yml: propagan las 2 env vars al contenedorweb.
Pasos manuales post-merge (PROD)
- Configurar
CF_ACCESS_CLIENT_IDyCF_ACCESS_CLIENT_SECRETen Dokploy panel del stack PROD. - Redeploy de PROD desde Dokploy.
- Verificar Help Widget: preguntar algo (proxy
/api/mcp) + abrir lista de artículos (/api/biblioteca/wiki). - Configurar las 2 env vars en PowerShell local de cada miembro del staff (para pre-commit hook al 100%).
Lección aprendida
Cuando se endurezca CF Access (quitar
bypass-everyoneo equivalente), el audit de callers debe incluir explícitamente los callers Django runtime, no solo workflows/scripts batch. Los callers de Django en PROD no aparecen en los workflows de GitHub — hay que revisar activamente los archivosapi_*.pyy scripts que llamen aworkspace.crearack.com.
Lección registrada en CHANGELOG.md (Lección s58) y RELEASE_NOTES.md v1.0.73 hotfix.
Véase también
- [[decision—20260512—cf-access-callers-django-runtime]]