Wiki
Webhook
リポジトリごとの送信通知(Discord・Slack・Teams・custom)。チェックインとアクティビティ要約に対応。作成、メッセージ形式、テンプレート変数、SSRF ガード。
はじめに
Webhook は、リポジトリ(サーバー上でバージョン管理されるプロジェクト)でイベントが 発生するたびに、外部サービス(Discord・Slack・Microsoft Teams、または任意の URL)へ送信通知を行います。 イベントとはチェックイン、または定期的なアクティビティ要約です。クライアントを開かずにチームへ状況を伝える 最も簡単な方法であり、誰かが作業を提出すると、あなたのチャンネルにメッセージが届きます。
Webhook はリポジトリごとに、デスクトップクライアントの管理パネルの Webhooks タブで設定します。1 つのリポジトリに複数の Webhook を設定できます(例: チーム全体向けに Discord へ 1 つ、リード向けにプライベートな Slack へ 1 つ)。
アクセスとロール
Webhook の管理はリポジトリ管理者に限定されます: 任意のリポジトリでのスーパー管理者
(admin ロール)、または自身が管理するリポジトリでの project_admin です。
その他のロールにはこのタブは表示されません。
Webhook を作成する
1. Webhooks タブを開く
管理パネルで、まず PROJECT 行のセレクターでリポジトリを選び、その同じ行の Webhooks タブを開きます。Webhook はリポジトリに属します。1 つも存在しないリポジトリでは No webhooks configured と表示されます。
2. フォームを開く
タブの右上にある Add Webhook をクリックします。Create Webhook ウィンドウが 空の状態で開きます。
3. 各フィールドを入力する
必須フィールドは 2 つ、Name と URL で、Events で少なくとも 1 つのイベントを選択する必要があります(ドロップダウンリストではなく、クリックできるピルです)。 Type は URL が指すサービスに一致していなければなりません。
| フィールド | 値 |
|---|---|
| Name | 後で見分けるためのラベル(例: Discord équipe)。必須。 |
| URL | 対象サービスが提供する Webhook の URL。必須。拒否される URL についてはセキュリティを参照。 |
| Type | discord、slack、teams、または custom。 |
| Events | 少なくとも 1 つは必須。実際には: checkin と activity_summary。checkout についてはイベントを参照。 |
| Enabled | 有効化トグル(編集時、および一覧から表示)。 |
Discord 側で URL を取得するには: チャンネルの設定 → 連携サービス → ウェブフック → 新しいウェブフック → URL をコピー。詳しくは下記のチュートリアルを参照してください。Slack 側では、Slack アプリの設定で Incoming Webhook を作成します。Teams 側では、チャンネルで コネクタ → Incoming Webhook。
4. 検証してからテストを送信する
Create Webhook をクリックします。Webhook が一覧に有効な状態で表示されます。その行で、 飛行機アイコンの Send test をクリックします。uVersion がサービスにテスト通知を送信し、行の末尾に 結果(緑のチェック、または返された HTTP コード付きのバツ)を表示します。今すぐ実行してください: この Webhook を頼りにする前に、URL とタイプが正しいことを知る唯一の方法です。
チュートリアル: Discord Webhook
これは最も一般的なケースです。「URL を取得する」部分は Discord 内で一度だけ行います。
Discord 側: URL を取得する
- Discord を開いてサーバーに移動します。通知を受け取るテキストチャンネルを選ぶ(または作成する)。例:
#uversion。 - チャンネル名にマウスを合わせ、歯車アイコン(「チャンネルの編集」)をクリックします。
- 左側のメニューで 連携サービス タブを開きます。
- ウェブフック をクリックし、新しいウェブフック をクリックします。Discord がこのチャンネルに紐づく Webhook を自動で作成します。
- 作成された Webhook をクリックして開きます。名前(例:
uVersion)を付け、対象のチャンネルが正しいことを確認します。アバター画像は任意です。 - ウェブフック URL をコピー をクリックします。URL は次のような形式です:
https://discord.com/api/webhooks/123456789/AbCdEf...。
uVersion 側: URL を接続する
上記の Webhook を作成する の手順を、次の値で進めます: Name は自分用のラベル
(例: Discord équipe)、URL はコピーしたばかりのもの、Type は
discord(メッセージを Discord の埋め込みとして送るために不可欠)、Events は
checkin。最後に Send test を実行します: 数秒以内にメッセージが Discord チャンネルに
表示されるはずです。
テストが HTTP 401 または 404 で失敗する場合、URL が誤っているか、Discord 側で
Webhook が削除されています: URL を再度コピーしてください。テストが緑なのに何も届かない場合は、正しいチャンネルを
見ているか、Discord で Webhook が無効化されていないかを確認してください。
タイプと形式
Type は、uVersion が送信前にメッセージをどう整形するかを決めます。URL が指すサービスに 合ったものを選んでください。そうしないとメッセージが崩れて届く(またはサービス側で拒否される)ことがあります。
| Type | 送信される形式 |
|---|---|
discord | Discord の埋め込み(タイトル、色、フィールド)。 |
slack | Slack ペイロード(メッセージブロック)。 |
teams | Microsoft Teams カード(MessageCard)。 |
custom | あなたが完全に定義する JSON ボディ: カスタム Webhook を参照。 |
イベント
サーバーが実際に発行するイベントは 2 つです:
| イベント | 発火する条件… |
|---|---|
checkin | ユーザーがリポジトリにコミットを提出したとき。 |
activity_summary | サーバーのスケジューラが定期的なアクティビティ要約を生成したとき(日次 / 週次)。 |
checkout: チェックボックスは存在するが、イベントは発行されない
フォームには 3 つ目のチェックボックス checkout があり、ファイルのロックを知らせるためのものです
(ロックとは、ユーザーがファイルを編集している間そのファイルに置く予約のことです)。
これは宣言されているものの、現時点では一度も発行されません: チェックしても通知は発生しません。
これに頼らないでください。また、これだけを選択して使わないでください: このイベントだけをチェックした Webhook は
永遠に沈黙したままになります。
チャンネルに必要なものだけをチェックしてください。実際に有用な組み合わせは、チームの作業フィード向けの
checkin と、定期的なまとめ向けの activity_summary です。
カスタム Webhook
custom タイプでは、追加で 2 つのフィールドが表示されます: Custom Headers (JSON)
と Custom Template (JSON)。これにより、JSON の POST を受け付ける任意のサービスと連携できます。
Template
テンプレートは送信される JSON ボディです。uVersion は二重波括弧で囲まれた変数を、イベントの値に置き換えます。 例:
{"text": "{{event_type}} par {{username}} dans {{repository}}"}
利用できる変数:
| 変数 | 内容 |
|---|---|
{{event_type}} | イベントの種類(checkin または activity_summary)。 |
{{repository}} | リポジトリ名。 |
{{username}} | イベントを発生させたユーザー。 |
{{message}} | コミットメッセージ(チェックインの場合)。 |
{{file_count}} | 対象ファイル数。 |
{{commit_hash}} | コミットハッシュ。 |
{{timestamp}} | イベントのタイムスタンプ。 |
Headers
リクエストに付与する HTTP ヘッダーの JSON オブジェクトです。例えば認証トークン:
{"Authorization": "Bearer VOTRE_JETON"}
既定は {}(ヘッダーなし)です。トランスポート用に予約されたヘッダー
(host、content-length、transfer-encoding、connection)
は自動的に取り除かれ、上書きできません。
テスト・有効化・削除
一覧の各 Webhook では次の操作ができます:
- Send test(飛行機アイコン): サービスにテスト通知を送信し、 インラインで結果(緑のチェックまたはバツ)を表示します。頼りにする前に URL とタイプを確認するのに便利です。
- トグル: Webhook を削除せずに有効 / 無効を切り替えます。
- Edit: 任意のフィールドを編集します。
- Delete: 完全に削除します(確認あり)。
セキュリティ: SSRF ガード
Webhook は HTTP リクエストをサーバーに発行させます。悪意ある URL が サーバーの内部ネットワークを探る(SSRF 攻撃)ために使われるのを防ぐため、uVersion は作成時、 変更時、およびテスト時に厳格なガードを適用します:
- スキームは
httpまたはhttpsでなければなりません。それ以外のスキームは拒否されます。 - ホスト名は DNS で解決され、得られたすべての IP アドレスが検査されます。いずれかが
非公開アドレスを指す場合、Webhook は拒否されます: ループバック、プライベートネットワーク(RFC1918)、リンクローカル、
ブロードキャスト、CGNAT 範囲
100.64.0.0/10、クラウドメタデータ169.254.169.254、 ULA / IPv6 リンクローカル、およびそれらの IPv4-mapped-IPv6 相当。 - HTTP リダイレクトは追従されません(したがって内部ホストへの 307 でガードを回避できません)。
- 上流のレスポンスボディはクライアントに一切返されません(SSRF オラクルなし)。
実際には: Webhook の URL は公開サービス(Discord、Slack、Teams、または
インターネットから到達可能な自前のエンドポイント)を指す必要があります。localhost、プライベート IP
(10.x、192.168.x、172.16-31.x)、または内部サービスへの URL は
「Webhook URL refused: …」というメッセージで拒否されます。
よくある落とし穴
タイプがサービスと一致しない
Discord 形式を Slack の URL に送る(またはその逆)と、崩れたメッセージになるか、サービス側で拒否されます。 Type フィールドは URL と一致していなければなりません。迷ったら Send test を実行してください。
イベントが 1 つもチェックされていない
イベントのない Webhook は決して発火しません。イベントが 1 つも選択されていない限り、クライアントは保存を ブロックします(「At least one event is required」)。
内部 URL が拒否される
自分のマシンや LAN 上のサービスに対してテストすると、SSRF ガードが拒否します。Webhook の対象として使うには、 そのサービスを公開 URL(またはトンネル)で公開してください。
無効化された Webhook の見落とし
無効化された Webhook は一覧に残りますが、何も送信しません。通知が途絶えた場合は、URL を疑う前に、まず 有効化トグルを確認してください。