Pre-flight checks — validando o laboratório antes das execuções¶
Leia no seu idioma: English · Português · Español
Status do escopo (pós-congelamento de escopo 2026-05-10) — Ver ARCHITECTURE.md para os 37 MÓDULOs canônicos + 7 Test Kinds + arquitetura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cobrem adições pós-Freeze. O motor de Pre-flight checks é um validador read-only que executa contra os dispositivos DUT API registrados ANTES do operador disparar a execução de um Test Plan. Ele captura cedo as condições de "lab fora do estado esperado" para que execuções não produzam dados forensicamente inúteis.
O princípio: garbage in, garbage out. Se o NGFW tem mudanças de deploy pendentes, ou se a política de decrypt está desligada quando o plan exige decrypt-on, os números de p99 resultantes não dizem nada de útil. O pre-flight recusa iniciar a execução em vez de permitir que ela produza dados enganosos.
Como se encaixa no fluxo do operador¶
Operator picks plan → Runs preflight → Reviews failures → Fixes lab state →
Triggers snapshot → Re-runs preflight → All green → Starts the actual test run
O pre-flight é invocado manualmente hoje (POST endpoint). Em um PR futuro (PR-D), o motor de Test Plan vai gatear o run-start em um preflight bem-sucedido automaticamente.
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"}'
Resposta (sucesso — 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"
}
Resposta (qualquer check falhou — 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 (atual)¶
| Check ID | Aplica-se a | Endpoint label | O que valida |
|---|---|---|---|
ngfw-deploy-clean |
Cisco FTD | deploy_status |
state == 'DEPLOYED' (sem mudanças pendentes) |
ngfw-decrypt-state-matches-plan |
Cisco FTD + Fortinet | decrypt_policy |
Se o plan exige decrypt-on, ao menos uma regra configurada; se decrypt-off, zero regras |
ntp-source-configured |
Todos os vendors | ntp_config |
Dispositivo tem ao menos um servidor NTP configurado |
ngfw-ha-state-sane |
Cisco FTD | ha_status |
Estado HA é um de ACTIVE / STANDBY_READY / NEGOTIATION / JOIN |
snapshot-fresh |
Todos os vendors | system_info |
Snapshot mais recente tem menos de 60 min |
O catálogo é extensível — adicionar um novo check é anexar uma entrada em lib/preflight/checks.ts. Sem mudanças no engine.
O que os checks retornam¶
Cada check retorna um de três estados:
| Resultado | Significado | Ação do operador |
|---|---|---|
| pass: true + evidence | Check avaliado contra um snapshot, tudo certo | Nenhuma — prossiga |
| pass: false + evidence | Check avaliado contra um snapshot, FALHA | Corrija o estado do dispositivo, dispare um snapshot manual, re-execute |
| pass: false + evidence: null | Skipped — não existe snapshot para esse dispositivo + label | Dispare um snapshot manual primeiro |
Evidence é o campo mais importante — ele cita o SHA-256 exato do snapshot + collected_at. O mesmo SHA-256 vai aparecer nos anexos do Test Run Report quando o PR-D for entregue, então o chain-of-custody fica intacto.
Por que pre-flight importa¶
Sem pre-flight, este é um cenário típico:
O operador dispara BASELINE-SLO-30M esperando decrypt-on. O NGFW teve sua política de decrypt desabilitada por outro engenheiro 30 minutos atrás. A execução de 30 minutos completa; o p99 parece suspeitosamente baixo. O operador só percebe que algo está errado ao comparar com a execução da semana passada. A run é inválida. O engagement perde 30 min + a credibilidade do relatório.
Com pre-flight:
O operador roda preflight primeiro. O check
ngfw-decrypt-state-matches-planfalha: "plan requires decrypt-on but no decrypt rules configured". O operador abre o console do NGFW (ou dispara uma write-op via a API futura), habilita decrypt, snapshot, re-roda preflight, tudo verde, inicia a run. Os 30 minutos são gastos em uma execução válida.
Fluxo do operador — sequência 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
Adicionando um novo check¶
O catálogo de checks em lib/preflight/checks.ts é data-driven. Para adicionar um 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'` };
}
}
Sem mudanças no engine. O runner descobre o novo check automaticamente.
Limitações¶
Escopo honesto:
- Read-only — pre-flight NÃO dispara snapshots por conta própria. O operador os dispara via o endpoint existente
POST /api/admin/dut/devices/{id}/snapshot - Snapshot stale tolerado até 60 min — o check
snapshot-freshfalha se mais antigo. Ajuste editando o check, OU rode um snapshot novo antes do preflight - Sem run-blocking automático ainda — PR-D vai integrar o preflight ao fluxo de run-start do Test Plan (recusar iniciar se o preflight falhar)
- Checks de Cisco UCS ainda não conectados — o adapter UCS está na fila do PR #199. Quando mergeado, checks específicos de UCS (sem critical faults, thermal sane) serão adicionados
- Sem write/remediation — pre-flight reporta estado mas não corrige. F-1 / F-2 (write ops) no API_FEATURE_CATALOG.md cobrem essa capacidade futura
O que o pre-flight NÃO substitui¶
- Julgamento do operador para preocupações não-checáveis (conexões de cabo, camada física, contratos de suporte de vendor)
- O TLS Decrypt Mode Probe (que é independente do estado da API — o probe pode detectar "decrypt está configurado mas de algum modo não está realmente decifrando tráfego", o que checks só-de-API não conseguem)
- Verificação de time-sync (script separado
check-time-sync.sh— pre-flight eventualmente vai chamá-lo como um check)
Relacionados¶
DUT_API_INTEGRATION.pt-BR.md— qual integração de API os checks consomemDUT_API_OPERATIONS.pt-BR.md— como registrar dispositivos que o pre-flight inspecionaAPI_FEATURE_CATALOG.pt-BR.md— pre-flight checks correspondem aos itens da categoria A, A-1 a A-7TEST_PLANS.pt-BR.md— os plans contra os quais o pre-flight validaTIME_SYNC.pt-BR.md— gate de time-sync separado; pre-flight vai integrá-lo em um follow-up