Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

SOP Fan-In: Webhook

La puerta de enlace expone dos puntos de entrada HTTP autenticados para SOPs activados mediante webhooks:

  • POST /sop/{path} es exclusivo de SOP. Invoca un SOP coincidente y devuelve 404 cuando ningún SOP cargado declara esa ruta exacta. Nunca recurre a un agente ni a una llamada al modelo.
  • POST /webhook comprueba primero si existe un activador SOP exacto para /webhook. Si no hay ninguna coincidencia, mantiene el comportamiento normal del chat de webhook.

Ejecute estos endpoints a través de zeroclaw daemon con sop.sops_dir configurado. Usan el motor SOP compartido del demonio. Un zeroclaw gateway start independiente, o un demonio sin el subsistema SOP habilitado, devuelve 503 desde /sop/*.

Activador

Solicitud HTTP entrante. En producción: rutas de gateway /sop/* y rutas /webhook con prioridad SOP.

campotipopredeterminadosignificado
path*cadenaLa ruta de la solicitud coincidió exactamente con la ruta del evento.

Cargar y verificar el SOP:

Definir

Author the SOP como se describe en Syntax, con un desencadenador webhook. Los campos del desencadenador anteriores son las claves compatibles; la página recorre el archivo completo.

Validar

zeroclaw sop validate

Inspeccionar

zeroclaw sop list
zeroclaw sop show <name>

La coincidencia de la ruta es exacta. Por ejemplo:

[[triggers]]
type = "webhook"
path = "/sop/deploy"

se activa para POST /sop/deploy, pero no para /sop/deploy/ ni para /sop/deploy/production.

Solicitud y respuesta

/sop/* acepta un cuerpo vacío o cualquier valor JSON válido. La ruta de la solicitud se convierte en el tema del evento y el cuerpo JSON canónico se convierte en su carga útil. El JSON no válido devuelve 400.

Envía todos los controles configurados. Con gateway.require_pairing = true y gateway.webhook_secret establecido (la configuración que se muestra a continuación), una solicitud completa incluye ambos:

curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'Authorization: Bearer <paired-token>' \
  -H 'X-Webhook-Secret: <gateway.webhook_secret>' \
  -H 'Content-Type: application/json' \
  -H 'X-Idempotency-Key: deploy-2026-07-20-001' \
  -d '{"revision":"abc123"}'

Cuando solo hay un control configurado, envía únicamente ese:

# gateway.webhook_secret configurado; no se requiere emparejamiento
curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'X-Webhook-Secret: <gateway.webhook_secret>' \
  -H 'Content-Type: application/json' \
  -d '{"revision":"abc123"}'

# gateway.require_pairing = true, no webhook secret configured
curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'Authorization: Bearer <paired-token>' \
  -H 'Content-Type: application/json' \
  -d '{"revision":"abc123"}'

Una coincidencia correcta devuelve 200, con un resultado por cada SOP coincidente. Los resultados de admisión, como skipped, deferred y coalesced, se notifican en esa matriz. La entrada rechazada por la protección contra entradas no confiables del SOP devuelve 422.

Autenticación e idempotencia

Ambos puntos de entrada utilizan los controles de seguridad de webhooks de la puerta de enlace:

  • autenticación Bearer para el emparejamiento cuando se requiere el emparejamiento de la puerta de enlace;
  • el X-Webhook-Secret opcional configurado mediante gateway.webhook_secret; y
  • limitación de frecuencia de los webhooks.

Iniciar una ejecución de SOP autoriza efectos secundarios reales, por lo que el despacho se bloquea ante fallos: debe configurarse al menos un control. Todos los controles configurados deben superarse: cuando se requiere el emparejamiento, envía un Authorization: Bearer <paired-token> válido; cuando gateway.webhook_secret está configurado, envía su valor exacto en X-Webhook-Secret; cuando ambos están configurados, envía ambos.

La política de credenciales se lee una vez por solicitud. La autorización captura una instantánea inmutable de qué controles están configurados y cuáles de ellos cumplió la solicitud, y la puerta de despacho de SOP decide basándose únicamente en esa instantánea. Por tanto, un cambio de configuración que se aplique mientras una solicitud está en curso no puede mezclar dos estados de seguridad dentro de una misma solicitud: una solicitud que no presentó ninguna credencial nunca se admitirá porque se haya añadido un secreto durante su ejecución, y una solicitud que incluya un secreto retirado nunca se admitirá porque su sustituto esté presente. La rotación surte efecto a partir de la siguiente solicitud.

[gateway]
webhook_secret = "replace-with-a-random-secret"

[channels.webhook.<alias>].secret no es una credencial del gateway. Pertenece al listener independiente del canal webhook y verifica X-Webhook-Signature: sha256=<HMAC>. Los alias de canal adicionales, incluidos los deshabilitados o obsoletos, nunca afectan a la autorización del gateway/SOP.

Sin ninguno de los controles del gateway configurado (por ejemplo, gateway.require_pairing = false y sin gateway.webhook_secret), /sop/* devuelve el mismo 401 antes de analizar JSON o consultar el motor SOP. Por lo tanto, un cliente anónimo no puede distinguir entre un JSON mal formado, la disponibilidad del motor o si una ruta coincide. Para /webhook, el requisito de credenciales de fallo cerrado se aplica únicamente cuando coincide un activador de SOP; una solicitud sin coincidencias conserva la política de respaldo del chat existente.

La protección opcional contra repeticiones de X-Idempotency-Key utiliza un espacio de nombres por ruta SOP, no solo por familia de endpoints: la misma clave enviada a dos rutas SOP diferentes (por ejemplo, /sop/deploy y luego /sop/rollback) se trata como dos solicitudes distintas, y las claves de /sop/* nunca colisionan con las claves de /webhook. La clave almacenada es una codificación con prefijo de longitud del dominio del endpoint, del espacio de nombres de la ruta y de la clave del emisor, por lo que es inyectiva: ningún valor controlado por el emisor puede manipularse para que caiga en el espacio de repetición de otra ruta o de otro endpoint. La entrega HTTP es como máximo una vez por intento: la clave se reserva antes del despacho, por lo que una condición de carrera, como la descarga de SOP entre la coincidencia y el despacho, puede consumir la clave sin iniciar una ejecución. Por tanto, una respuesta de duplicado indica que una solicitud anterior reservó la clave y que no se inició ningún despacho nuevo; no afirma que el intento anterior se completara correctamente. Un resultado deferred es observable, pero la puerta de enlace no lo reintenta automáticamente.

Ver también