Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

SOP Fan-In : Webhook

La passerelle expose deux points d’entrée HTTP authentifiés pour les SOP déclenchés par des webhooks :

  • POST /sop/{path} est réservé aux SOP. Il distribue le SOP correspondant et renvoie 404 lorsqu’aucun SOP chargé ne déclare ce chemin exact. Il ne bascule jamais vers un agent ni vers un appel de modèle.
  • POST /webhook vérifie d’abord la présence d’un déclencheur SOP /webhook exact. Si aucune correspondance n’est trouvée, il conserve le comportement normal du chat webhook.

Faites passer ces points de terminaison par zeroclaw daemon avec sop.sops_dir configuré. Ils utilisent le moteur SOP partagé du démon. Un zeroclaw gateway start autonome, ou un démon dont le sous-système SOP n’est pas activé, renvoie 503 pour /sop/*.

Déclencheur

Requête HTTP entrante. En production : routes de passerelle /sop/* et routes /webhook donnant la priorité au SOP.

champtypepar défautsens
path*chaîneLe chemin de la requête a exactement correspondu au chemin de l’événement.

Charger et vérifier le SOP :

Définir

Rédigez la SOP comme décrit dans Syntax, avec un déclencheur webhook. Les champs de déclencheur ci-dessus correspondent aux clés prises en charge ; la page parcourt le fichier dans son intégralité.

Valider

zeroclaw sop validate

Inspect

zeroclaw sop list
zeroclaw sop show <name>

La correspondance du chemin est exacte. Par exemple :

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

se déclenche pour POST /sop/deploy, mais pas pour /sop/deploy/ ni /sop/deploy/production.

Requête et réponse

/sop/* accepte un corps vide ou toute valeur JSON valide. Le chemin de la requête devient le sujet de l’événement et le corps JSON canonique devient sa charge utile. Un JSON non valide renvoie 400.

Envoyez tous les contrôles configurés. Lorsque gateway.require_pairing = true et que gateway.webhook_secret est défini (comme dans la configuration ci-dessous), une requête complète contient les deux éléments suivants :

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"}'

Lorsqu’un seul contrôle est configuré, envoyez uniquement celui-ci :

# gateway.webhook_secret défini, appairage non requis
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"}'

Une correspondance réussie renvoie 200 avec un résultat pour chaque SOP correspondant. Les résultats d’admission tels que skipped, deferred et coalesced sont signalés dans ce tableau. Les entrées rejetées par la protection du SOP contre les entrées non fiables renvoient 422.

Authentification et idempotence

Les deux points d’entrée utilisent les contrôles de sécurité du webhook de la passerelle :

  • authentification Bearer pour l’appairage lorsque l’appairage de la passerelle est requis ;
  • l’en-tête facultatif X-Webhook-Secret, configuré par gateway.webhook_secret ; et
  • limitation du débit des webhooks.

Le lancement d’une exécution SOP autorise des effets de bord réels ; le dispatch échoue donc par défaut : au moins un contrôle doit être configuré. Tous les contrôles configurés doivent réussir : lorsque l’association est requise, envoyer un Authorization: Bearer <paired-token> valide ; lorsque gateway.webhook_secret est défini, envoyer sa valeur exacte dans X-Webhook-Secret ; lorsque les deux sont configurés, envoyer les deux.

La politique d’authentification est lue une fois par requête. L’autorisation capture un instantané immuable des contrôles configurés et de ceux auxquels la requête a satisfait, et la porte de dispatch SOP décide à partir de ce seul instantané. Une modification de configuration qui intervient alors qu’une requête est en cours ne peut donc pas mélanger deux états de sécurité au sein d’une même requête : une requête qui n’a présenté aucun justificatif n’est jamais admise parce qu’un secret a été ajouté en cours de traitement, et une requête contenant un secret retiré n’est jamais admise parce que son remplacement est présent. La rotation prend effet à la granularité de la requête suivante.

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

[channels.webhook.<alias>].secret n’est pas un identifiant d’authentification de la passerelle. Il appartient à l’écouteur de canal webhook distinct et vérifie X-Webhook-Signature: sha256=<HMAC>. Plusieurs alias de canaux, y compris les alias désactivés ou obsolètes, n’ont jamais d’incidence sur l’autorisation de la passerelle/SOP.

Lorsque ni l’un ni l’autre des contrôles de gateway n’est configuré (par exemple gateway.require_pairing = false et sans gateway.webhook_secret), /sop/* renvoie le même 401 avant d’analyser le JSON ou de consulter le moteur SOP. Un appelant anonyme ne peut donc pas distinguer un JSON mal formé, la disponibilité du moteur ou le fait qu’un chemin corresponde. Pour /webhook, l’exigence d’identifiants avec refus par défaut ne s’applique que lorsqu’un déclencheur SOP correspond ; une requête sans correspondance conserve la stratégie de repli du chat existante.

La protection facultative contre la relecture via X-Idempotency-Key utilise un espace de noms distinct pour chaque chemin SOP, et pas seulement pour chaque famille de points de terminaison : la même clé envoyée à deux chemins SOP différents (par ex. /sop/deploy, puis /sop/rollback) est traitée comme deux requêtes distinctes, et les clés /sop/* n’entrent jamais en collision avec les clés /webhook. La clé stockée est un encodage préfixé par la longueur du domaine du point de terminaison, de l’espace de noms du chemin et de la clé de l’appelant ; elle est donc injective : aucune valeur contrôlée par l’appelant ne peut être conçue pour tomber dans l’emplacement de relecture d’un autre chemin ou d’un autre point de terminaison. La livraison HTTP est effectuée au plus une fois par tentative : la clé est réservée avant le déclenchement, de sorte qu’une condition de concurrence telle que le déchargement de SOP entre la mise en correspondance et le déclenchement peut consommer la clé sans lancer d’exécution. Une réponse indiquant un doublon signifie donc qu’une requête précédente a réservé la clé et qu’aucun nouveau déclenchement n’a démarré ; elle n’affirme pas que la tentative précédente s’est terminée avec succès. Un résultat deferred est observable, mais n’est pas automatiquement réessayé par la passerelle.

Voir aussi