Volver a la wiki

Endpoint /api/tools/deps — API de frescura de dependencias

Fusionada en [[entity—functions—endpoint—tools-deps]] el 28-08-2026 (task #275). Las dos páginas documentaban el mismo endpoint GET/POST /api/tools/deps y se crearon con un segundo de diferencia el 28-05-2026. El contenido vivo está en la superviviente; esta queda como histórico.

Descripción

Endpoint Cloudflare Pages Function (functions/api/tools/deps/index.ts) que sirve la tabla de frescura de dependencias de CreaRack-Pro y el Workspace. Maneja dos operaciones:

Métodos

GET /api/tools/deps

Autenticación: CF Access (navegador, vía _middleware.ts)

Response: 200 OK

{
  "checked_at": "2026-05-28T19:55:42.123Z",
  "count": 147,
  "items": [
    {
      "repo": "crearack-pro",
      "ecosystem": "pypi",
      "manifest": "requirements.txt",
      "package": "requests",
      "pinned": "==2.28.0",
      "installed": "2.28.0",
      "latest": "2.31.0",
      "lag_kind": "major",
      "is_dev": 0,
      "vuln_count": 0,
      "vuln_ids": null,
      "vuln_severity": null,
      "manifests": "requirements.txt,tests/requirements.txt",
      "resolved": "2.31.0",
      "installed_source": "prod",
      "unbounded": 1,
      "unbounded_major": 0,
      "fix_within_spec": null,
      "checked_at": "2026-05-28T19:55:42.123Z"
    },
    ...
  ]
}

Ordenamiento: con aviso de seguridad primero (vuln_count > 0), dentro de ellos por severidad (critical=0 … unknown=4), luego lag_kind (major=0, minor=1, patch=2, unknown=3, uptodate=4) → repo → lower(package).

POST /api/tools/deps

Autenticación: Bearer token (MCP_TOKEN en _middleware.ts)

Request body:

{
  "items": [
    {
      "repo": "crearack-pro",
      "ecosystem": "pypi",
      "manifest": "requirements.txt",
      "package": "requests",
      "pinned": "==2.28.0",
      "installed": "2.28.0",
      "latest": "2.31.0",
      "lag_kind": "major",
      "is_dev": false,
      "manifests": "requirements.txt,tests/requirements.txt",
      "resolved": "2.31.0",
      "installed_source": "prod",
      "unbounded": true,
      "unbounded_major": false,
      "fix_within_spec": null
    },
    ...
  ]
}

Validaciones:

Campos del motor fiable (task #275, 28-08-2026 — migración 0052). Los payloads viejos no los traen y quedan en NULL/0, así que el endpoint sigue aceptando colectores anteriores:

CampoTipoQué guarda
manifeststexto o NULLTodos los manifiestos donde aparece el paquete, separados por coma (manifest sigue siendo el ganador tras deduplicar: el más restrictivo)
resolvedtexto o NULLMayor versión publicada que la horquilla pinned admite — la que se instalaría hoy en un despliegue limpio
installed_sourceprod | runner | lockfileDe dónde salió installed. Cualquier otro valor → NULL
unbounded0/1La horquilla no pone techo superior
unbounded_major0/1Sin techo y ya corriendo en un major distinto al declarado
fix_within_spec0/1/NULLTri-estado: 1 = hay versión con fix dentro de la horquilla (basta redeploy) · 0 = hay que cambiar el pin · NULL = OSV no publica versión con fix. Solo un booleano explícito se guarda como 0/1; ausente o basura → NULL

Response: 200 OK

{
  "inserted": 147,
  "checked_at": "2026-05-28T19:55:42.123Z"
}

Response: 400 Bad Request si body.items no es un array.

Operación en DB: Ejecuta en batch:

  1. DELETE FROM deps_freshness (limpia snapshot anterior).
  2. INSERT INTO deps_freshness (...) × N filas.
  3. Todas con checked_at = momento de la llamada.

Tabla D1 subyacente

Tabla: deps_freshness (migración 0042, ampliada por la 0048 y la 0052)

CREATE TABLE deps_freshness (
  id INTEGER PRIMARY KEY,
  repo TEXT NOT NULL,           -- 'crearack-pro' | 'workspace'
  ecosystem TEXT NOT NULL,      -- 'pypi' | 'npm'
  manifest TEXT NOT NULL,       -- ruta relativa del manifiesto
  package TEXT NOT NULL,
  pinned TEXT,                  -- spec del manifiesto (==6.0.4, ^9.3.0...)
  installed TEXT,               -- versión resuelta
  latest TEXT,                  -- última en PyPI/npm
  lag_kind TEXT NOT NULL CHECK (...),  -- 'major' | 'minor' | 'patch' | 'uptodate' | 'unknown'
  is_dev INTEGER NOT NULL,      -- 1 si es devDependency
  checked_at TEXT NOT NULL,
  -- 0048: eje de seguridad (OSV.dev)
  vuln_count INTEGER,           -- nº de avisos publicados para la versión en uso
  vuln_ids TEXT,                -- 'GHSA-...,PYSEC-...'
  vuln_severity TEXT,           -- la peor de la fila
  -- 0052: motor fiable (task #275)
  manifests TEXT,               -- todos los manifiestos donde aparece, coma
  resolved TEXT,                -- mayor versión publicada que 'pinned' admite
  installed_source TEXT,        -- 'prod' | 'runner' | 'lockfile'
  unbounded INTEGER NOT NULL DEFAULT 0,        -- la horquilla no pone techo
  unbounded_major INTEGER NOT NULL DEFAULT 0,  -- ...y ya corre en otro major
  fix_within_spec INTEGER       -- 1 redeploy basta · 0 cambiar pin · NULL sin fix
);

Índices:

Consumidores

Flujo temporal

GitHub Actions (semanal o manual)
  ↓
scripts/deps_freshness.py  (+ deps_specs.py, deps_sources.py)
  • Lee manifiestos de ambos repos
  • Consulta PyPI / npm (última publicada + lista completa de versiones)
  • Resuelve cada horquilla a la mayor versión que admite → `resolved`
  • Resuelve la "instalada": PROD real → runner del CI → lockfile
      · PROD: GET https://crearack.com/api/installed-packages (Bearer
        INTERNAL_TOOLS_TOKEN). Falla suave: si no contesta, cae al runner
  • Deduplica por (repo, ecosistema, paquete) — gana la horquilla más
    restrictiva; el resto de manifiestos queda en `manifests`
  • Cruza (instalada || resuelta) con OSV.dev → avisos, severidad y
    `fix_within_spec`
  • Calcula desfase semver y marca las horquillas sin techo
  ↓
POST /api/tools/deps + Bearer
  ↓
DELETE + INSERT batch en D1
  ↓
GET /api/tools/deps (navegador con CF Access)
  ↓
DepsPanel + DepsBadges → tabla filtrada, fuente de "en uso" y avisos

Véase también

Subir