SOP ファンイン: Webhook
ゲートウェイは、Webhook でトリガーされる SOP 用の認証付き HTTP エントリーポイントを 2 つ公開します:
POST /sop/{path}は SOP 専用です。一致する SOP をディスパッチし、読み込まれている SOP のいずれもその正確なパスを宣言していない場合は404を返します。エージェントやモデルの呼び出しにフォールバックすることはありません。POST /webhookは、まず完全一致する/webhookSOP トリガーを確認します。一致するものがない場合は、通常の webhook チャット動作を維持します。
これらのエンドポイントは、sop.sops_dirを設定したzeroclaw daemon経由で実行してください。デーモンの共有SOPエンジンを使用します。単独のzeroclaw gateway start、またはSOPサブシステムを有効にしていないデーモンを使用すると、/sop/*から503が返されます。
トリガー
受信 HTTP リクエスト。稼働中: ゲートウェイの /sop/* と SOP-first の /webhook ルート。
| フィールド | 型 | default | 意味 |
|---|---|---|---|
path* | string | — | リクエストパスがイベントパスと完全に一致しました。 |
SOP を読み込んで検証する:
定義
Syntax で説明されているとおり、webhook トリガーを指定して SOP を作成します。上記のトリガーフィールドはサポートされているキーです。ページではファイル全体を順に説明します。
検証
zeroclaw sop validate
検査
zeroclaw sop list
zeroclaw sop show <name>
パスは完全一致で照合されます。例:
[[triggers]]
type = "webhook"
path = "/sop/deploy"
POST /sop/deploy に対して発火しますが、/sop/deploy/ または /sop/deploy/production に対しては発火しません。
リクエストとレスポンス
/sop/* は空のボディまたは有効な JSON 値を受け付けます。リクエストパスがイベントトピックになり、正規化された JSON ボディがそのペイロードになります。無効な JSON の場合は 400 を返します。
設定されているすべての制御を送信します。gateway.require_pairing = true および gateway.webhook_secret が設定されている場合(以下に示す設定)、完全なリクエストには両方が含まれます:
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"}'
コントロールが 1 つだけ設定されている場合は、そのコントロールだけを送信します:
# gateway.webhook_secret を設定済みの場合、ペアリングは不要
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"}'
一致に成功すると、一致する SOP ごとに 1 件の結果を含む 200 が返されます。skipped、deferred、coalesced などの受け入れ結果は、その配列で報告されます。SOP の信頼されていない入力ガードによって拒否された入力には 422 が返されます。
認証と冪等性
両方のエントリポイントでは、ゲートウェイ Webhook のセキュリティ制御が使用されます:
- ゲートウェイのペアリングが必要な場合のペアリング用ベアラー認証;
gateway.webhook_secretで設定されたオプションのX-Webhook-Secret; および- Webhook のレート制限。
SOP の実行を開始すると実際の副作用が許可されるため、ディスパッチはフェイルクローズします。少なくとも 1 つの制御を設定する必要があります。設定されているすべての制御に合格する必要があります。ペアリングが必要な場合は、有効な Authorization: Bearer <paired-token> を送信します。gateway.webhook_secret が設定されている場合は、その正確な値を X-Webhook-Secret で送信します。両方が設定されている場合は、両方を送信します。
認証情報ポリシーは、リクエストごとに1回読み取られます。認可では、どの制御が構成されているか、およびそのうちリクエストがどれを満たしたかの不変スナップショットを取得し、SOP ディスパッチゲートはそのスナップショットだけに基づいて判断します。リクエストの処理中に反映された構成変更によって、1つのリクエスト内で2つのセキュリティ状態が混在することはありません。したがって、認証情報を提示しなかったリクエストが、処理途中でシークレットが追加されたために許可されることはなく、廃止されたシークレットを含むリクエストが、その置き換えが存在するために許可されることもありません。ローテーションは次のリクエストから有効になります。
[gateway]
webhook_secret = "replace-with-a-random-secret"
[channels.webhook.<alias>].secret はゲートウェイの認証情報ではありません。これは独立した webhook チャネルリスナーに属し、X-Webhook-Signature: sha256=<HMAC> を検証します。無効なエイリアスや古いエイリアスを含む複数のチャネルエイリアスが、ゲートウェイ/SOP の認可に影響を与えることは決してありません。
ゲートウェイ制御がいずれも設定されていない場合(たとえば、gateway.require_pairing = false で、gateway.webhook_secret がない場合)、/sop/* は JSON の解析や SOP エンジンへの照会を行う前に、常に同じ 401 を返します。そのため、匿名の呼び出し元は、不正な JSON、エンジンの可用性、またはパスが一致するかどうかを区別できません。/webhook では、フェイルクローズの認証情報要件は SOP トリガーが一致した場合にのみ適用され、一致しないリクエストでは既存のチャットフォールバックポリシーが維持されます。
オプションの X-Idempotency-Key によるリプレイ防止は、エンドポイントファミリー単位だけでなく、SOPパスごとに名前空間が分かれています。2つの異なるSOPパス(例: /sop/deploy、続いて /sop/rollback)に同じキーを送信しても、2つの別個のリクエストとして扱われ、/sop/* のキーが /webhook のキーと衝突することはありません。保存されるキーは、エンドポイントドメイン、パス名前空間、呼び出し元のキーを長さプレフィックス付きでエンコードしたものであるため単射的です。つまり、呼び出し元が制御する値を細工して、別のパスまたは別のエンドポイントのリプレイスロットに入れることはできません。HTTP配信は試行単位で最大1回です。キーはディスパッチ前に予約されるため、マッチングとディスパッチの間にSOPのアンロードが発生する競合などでは、実行を開始せずにキーが消費されることがあります。そのため、重複応答は、以前のリクエストがキーを予約し、新しいディスパッチが開始されなかったことを示します。以前の試行が正常に完了したことを示すものではありません。deferred の結果は観測できますが、ゲートウェイによって自動的に再試行されることはありません。