Files
fn_registry/docs/capabilities/flow-replay.md
T
egutierrez 8742cb25be feat(browser): auto-commit con 60 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-07 11:42:31 +02:00

6.9 KiB

Flow Replay — Guardar un flujo web como función reproducible

Tag: flow-replay. Grupo de funciones para convertir un flujo de navegador que se hizo una vez a mano (login en un panel, reiniciar un servidor, rellenar un formulario) en una función del registry reproducible sin intervención. Materializa la doctrina del issue 0087: el registry crece promoviendo secuencias repetidas a operaciones de un solo paso.

Filtro MCP: mcp__registry__fn_search query="" tag="flow-replay".

Complementa al grupo web-proxy: web-proxy graba el tráfico, flow-replay lo destila y reproduce.

El patrón: grabar → destilar → reproducir

Tres fases, con una jerarquía de reproducción de más barato a más caro:

Fase 0 — GRABAR (una vez, siempre con browser + proxy)
  web_proxy ON  →  haces la acción a mano en el navegador  →  exportas el tramo a HAR
  (funciones del grupo web-proxy: start_mitm_capture, launch_chromium_proxy, query_mitm_flows --har)

Fase 1 — DESTILAR (del HAR a una secuencia de requests)
  har_filter_flows   → descarta estáticos/analytics, deja los flujos que importan
  har_extract_calls  → normaliza cada flujo a una "call spec" reproducible (método, url,
                       headers, cookies, body), aislando los datos de auth

Fase 2 — REPRODUCIR, en orden de preferencia:
  Nivel 1  HTTP puro       http_replay_sequence — rápido, headless, scriptable. PREFERIDO.
  Nivel 2  headless chromium (fallback)  — cuando hay token dinámico firmado en cliente,
                            challenge JS o WAF con fingerprint de navegador. Reutiliza
                            cdp_extract_recipe + cdp_save_storage_state (ver Fronteras).
  Nivel 3  chromium visible + acciones humanizadas — último recurso si headless es detectado
                            (cdp_click_xy_human, cdp_move_mouse_human del dominio browser).

La función-acción concreta que guardas en el registry (reboot_<panel>_server, login_<panel>, etc.) envuelve el nivel que funcione: idealmente una llamada a http_replay_sequence con su secuencia + parámetros, y los secretos resueltos desde pass/vault.

Funciones del grupo

ID Firma corta Qué hace
har_filter_flows_py_cybersecurity har_filter_flows(har, *, hosts, methods, drop_static, drop_analytics) -> list[dict] Filtra un HAR: descarta recursos estáticos y hosts de telemetría, deja los flujos candidatos a "acción". Pura.
har_extract_calls_py_cybersecurity har_extract_calls(entries, *, drop_headers) -> list[dict] Convierte entries HAR en "call specs" normalizadas (método/url/headers/cookies/body/body_type), aislando cookies de auth y descartando headers hop-by-hop. Pura.
http_replay_sequence_py_infra http_replay_sequence(calls, *, params, extract, timeout_s, verify_tls, allow_redirects, base_headers) -> dict Motor de replay HTTP: ejecuta la secuencia compartiendo cookie jar, substituye {{param}} y extrae valores de una respuesta para inyectarlos en pasos siguientes (flujo CSRF-like). Impura.

Ejemplo canónico end-to-end

Destilar un HAR capturado y reproducir el flujo sin navegador. Las tres funciones se encadenan; la extracción del paso 1 (un token) se inyecta en el paso 2:

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from cybersecurity.har_filter_flows import har_filter_flows
from cybersecurity.har_extract_calls import har_extract_calls
from infra.http_replay_sequence import http_replay_sequence

# 1. HAR exportado por:  query_mitm_flows ~/captures/traffic-*.mitm --har ~/sesion.har
import json
har = json.load(open(os.path.expanduser("~/sesion.har")))

# 2. Destilar: del ruido a la secuencia mínima
flows = har_filter_flows(har, hosts=["panel.midominio.com"])   # solo el host del panel
calls = har_extract_calls(flows)                                # call specs reproducibles

# 3. Reproducir (Nivel 1, HTTP puro). El token del GET inicial se inyecta en el POST.
res = http_replay_sequence(
    calls,
    params={"server_id": "vps-42"},                            # parametrizado por el caller
    extract=[{"from": 0, "type": "json", "expr": "csrf", "as": "csrf"}],
    verify_tls=True,
)
print(res["status"], [s["status_code"] for s in res["steps"]])

Una vez validado, el flujo se promueve a una función-acción nombrada del registry (p. ej. reboot_vps_server_<panel>) que internamente llama a http_replay_sequence con su secuencia fija, recibe los parámetros del caller y resuelve los secretos desde pass. Esa función-acción es lo que el agente invoca en un solo paso a partir de entonces.

Fronteras

  • No graba: la captura es del grupo web-proxy. Este grupo empieza con un HAR ya existente.
  • No auto-parametriza (todavía). har_extract_calls normaliza pero NO detecta solo qué valor es un token dinámico ni dónde se reinyecta. La parametrización ({{param}}) y las reglas de extract las decide el humano/agente leyendo el HAR. La detección automática de tokens/CSRF sería una función nueva del grupo, no una ampliación.
  • No incluye el runner de Nivel 2/3 (browser fallback). Está especificado en el patrón pero no implementado: cuando un flujo real falle en HTTP puro, se construye un "action recipe" reutilizando casi entero cdp_extract_recipe_py_pipelines (mismo formato YAML, steps de acción en vez de extracción) + cdp_save_storage_state_go_browser para saltarse el login. No se construye por adelantado (KISS / registry-first).
  • No gestiona secretos: los secretos viajan como {{param}} desde pass/vault. El grupo nunca los hardcodea ni los persiste.

Gotchas (seguridad — leer antes de usar)

  • El HAR es sensible: contiene cookies y tokens en crudo. Trátalo como un secreto — gitignored, no subir a Gitea, no indexar, borrar tras destilar. El output de har_extract_calls también lleva esos valores hasta que los sustituyes por {{param}}.
  • Secretos a pass/vault, nunca en el código de la función-acción.
  • Replay con efectos = peligroso: reproducir un POST que reinicia, borra o paga es destructivo. La función-acción debe pedir confirmación o exponer un flag explícito (--yes/confirm=True) antes de disparar. Nunca replay ciego de una acción irreversible.
  • HTTP puro no siempre reproduce: token firmado en cliente, challenge JS, o WAF que exige fingerprint de navegador → cae a Nivel 2 (headless) o 3 (visible humanizado).
  • http_replay_sequence sigue redirects por defecto y verify_tls=True. La extracción JSON es dot-path simple (a.b.0.c), no JSONPath completo.

Prerequisitos

  • Fase 0 (grabar): grupo web-proxy operativo (mitmproxy + chromium). Ver su página.
  • Fase 1-2: requests en python/.venv (ya presente). Sin dependencias nuevas.