> ## Documentation Index
> Fetch the complete documentation index at: https://docs.diversion.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook

> Webhook を使って Diversion を外部ツールと連携し、ビルド、通知、ワークフローを自動化します。

Diversion は、リポジトリでイベントが発生したときに外部サービスに通知する Webhook をサポートしています。これにより、CI/CD システム、通知サービス、およびカスタム自動化ワークフローとの連携が可能になります。

## 概要

Webhook は、特定のリポジトリイベントによってトリガーされる HTTP コールバックです。イベントが発生すると、Diversion は設定されたエンドポイント URL に、リクエストボディにイベントの詳細を含めた POST リクエストを送信します。

### 主な特長

* **イベント駆動の通知**: リポジトリイベントに対するリアルタイム通知
* **セキュアな配信**: リクエストの真正性を検証するための HMAC-SHA256 署名
* **信頼性の高い配信**: 指数バックオフによる自動再試行
* **柔軟な構成**: Webhook ごとに特定のイベントタイプにサブスクライブ可能
* **管理者専用の管理**: リポジトリの管理者アクセスが必要

## サポートされているイベント

現在、Diversion は以下の Webhook イベントをサポートしています:

| イベント             | 説明                 | ペイロード                             |
| ---------------- | ------------------ | --------------------------------- |
| `commit_created` | 新しいコミットが作成されたときに発火 | コミットの詳細、リポジトリ情報、作成者               |
| `review_created` | 新しいレビューが作成されたときに発火 | レビューの詳細、リポジトリ情報、作成者、レビュアー         |
| `review_merged`  | レビューがマージされたときに発火   | レビューの詳細、マージコミット、リポジトリ情報、作成者、レビュアー |

## Webhook の管理

Webhook は Web アプリケーションから管理できます。アクセスにはリポジトリの管理者権限が必要です。

### Web インターフェース

**プロフィールアバター** → **Your organizations** → 設定サイドバーで **Repositories** を選択し、リポジトリ列で **Webhooks** を選択します。その列の上部にあるリポジトリピッカーでリポジトリを選択します。

<img src="https://mintcdn.com/diversion-2/Yky3RnSpHJMXzWF0/images/webhooks/webhook-list.png?fit=max&auto=format&n=Yky3RnSpHJMXzWF0&q=85&s=b7b309e52838bad00a7d6325e7b77df8" alt="Webhook 管理インターフェース" width="1280" height="301" data-path="images/webhooks/webhook-list.png" />

### Webhook を作成する

1. **"Create Webhook"** をクリック
2. Webhook の詳細を入力:
   * **Name**: Webhook の分かりやすい名前
   * **Description**: Webhook の目的の任意の説明
   * **Endpoint URL**: イベントの送信先となる HTTPS URL
   * **Secret**: 署名検証用の Webhook シークレット（未指定の場合は自動生成）
   * **Events**: Webhook をトリガーするイベントを選択
3. **"Create"** をクリックして Webhook を保存

<img src="https://mintcdn.com/diversion-2/5l5ms-3ikwF1UR5X/images/webhooks/webhook-create.png?fit=max&auto=format&n=5l5ms-3ikwF1UR5X&q=85&s=d2e82c6ee45539aab24c3506158474f8" alt="Webhook 作成フォーム" width="448" height="730" data-path="images/webhooks/webhook-create.png" />

### Webhook シークレット

Webhook シークレットは、リクエスト検証用の HMAC-SHA256 署名の生成に使用されます。シークレットは次を満たす必要があります:

* 24〜75 文字の長さ
* データベースに暗号化して保存
* Webhook 作成時のみ表示

**自動生成**: シークレットが指定されていない場合、Diversion は `whsec_<base64-encoded-random-bytes>` 形式で暗号学的に安全な 32 バイトのシークレットを生成します。

## Webhook ペイロード

すべての Webhook ペイロードは一貫した構造に従います:

```json theme={null}
{
  "id": "evt_1234567890",
  "timestamp": "2025-01-17T12:34:56.789Z",
  "type": "v1.repo.commit.created",
  "data": {
    // Event-specific data
  }
}
```

### Commit Created イベントのペイロード

```json theme={null}
{
  "id": "evt_2KtGQeeJhtF5qQ",
  "timestamp": "2025-01-17T08:23:15.123Z",
  "type": "v1.repo.commit.created",
  "data": {
    "repository_id": "dv.repo.12345678-1234-1234-1234-123456789abc",
    "repository_name": "my-project",
    "repository_owner_id": "Google_12345678901234567890",
    "commit_id": "dv.commit.123456",
    "commit_url": "https://app.diversion.dev/r/my-project/commit/dv.commit.123456",
    "correlation_id": "abc123-def456-ghi789",
    "message": "Add new feature",
    "commit_time": "2025-01-17T08:23:14.567Z",
    "branch_id": "dv.branch.42",
    "branch_name": "feature-branch",
    "branch_url": "https://app.diversion.dev/r/my-project/branch/dv.branch.42",
    "author": {
        "id": "Google_12345678901234567890",
        "name": "John Doe",
        "email": "john.doe@example.com",
        "full_name": "John Doe"
    },
    "parent_commits": [
        {
            "commit_id": "dv.commit.123455",
            "branch_id": "dv.branch.42"
        }
    ],
    "changes": {
        "deleted": [
            "del1.txt",
            "del2.txt",
            "del3.txt"
        ],
        "has_more_deleted": false,
        "modified": [
            "mod1.txt",
            "mod2.txt"
        ],
        "has_more_modified": false,
        "new": [
            "new1.txt"
        ],
        "has_more_new": false
    }
  }
}
```

### Review Created イベントのペイロード

```json theme={null}
{
  "id": "evt_2KtGQeeJhtF5qQ",
  "timestamp": "2025-01-17T08:23:15.123Z",
  "type": "v1.repo.review.created",
  "data": {
    "repository_id": "dv.repo.12345678-1234-1234-1234-123456789abc",
    "repository_name": "my-project",
    "repository_owner_id": "Google_12345678901234567890",
    "review_id": "dv.review.98765",
    "review_url": "https://app.diversion.dev/r/my-project/review/dv.review.98765",
    "title": "Add authentication feature",
    "description": "This review adds OAuth2 authentication to the API",
    "status": "open",
    "created_unix": 1737098594,
    "draft_commit_id": "dv.commit.123456",
    "base_branch_id": "dv.branch.1",
    "base_branch_name": "master",
    "compare_branch_id": "dv.branch.42",
    "compare_branch_name": "feature-auth",
    "author": {
    "id": "Google_12345678901234567890",
    "name": "johndoe",
    "full_name": "John Doe",
    "email": "john.doe@example.com"
    },
    "reviewers": [
        {
          "id": "Google_98765432109876543210",
          "name": "janedoe",
          "full_name": "Jane Doe",
          "email": "jane.doe@example.com",
          "status": "requested"
        },
        {
          "id": "Google_11111111111111111111",
          "name": "bobsmith",
          "full_name": "Bob Smith",
          "email": "bob.smith@example.com",
          "status": "approved"
        }
    ],
    "correlation_id": "abc123-def456-ghi789"
  }
}
```

### Review Merged イベントのペイロード

```json theme={null}
{
  "id": "evt_3MuHRffKiuG6rR",
  "timestamp": "2025-01-17T09:45:30.456Z",
  "type": "v1.repo.review.merged",
  "data": {
    "repository_id": "dv.repo.12345678-1234-1234-1234-123456789abc",
    "repository_name": "my-project",
    "repository_owner_id": "Google_12345678901234567890",
    "review_id": "dv.review.98765",
    "review_url": "https://app.diversion.dev/r/my-project/review/dv.review.98765",
    "title": "Add authentication feature",
    "description": "This review adds OAuth2 authentication to the API",
    "status": "merged",
    "created_unix": 1737098594,
    "updated_unix": 1737103530,
    "merge_commit_id": "dv.commit.123457",
    "draft_commit_id": "dv.commit.123456",
    "base_branch_id": "dv.branch.1",
    "base_branch_name": "master",
    "compare_branch_id": "dv.branch.42",
    "compare_branch_name": "feature-auth",
    "author": {
        "id": "Google_12345678901234567890",
        "name": "johndoe",
        "full_name": "John Doe",
        "email": "john.doe@example.com"
    },
    "reviewers": [
        {
          "id": "Google_98765432109876543210",
          "name": "janedoe",
          "full_name": "Jane Doe",
          "email": "jane.doe@example.com",
          "status": "approved"
        },
        {
          "id": "Google_11111111111111111111",
          "name": "bobsmith",
          "full_name": "Bob Smith",
          "email": "bob.smith@example.com",
          "status": "approved"
        }
    ],
    "correlation_id": "xyz789-abc123-def456"
  }
}
```

## リクエスト署名の検証

すべての Webhook リクエストには、検証用の署名ヘッダーが含まれます:

* `webhook-id`: メッセージの一意識別子
* `webhook-timestamp`: リクエストのタイムスタンプ（Unix エポック秒）
* `webhook-signature`: HMAC-SHA256 署名（形式: `v1,base64signature`）

### 署名検証の例

Diversion は Webhook 署名検証のリファレンス実装を提供しています。以下は Python での例です:

```python theme={null}
import base64
import hashlib
import hmac

def verify_webhook_signature(webhook_id, webhook_timestamp, sig_header, secret, payload_body):
    # Svix signature format: v1,base64signature
    if not sig_header.startswith('v1,'):
        print(f"Invalid signature format: {sig_header}")
        return False
    
    # Extract the signature part after v1,
    v1_signature = sig_header[3:]  # Skip "v1,"
    
    # Use raw hex format directly as the signing key
    try:
        # Svix uses the literal hex string as UTF-8 bytes for signing
        signing_key = secret.encode('utf-8')
    except Exception as e:
        print(f"Failed to encode secret: {e}")
        return False
    
    # Construct the signed content according to Svix docs
    # Format: {id}.{timestamp}.{payload}
    signed_content = f"{webhook_id}.{webhook_timestamp}.{payload_body.decode('utf-8')}"
    
    # Compute HMAC-SHA256
    computed_hmac = hmac.new(
        signing_key,  # Use the hex string encoded as UTF-8 bytes
        signed_content.encode('utf-8'),
        hashlib.sha256  
    ).digest()
    
    # Base64 encode the result
    expected_sig = base64.b64encode(computed_hmac).decode('utf-8')
    
    # Compare signatures
    is_valid = hmac.compare_digest(expected_sig, v1_signature)
    
    if is_valid:
        print("Svix signature verified successfully")
    else:
        print(f"Signature verification failed. Expected: {expected_sig}, Got: {v1_signature}")
    
    return is_valid
```

**注**: 完全にテスト済みの Webhook 検証実装が、AWS Lambda 関数の例として利用できます。Webhook 署名検証について支援が必要な場合は、[サポートまでご連絡ください](mailto:support@diversion.dev)。

## Webhook の配信

Diversion は、以下の機能により Webhook の信頼性の高い配信を保証します:

* **自動再試行**: 失敗した配信は指数バックオフで再試行されます
* **配信状況の追跡**: Webhook の配信状況を監視できます
* **レート制限**: 送信先サーバーが過負荷にならないようにします
* **サーキットブレーキング**: 失敗し続けるエンドポイントを一時的に無効化します

### 配信保証

* Webhook は少なくとも 1 回配信されます
* イベントは順不同で届くことがあります
* イベントの順序付けには `timestamp` フィールドを使用してください
* `id` フィールドを利用して、冪等なハンドラーを実装してください

## Webhook のテスト

署名検証の実装をテストするには:

1. 既知のシークレットでテスト用の Webhook を作成する
2. 上記の検証コード例を使用する
3. リファレンスの AWS Lambda 実装と比較する

## ベストプラクティス

1. **HTTPS エンドポイントを使用する**: セキュリティ上、HTTP エンドポイントはサポートされていません
2. **署名を検証する**: 本番環境では常に Webhook の署名を検証してください
3. **再試行に対応する**: Webhook ハンドラーを冪等にしてください
4. **迅速に応答する**: 30 秒以内に 2xx ステータスを返してください
5. **キューでの処理**: 長時間実行タスクの場合は、作業をキューに入れて即座に応答してください
6. **失敗を監視する**: Webhook 配信の失敗に対するアラートを設定してください

## トラブルシューティング

### よくある問題

1. **Webhook がトリガーされない**
   * Webhook が有効かどうかを確認する
   * イベントタイプのサブスクリプションを確認する
   * リポジトリへの管理者アクセスがあることを確認する

2. **署名検証に失敗する**
   * 正しいシークレットを使用しているか確認する
   * タイムスタンプが許容範囲（5 分）内であることを確認する
   * 署名の形式と解析を確認する

3. **配信の失敗**
   * エンドポイントが公開アクセス可能であることを確認する
   * SSL/TLS 証明書の問題を確認する
   * エンドポイントが 2xx ステータスコードを返すことを確認する
   * サーバーログでエラーを確認する

### デバッグのヒント

* 初期テストには [webhook.site](https://webhook.site) などの Webhook テストツールを使用する
* Webhook ハンドラーでデバッグログを有効化する
* 想定されるペイロード形式で curl を使ってテストする
* 配信の問題を調査するためのサポートが必要な場合は [サポートまでご連絡ください](mailto:support@diversion.dev)

## セキュリティに関する考慮事項

1. **シークレット管理**: Webhook シークレットは安全に保管し、コード内に記述しないでください
2. **ペイロード検証**: 処理前にすべての Webhook データを検証してください
3. **レート制限**: Webhook エンドポイントにレート制限を実装してください
4. **認証**: Webhook 署名を唯一の認証手段として使用してください
5. **HTTPS のみ**: Webhook 配信には常に HTTPS エンドポイントを使用してください

## Discord Webhook の統合

現時点では、Discord Webhook との直接連携はサポートされていません。ただし、Zapier や Pipedream のようなミドルウェアサービスを Discord と当社のプラットフォームの橋渡しとして使えば、Discord を接続できます。

### Pipedream を使って Discord Webhook を統合する

1. **Pipedream をセットアップする**
   * Pipedream アカウントと新しいプロジェクトを作成する
   * プロジェクトに名前を付け、**Create Project** をクリックする

2. **ワークフローを作成する**
   * **+ New** → **Workflow** を選択する
   * ワークフローに名前を付け、"Send error notifications" のチェックを外し、**Create Workflow** をクリックする

3. **トリガーを追加する**
   * **Add Trigger** をクリック → **New HTTP / Webhook Requests** を選択する
   * **Save and Continue** をクリックする

4. **Discord アクションを追加する**
   * トリガーの下の **+** シンボルをクリック → **Discord** を検索して選択する
   * **Send Message** を選択する
   * Discord アカウントを選択する
   * Discord にログインし、サーバーとチャンネルを選択する
   * メッセージを入力し（例: "New commit!"）、アクションを閉じる
   * リポジトリ名、作成者、ブランチ、コミット ID、コミットメッセージ、コミットへのリンクを含む、より詳細なメッセージのテンプレートは次のとおりです:
   ```
       **New Commit to {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.repository_name || 'Unknown Repo' }}**

       **Author:** {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.author?.full_name || 'Unknown Author' }}
       **Branch:** {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.branch_name || 'Unknown Branch' }}
       **Commit ID:** {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.commit_id || 'Unknown ID' }}
       **Message:** {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.message || 'No message' }}
       **Link:** {{ JSON.parse(JSON.stringify(steps.trigger.event.body)).data?.commit_url || 'No URL' }}
   ```
   * commit created イベントのペイロードから利用可能な他のフィールドにアクセスして、メッセージをさらにカスタマイズできます

5. **テストとデプロイ**
   * **Test** をクリックしてメッセージが Discord に表示されることを確認する
   * トリガーをクリック → Webhook URL をコピーする
   * Diversion アプリで Webhook を設定する際、この URL を Payload URL として使用する
   * **Deploy** をクリックしてワークフローを有効化する
   * Diversion に移動し、この URL を Diversion に貼り付けて Webhook を追加する

6. **Diversion で Webhook を設定する**
   * Diversion デスクトップアプリまたは Web UI を開く
   * **プロフィールアバター** → **Your organizations** → 設定サイドバーで **Repositories** を選択し、リポジトリ列で **Webhooks** を選択します。その列の上部にあるリポジトリピッカーでリポジトリを選択します。
   * **Add Webhook** をクリック
   * **Payload URL** フィールドに、Pipedream からコピーした Webhook URL を貼り付ける
   * その他の Webhook 詳細を入力する
   * **Add webhook** をクリックして Webhook を有効化する
