# 機能設計書 94-システムWebhook

## 概要

本ドキュメントは、GitLabにおけるシステムWebhook機能の設計仕様を記載する。本機能は、GitLabインスタンス全体で発生するイベント（ユーザー作成、プロジェクト作成・削除、グループ変更等）を外部のHTTPエンドポイントまたはローカルスクリプトに通知するための設定・管理・実行機能を提供する。

### 本機能の処理概要

システムWebhook機能は、GitLabインスタンス全体のライフサイクルイベントを監視し、指定されたURLへHTTP POSTリクエストを送信する。プロジェクトWebhookやグループWebhookとは異なり、個別のプロジェクトやグループに限定されず、インスタンス全体を対象とする管理者向け機能である。

**業務上の目的・背景**：GitLabインスタンスを運用する組織では、ユーザーアカウントの作成・削除、プロジェクトの作成・移動、グループの変更などのイベントを外部システムに通知する必要がある。これにより、アカウント管理システムとの連携、監査ログの外部保存、プロビジョニング自動化などが実現できる。

**機能の利用シーン**：本機能は以下のシーンで利用される。
- 新規ユーザー作成時のIDaaSへの連携
- プロジェクト作成時の外部チケットシステムへの自動登録
- グループ変更時のアクセス管理システムへの通知
- ユーザーのログイン失敗時のセキュリティ監視システムへの通知
- リポジトリプッシュ時の外部バックアップシステムへの通知

**主要な処理内容**：
1. システムWebhookの登録・編集・削除（CRUD操作）
2. 対象イベントの選択と設定
3. インスタンス全体のイベント検知
4. イベント発生時のHTTPリクエスト送信
5. ファイルフック（ローカルスクリプト）の実行
6. リクエスト/レスポンスのログ記録

**関連システム・外部連携**：外部HTTPエンドポイント、Sidekiq（非同期処理）、ローカルファイルスクリプト、SSL/TLS（暗号化通信）

**権限による制御**：システムWebhookは管理者（Administrator）のみが操作可能。GitLab.comでは無効化されている。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 管理エリア > システムフック | 主機能 | システムWebhook設定の一覧・編集 |

## 機能種別

CRUD操作 / イベント通知 / 外部システム連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| url | String | Yes | 通知先URL | system_hook_url形式 |
| token | String | No | 認証用シークレットトークン | - |
| name | String | No | Webhook名 | - |
| description | String | No | 説明 | - |
| push_events | Boolean | No | プッシュイベントを通知 | デフォルト: false |
| tag_push_events | Boolean | No | タグプッシュイベントを通知 | - |
| merge_requests_events | Boolean | No | MRイベントを通知 | デフォルト: false |
| repository_update_events | Boolean | No | リポジトリ更新イベントを通知 | デフォルト: true |
| enable_ssl_verification | Boolean | No | SSL証明書検証を有効化 | デフォルト: true |
| push_events_branch_filter | String | No | ブランチフィルタ | - |
| branch_filter_strategy | String | No | ブランチフィルタ戦略 | wildcard/regex/all_branches |
| url_variables | Hash | No | URL変数 | JSON形式 |
| custom_headers | Hash | No | カスタムHTTPヘッダー | JSON形式 |

### 入力データソース

- 管理画面入力（Admin > System hooks）
- REST API（/api/v4/hooks）
- イベントデータ（各種モデルからのトリガー）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | Webhook ID |
| url | String | 通知先URL |
| name | String | Webhook名 |
| description | String | 説明 |
| push_events | Boolean | プッシュイベント設定 |
| tag_push_events | Boolean | タグプッシュイベント設定 |
| merge_requests_events | Boolean | MRイベント設定 |
| repository_update_events | Boolean | リポジトリ更新イベント設定 |
| enable_ssl_verification | Boolean | SSL検証設定 |
| created_at | DateTime | 作成日時 |

### 出力先

- 管理画面表示（システムフック一覧・詳細）
- REST API レスポンス
- 外部HTTPエンドポイント（イベント通知時）
- WebHookLogテーブル（実行ログ）

## 処理フロー

### 処理シーケンス

```
1. システムWebhook登録
   └─ 管理者がWebhook設定を作成

2. イベント発生
   └─ User/Project/Group/Keyモデルでイベント発生
   └─ SystemHooksService.execute_hooks_forが呼び出される

3. イベントデータ構築
   └─ 対応するBuilder（UserBuilder, ProjectBuilder等）でデータ構築

4. Webhook実行
   └─ SystemHook.executable.hooks_for(scope)で対象フック取得
   └─ 各フックで async_execute

5. ファイルフック実行
   └─ Gitlab::FileHook.execute_all_asyncでローカルスクリプト実行

6. HTTP送信（WebHookService#execute）
   └─ ペイロード構築
   └─ ヘッダー構築（X-Gitlab-Event: System Hook）
   └─ Gitlab::HTTP.postでリクエスト送信

7. レスポンス処理
   └─ ログ記録
   └─ 失敗時の自動無効化
```

### フローチャート

```mermaid
flowchart TD
    A[インスタンスイベント発生] --> B[SystemHooksService.execute_hooks_for]
    B --> C[イベントデータ構築]
    C --> D{トリガー対象?}
    D -->|No| E[終了]
    D -->|Yes| F[SystemHook.executable.hooks_for]
    F --> G{Webhook存在?}
    G -->|No| H[ファイルフック実行]
    G -->|Yes| I[WebHook#async_execute]
    I --> J[WebHookWorker]
    J --> K[HTTPリクエスト送信]
    K --> L{成功?}
    L -->|Yes| M[成功ログ記録]
    L -->|No| N[失敗ログ記録]
    M --> H
    N --> H
    H --> E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-94-01 | 管理者限定 | 管理者のみがシステムWebhookを操作可能 | 全操作 |
| BR-94-02 | SaaS無効 | GitLab.comではシステムWebhookは無効 | GitLab.com環境 |
| BR-94-03 | プッシュイベント上限 | push_event_hooks_limit（デフォルト3）を超えるブランチ/タグのプッシュは通知しない | プッシュイベント時 |
| BR-94-04 | ローカルアドレス許可 | allow_local_requests_from_system_hooks設定で制御 | URL設定時 |
| BR-94-05 | デフォルト値 | repository_update_eventsはデフォルトtrue、push/merge_requestsはデフォルトfalse | Webhook作成時 |
| BR-94-06 | 組織紐付け | organization_idが必須 | Webhook作成時 |
| BR-94-07 | ファイルフック併用 | Webhookと同時にローカルファイルスクリプトも実行可能 | イベント発生時 |

### 対応イベント一覧

| イベント種別 | event_name | 説明 |
|------------|------------|------|
| プロジェクト作成 | project_create | プロジェクトが作成された |
| プロジェクト削除 | project_destroy | プロジェクトが削除された |
| プロジェクト名変更 | project_rename | プロジェクトのパスまたは名前が変更された |
| プロジェクト移動 | project_transfer | プロジェクトが別の名前空間に移動された |
| プロジェクト更新 | project_update | プロジェクト属性が変更された |
| グループ作成 | group_create | グループが作成された |
| グループ削除 | group_destroy | グループが削除された |
| グループ名変更 | group_rename | グループのパスまたは名前が変更された |
| ユーザー作成 | user_create | ユーザーアカウントが作成された |
| ユーザー削除 | user_destroy | ユーザーアカウントが削除された |
| ユーザー名変更 | user_rename | ユーザー名が変更された |
| ユーザーログイン失敗 | user_failed_login | ブロックされたユーザーがログインを試みた |
| SSHキー作成 | key_create | SSHキーが作成された |
| SSHキー削除 | key_destroy | SSHキーが削除された |
| メンバー追加（プロジェクト） | user_add_to_team | ユーザーがプロジェクトメンバーに追加された |
| メンバー削除（プロジェクト） | user_remove_from_team | ユーザーがプロジェクトメンバーから削除された |
| メンバー追加（グループ） | user_add_to_group | ユーザーがグループメンバーに追加された |
| メンバー削除（グループ） | user_remove_from_group | ユーザーがグループメンバーから削除された |
| リポジトリ更新 | repository_update | タグまたは複数ブランチを含むプッシュ |
| プッシュ | push | リポジトリへのプッシュ（タグを除く） |
| タグプッシュ | tag_push | タグの追加または削除 |
| マージリクエスト | merge_request | MRの作成、更新、マージ、クローズ |

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Webhook作成 | web_hooks | INSERT | 新規システムWebhook設定の登録（type: SystemHook） |
| Webhook更新 | web_hooks | UPDATE | システムWebhook設定の変更 |
| Webhook削除 | web_hooks | DELETE | システムWebhook設定の削除 |
| ログ記録 | web_hook_logs | INSERT | 実行ログの記録 |

### テーブル別操作詳細

#### web_hooks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | type, url, token, organization_id, *_events | フォーム入力値 | type='SystemHook' |
| UPDATE | url, token, *_events | フォーム入力値 | - |
| DELETE | - | id条件 | 関連ログも削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | 権限エラー | 管理者以外がアクセス | 管理者でログイン |
| 404 | 未検出エラー | GitLab.com環境でアクセス | セルフマネージド環境で利用 |
| - | タイムアウト | レスポンスがタイムアウト | リトライ |
| - | 接続エラー | 接続先に到達できない | URLを確認 |

### リトライ仕様

SystemHookPushWorkerはsidekiq_options retry: 3でリトライ設定されている。

## トランザクション仕様

イベント発生時は`run_after_commit_or_now`を使用し、コミット後にWebhook送信を実行する。

## パフォーマンス要件

- プッシュイベント上限：push_event_hooks_limit（デフォルト3ブランチ/タグ）
- HTTPリクエストタイムアウト：10秒（設定可能）
- 非同期処理：Sidekiqワーカーによる非同期実行

## セキュリティ考慮事項

- **管理者限定**：管理者のみがアクセス可能
- **SaaS無効**：GitLab.comでは利用不可（セキュリティリスク軽減）
- **URL暗号化**：AES-256-GCMで暗号化して保存
- **トークン暗号化**：AES-256-GCMで暗号化して保存
- **X-Gitlab-Token**：認証用ヘッダーとしてトークンを送信
- **X-Gitlab-Event**：System Hookヘッダーで識別
- **ローカルアドレス制御**：allow_local_requests_from_system_hooks設定で制御
- **SSL検証**：デフォルトで有効

## 備考

- ファイルフック機能により、Webhookに加えてローカルスクリプトの実行も可能
- プッシュ/タグイベントはプロジェクトWebhookと同様の構造を使用（ただしコミット情報は含まない）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

SystemHookはWebHookを継承したSTI（Single Table Inheritance）モデル。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | system_hook.rb | `app/models/hooks/system_hook.rb` | SystemHookモデル、利用可能なフック種別、デフォルト値 |
| 1-2 | hook.rb | `app/models/concerns/web_hooks/hook.rb` | Webhook基本機能（プロジェクトWebhookと共通） |

**主要処理フロー（system_hook.rb）**:
- **7-12行目**: `AVAILABLE_HOOKS` - 利用可能なフック種別定義
- **24-26行目**: デフォルト値設定（push_events: false, repository_update_events: true等）
- **28行目**: organization所属の定義
- **30-31行目**: バリデーション（system_hook_url, organization_id必須）
- **34-36行目**: `allow_local_requests?` - ローカルアドレス許可設定の参照

#### Step 2: エントリーポイントを理解する

管理画面コントローラーとAPIエンドポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hooks_controller.rb | `app/controllers/admin/hooks_controller.rb` | 管理画面からのCRUD操作 |
| 2-2 | system_hooks.rb | `lib/api/system_hooks.rb` | REST API実装 |

**主要処理フロー（hooks_controller.rb）**:
- **8行目**: `before_action :not_found, unless: -> { system_hooks? }` - GitLab.comでの無効化
- **10-16行目**: `test`アクション - テスト送信
- **36-38行目**: `system_hooks?` - GitLab.comでないことを確認

**主要処理フロー（system_hooks.rb）**:
- **11-16行目**: 認証と権限チェック（管理者のみ）
- **25-40行目**: `hook_parameters` - 利用可能なパラメータ定義
- **92-102行目**: POST `/hooks` - Webhook作成

#### Step 3: イベントトリガーサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | system_hooks_service.rb | `app/services/system_hooks_service.rb` | イベントトリガーとWebhook実行 |

**主要処理フロー**:
- **4-10行目**: `execute_hooks_for` - モデルとイベントからWebhookをトリガー
- **12-18行目**: `execute_hooks` - Webhookとファイルフックの実行
- **22-36行目**: `build_event_data` - イベントデータの構築（モデルタイプに応じたBuilder選択）

#### Step 4: イベントデータビルダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | user_builder.rb | `lib/gitlab/hook_data/user_builder.rb` | ユーザーイベントデータ構築 |
| 4-2 | project_builder.rb | `lib/gitlab/hook_data/project_builder.rb` | プロジェクトイベントデータ構築 |
| 4-3 | group_builder.rb | `lib/gitlab/hook_data/group_builder.rb` | グループイベントデータ構築 |
| 4-4 | key_builder.rb | `lib/gitlab/hook_data/key_builder.rb` | SSHキーイベントデータ構築 |

#### Step 5: URLバリデーターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | system_hook_url_validator.rb | `app/validators/system_hook_url_validator.rb` | システムWebhook固有のURL検証 |

**主要処理フロー**:
- **15-17行目**: `allow_setting_local_requests?` - ローカルアドレス許可の判定

### プログラム呼び出し階層図

```
Admin::HooksController
    |
    +-- WebHooks::HookActions (concern)
    |       |
    |       +-- WebHooks::CreateService#execute
    |       +-- WebHooks::DestroyService#execute
    |
    +-- TestHooks::SystemService#execute (テスト送信)
            |
            +-- WebHookService#execute

[イベント発生時]
User/Project/Group/Key モデル
    |
    +-- run_after_commit
            |
            +-- SystemHooksService#execute_hooks_for
                    |
                    +-- build_event_data (Builder選択)
                    +-- SystemHook.executable.hooks_for
                    +-- WebHook#async_execute
                            |
                            +-- WebHookWorker
                                    |
                                    +-- WebHookService#execute
                    +-- Gitlab::FileHook.execute_all_async
```

### データフロー図

```
[入力]                      [処理]                           [出力]

管理画面入力        ---->   Admin::HooksController       ---->  DB保存
(url, token等)              WebHooks::CreateService            (web_hooks)

インスタンスイベント ---->  SystemHooksService           ---->  外部HTTP
(user_create等)             execute_hooks_for                  エンドポイント
                                    |
                                    +-- HookData::*Builder
                                    +-- WebHookService#execute
                                    +-- FileHook.execute_all_async ---> ローカルスクリプト
                                    |
                                    v
                            WebHooks::LogExecutionWorker ---->  DB保存
                                                               (web_hook_logs)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| hooks_controller.rb | `app/controllers/admin/hooks_controller.rb` | ソース | 管理画面コントローラー |
| system_hook.rb | `app/models/hooks/system_hook.rb` | ソース | SystemHookモデル |
| system_hooks_service.rb | `app/services/system_hooks_service.rb` | ソース | イベントトリガーサービス |
| system_hooks.rb | `lib/api/system_hooks.rb` | ソース | REST API |
| system_hook_url_validator.rb | `app/validators/system_hook_url_validator.rb` | ソース | URL検証 |
| system_hook_push_worker.rb | `app/workers/system_hook_push_worker.rb` | ソース | プッシュイベントワーカー |
| user_builder.rb | `lib/gitlab/hook_data/user_builder.rb` | ソース | ユーザーイベントデータ構築 |
| project_builder.rb | `lib/gitlab/hook_data/project_builder.rb` | ソース | プロジェクトイベントデータ構築 |
| group_builder.rb | `lib/gitlab/hook_data/group_builder.rb` | ソース | グループイベントデータ構築 |
| key_builder.rb | `lib/gitlab/hook_data/key_builder.rb` | ソース | SSHキーイベントデータ構築 |
| system_hooks_menu.rb | `lib/sidebars/admin/menus/system_hooks_menu.rb` | ソース | 管理メニュー定義 |
| system_hooks.md | `doc/administration/system_hooks.md` | ドキュメント | 管理者向けドキュメント |
