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 を作成する
- 管理パネルを開き、リポジトリを選択してから Webhooks タブを開きます。
- Add Webhook をクリックします。
- 各フィールドを入力し、Create を押します。
| フィールド | 値 |
|---|---|
| Name | 後で見分けるためのラベル(例: Discord équipe)。必須。 |
| URL | 対象サービスが提供する Webhook の URL。必須。拒否される URL についてはセキュリティを参照。 |
| Type | discord、slack、teams、または custom。 |
| Events | checkin、checkout、activity_summary のうち 1 つ以上。少なくとも 1 つは必須。 |
| Enabled | 有効化トグル(編集時、および一覧から表示)。 |
Discord 側で URL を取得するには: チャンネルの設定 → 連携サービス → ウェブフック → 新しいウェブフック → ウェブフック URL をコピー。Slack 側では、Slack アプリの設定で Incoming Webhook を作成します。 Teams 側では、チャンネルで コネクタ → Incoming Webhook。
チュートリアル: Discord Webhook
これは最も一般的なケースです。「URL を取得する」部分は Discord 内で一度だけ行います。
Discord 側: URL を取得する
- Discord を開いてサーバーに移動します。通知を受け取るテキストチャンネルを選ぶ(または作成する)。例:
#uversion。 - チャンネル名にマウスを合わせ、歯車アイコン(「チャンネルの編集」)をクリックします。
- 左側のメニューで 連携サービス タブを開きます。
- ウェブフック をクリックし、新しいウェブフック をクリックします。Discord がこのチャンネルに紐づく Webhook を自動で作成します。
- 作成された Webhook をクリックして開きます。名前(例:
uVersion)を付け、対象のチャンネルが正しいことを確認します。アバター画像は任意です。 - ウェブフック URL をコピー をクリックします。URL は次のような形式です:
https://discord.com/api/webhooks/123456789/AbCdEf...。
uVersion 側: URL を接続する
- デスクトップクライアントで管理パネルを開き、リポジトリを選択してから Webhooks タブを開きます。
- Add Webhook をクリックします。
- Name: 自分用のラベル(例:
Discord équipe)。 - URL: Discord からコピーした URL を貼り付けます。
- Type:
discordを選びます(メッセージを Discord の埋め込み形式にするために不可欠)。 - Events: 必要なイベントにチェックを入れます。例:
checkin。 - Create をクリックします。
- Webhook の行で 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 を参照。 |
イベント
| イベント | 発火する条件… |
|---|---|
checkin | ユーザーがリポジトリにコミットを提出したとき。 |
checkout | ユーザーが 1 つ以上のファイルをロック(チェックアウト)したとき。 |
activity_summary | サーバーのスケジューラが定期的なアクティビティ要約を生成したとき(日次 / 週次)。 |
チャンネルに必要なものだけをチェックしてください。大規模スタジオでは checkout は騒がしくなりがちです:
多くのチームは 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、checkout、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 を疑う前に、まず 有効化トグルを確認してください。