Skip to content

Pre-flight checks — validando el laboratorio antes de las ejecuciones

Estado del alcance (post-congelación de alcance 2026-05-10) — Ver ARCHITECTURE.md para los 37 MÓDULOs canónicos + 7 Test Kinds + arquitectura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cubren adiciones post-Freeze.

Lea en su idioma: English · Português · Español

El motor de Pre-flight checks es un validador read-only que se ejecuta contra los dispositivos DUT API registrados ANTES de que el operador dispare la ejecución de un Test Plan. Detecta tempranamente las condiciones de "lab fuera del estado esperado" para que las ejecuciones no produzcan datos forensemente inútiles.

El principio: garbage in, garbage out. Si el NGFW tiene cambios de deploy pendientes, o la política de decrypt está apagada cuando el plan exige decrypt-on, los números de p99 resultantes no dicen nada útil. El pre-flight rehúsa iniciar la ejecución en lugar de permitir que produzca datos engañosos.

Cómo encaja en el flujo del operador

Operator picks plan → Runs preflight → Reviews failures → Fixes lab state →
Triggers snapshot → Re-runs preflight → All green → Starts the actual test run

El pre-flight es invocado manualmente hoy (POST endpoint). En un PR futuro (PR-D), el motor de Test Plan condicionará el run-start a un preflight exitoso automáticamente.

API

POST /api/test-runs/preflight

curl -X POST "https://dashboard.example/api/test-runs/preflight" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "content-type: application/json" \
  -d '{"planIdentifier": "BASELINE-SLO-30M"}'

Respuesta (éxito — 200):

{
  "planIdentifier": "BASELINE-SLO-30M",
  "ranAt": "2026-05-06T14:35:00.000Z",
  "checksRun": 8,
  "checksPassed": 8,
  "checksFailed": 0,
  "checksSkipped": 0,
  "pass": true,
  "checks": [
    {
      "checkId": "ngfw-deploy-clean",
      "description": "NGFW deploy state is DEPLOYED — no pending config changes",
      "deviceHostname": "ftd-1.lab.example.com",
      "vendor": "cisco-ftd",
      "pass": true,
      "detail": "state=DEPLOYED — no pending changes",
      "evidence": {
        "snapshotId": "...",
        "payloadSha256": "abc123...",
        "collectedAt": "2026-05-06T14:34:42.000Z"
      }
    },
    ...
  ],
  "summary": "8/8 checks passed — lab is ready for plan BASELINE-SLO-30M"
}

Respuesta (algún check falló — 422):

{
  "planIdentifier": "BASELINE-SLO-30M",
  "ranAt": "2026-05-06T14:35:00.000Z",
  "checksRun": 8,
  "checksPassed": 6,
  "checksFailed": 1,
  "checksSkipped": 1,
  "pass": false,
  "checks": [
    ...
    {
      "checkId": "ngfw-decrypt-state-matches-plan",
      "deviceHostname": "ftd-1.lab.example.com",
      "vendor": "cisco-ftd",
      "pass": false,
      "detail": "plan requires decrypt-on but no decrypt rules configured",
      "evidence": { ... }
    }
  ],
  "summary": "1 check(s) failed, 1 skipped (missing snapshots) — review details"
}

Catálogo de checks (actual)

Check ID Aplica a Endpoint label Qué valida
ngfw-deploy-clean Cisco FTD deploy_status state == 'DEPLOYED' (sin cambios pendientes)
ngfw-decrypt-state-matches-plan Cisco FTD + Fortinet decrypt_policy Si el plan exige decrypt-on, al menos una regla configurada; si decrypt-off, cero reglas
ntp-source-configured Todos los vendors ntp_config El dispositivo tiene al menos un servidor NTP configurado
ngfw-ha-state-sane Cisco FTD ha_status El estado HA es uno de ACTIVE / STANDBY_READY / NEGOTIATION / JOIN
snapshot-fresh Todos los vendors system_info El snapshot más reciente tiene menos de 60 min

El catálogo es extensible — agregar un nuevo check es anexar una entrada en lib/preflight/checks.ts. Sin cambios en el engine.

Qué retornan los checks

Cada check retorna uno de tres estados:

Resultado Significado Acción del operador
pass: true + evidence Check evaluado contra un snapshot, todo bien Ninguna — proceda
pass: false + evidence Check evaluado contra un snapshot, FALLO Corrija el estado del dispositivo, dispare un snapshot manual, re-ejecute
pass: false + evidence: null Skipped — no existe snapshot para este dispositivo + label Dispare un snapshot manual primero

Evidence es el campo más importante — cita el SHA-256 exacto del snapshot + collected_at. El mismo SHA-256 aparecerá en los anexos del Test Run Report cuando se entregue PR-D, así el chain-of-custody queda intacto.

Por qué importa el pre-flight

Sin pre-flight, este es un escenario típico:

El operador dispara BASELINE-SLO-30M esperando decrypt-on. El NGFW tuvo su política de decrypt deshabilitada por otro ingeniero hace 30 minutos. La ejecución de 30 minutos completa; el p99 luce sospechosamente bajo. El operador solo nota que algo anda mal al comparar con la ejecución de la semana pasada. La run es inválida. El engagement pierde 30 min + la credibilidad del informe.

Con pre-flight:

El operador corre preflight primero. El check ngfw-decrypt-state-matches-plan falla: "plan requires decrypt-on but no decrypt rules configured". El operador abre la consola del NGFW (o dispara una write-op vía la API futura), habilita decrypt, snapshot, re-corre preflight, todo en verde, inicia la run. Los 30 minutos se gastan en una ejecución válida.

Flujo del operador — secuencia completa

# 1. Confirm devices are registered
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
  "https://dashboard.example/api/admin/dut/devices"

# 2. Trigger fresh snapshots (so preflight sees current state)
for id in $(curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
  "https://dashboard.example/api/admin/dut/devices" \
  | jq -r '.devices[].id'); do
  curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
    "https://dashboard.example/api/admin/dut/devices/$id/snapshot"
done

# 3. Run pre-flight
curl -X POST "https://dashboard.example/api/test-runs/preflight" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "content-type: application/json" \
  -d '{"planIdentifier": "BASELINE-SLO-30M"}'

# 4. If pass: true → proceed with run trigger (existing flow)
# 5. If pass: false → review checks[].detail, fix the lab, go to step 2

Agregando un nuevo check

El catálogo de checks en lib/preflight/checks.ts es data-driven. Para agregar un check:

{
  id: 'my-new-check',
  description: 'What this check validates in operator-friendly prose',
  endpointLabel: 'system_info', // which snapshot label the check needs
  appliesTo: (device, plan) => {
    // Return true if this check is relevant for this device + plan combo
    return device.vendor === 'cisco-ftd' && plan.someField === 'someValue';
  },
  evaluate: (snapshot, plan) => {
    // Inspect snapshot.payloadJson and decide pass/fail
    const fieldValue = (snapshot.payloadJson as any)?.someField;
    if (fieldValue === 'expected') {
      return { pass: true, detail: 'value matches expectation' };
    }
    return { pass: false, detail: `value=${fieldValue}, expected 'expected'` };
  }
}

Sin cambios en el engine. El runner descubre el nuevo check automáticamente.

Limitaciones

Alcance honesto:

  • Read-only — el pre-flight NO dispara snapshots por sí mismo. El operador los dispara vía el endpoint existente POST /api/admin/dut/devices/{id}/snapshot
  • Snapshot stale tolerado hasta 60 min — el check snapshot-fresh falla si es más antiguo. Ajuste editando el check, O corra un snapshot fresco antes del preflight
  • Sin run-blocking automático aún — PR-D integrará el preflight al flujo de run-start del Test Plan (rehusará iniciar si el preflight falla)
  • Checks de Cisco UCS aún no conectados — el adapter UCS está en la cola del PR #199. Cuando se mergee, se agregarán checks específicos de UCS (sin critical faults, thermal sane)
  • Sin write/remediation — el pre-flight reporta estado pero no lo corrige. F-1 / F-2 (write ops) en el API_FEATURE_CATALOG.md cubren esa capacidad futura

Lo que el pre-flight NO reemplaza

  • El juicio del operador para preocupaciones no-checables (conexiones de cable, capa física, contratos de soporte de vendor)
  • El TLS Decrypt Mode Probe (que es independiente del estado de la API — el probe puede detectar "decrypt está configurado pero de algún modo no está realmente desencriptando tráfico", lo que los checks solo-de-API no pueden)
  • Verificación de time-sync (script separado check-time-sync.sh — el pre-flight eventualmente lo llamará como un check)

Relacionados