Endpoint /api/installed-packages — versiones REALES instaladas en PROD
Descripción
GET /api/installed-packages es un endpoint interno de Django Ninja registrado en config/urls.py, introducido en task #275 (28-08-2026, v1.86.4). Devuelve las versiones Python REALMENTE instaladas en el contenedor que lo sirve — importlib.metadata.distributions() en vivo, no una resolución teórica.
Existe porque la tool “Dependencias” mostraba, en la columna “instalada”, lo que resolvía el runner de CI (un entorno limpio, sin relación con lo que corre en PROD) — y las horquillas sin techo (openai>=..., anthropic>=...) habían saltado de major sin que la página lo dijera. Este endpoint le da al colector una fuente de verdad real: ver [[entity—ci—service—deps-freshness-collector]].
Contrato
@api.get("/installed-packages", auth=_InternalToolsAuth(), tags=["meta"])
def installed_packages(request):
packages = {}
for dist in distributions():
name = (dist.metadata or {}).get("Name")
if name:
packages[name] = dist.version
return {"packages": packages, "count": len(packages), "python": platform.python_version()}
Respuesta: {"packages": {"<nombre>": "<version>", ...}, "count": <int>, "python": "<version>"}.
Autenticación
Reutiliza _InternalToolsAuth (HttpBearer, variable de entorno INTERNAL_TOOLS_TOKEN, mínimo 32 caracteres, deny-all si falta) — la misma clase que protege /api/openapi-export ([[entity—api—endpoint—openapi-export]]). No hay secret nuevo que gestionar: es el mismo token, ya desplegado en Dokploy PROD; solo falta darlo de alta como secret INTERNAL_TOOLS_TOKEN en GitHub Actions para que el workflow lo use (ver [[runbook—infra—deploy-internal-tools-token]]).
Consumidor
| Consumidor | Modo |
|---|---|
scripts/deps_freshness.py (fetch_prod_versions) | GET con Authorization: Bearer $INTERNAL_TOOLS_TOKEN, invocado desde [[entity—ci—workflow—deps-freshness]] con --prod-versions-url/--prod-token |
Si el endpoint no responde o el secret no está configurado en Actions, el colector cae sin romper a la versión que resuelve el runner de CI (installed_source = "runner").
Seguridad
- Sin acceso a base de datos ni sesión de usuario — solo metadata de paquetes Python instalados (nombre + versión), sin secrets ni datos de negocio.
- Mismo modelo de fallo seguro que
/openapi-export: token ausente o corto → 401 deny-all. - No aparece en
/api/docsSwagger UI (no habilitado en producción).
Véase también
- [[entity—api—endpoint—openapi-export]]
- [[entity—ci—service—deps-freshness-collector]]
- [[entity—ci—workflow—deps-freshness]]
- [[runbook—infra—deploy-internal-tools-token]]