# 機能設計書 25-保護ブランチ

## 概要

本ドキュメントは、GitLabにおける保護ブランチ機能の設計を定義する。特定ブランチへのプッシュ、マージ権限を制限し、重要なブランチを意図しない変更から保護する機能である。

### 本機能の処理概要

保護ブランチ機能は、main/masterブランチなどの重要なブランチを保護し、誰がプッシュ・マージできるかを細かく制御できる機能である。

**業務上の目的・背景**：ソフトウェア開発において、本番環境にデプロイされるブランチや、リリースブランチを不正な変更から保護することは極めて重要である。本機能により、誤ったforce pushによるコミット履歴の消失、未レビューコードの直接プッシュ、権限のないユーザーによる変更を防止できる。これはコード品質の維持、セキュリティの確保、そしてチーム内のワークフローの統制に不可欠である。

**機能の利用シーン**：
- main/masterブランチを保護し、マージリクエスト経由でのみ変更を許可する
- 特定のユーザーまたはグループにのみプッシュ権限を付与する
- リリースブランチへのforce pushを禁止する
- 開発者にはマージ権限を与えつつ、直接プッシュは禁止する
- デプロイキーによる自動化プッシュを許可する

**主要な処理内容**：
1. 保護ブランチルールの作成（名前パターン、ワイルドカード対応）
2. プッシュアクセスレベルの設定（No one/Maintainers/Developers/特定ユーザー）
3. マージアクセスレベルの設定（同上）
4. force push許可設定
5. 保護ブランチルールの更新・削除
6. マッチするブランチの一覧表示

**関連システム・外部連携**：Gitalyサーバーとの連携（ブランチ一覧取得）、GitLab Shellとの連携（プッシュ時の権限チェック）

**権限による制御**：プロジェクト管理者権限（admin_project）が必要。保護ブランチの作成・更新・削除には create_protected_branch, update_protected_branch, destroy_protected_branch 権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 111 | リポジトリ設定 | 主機能 | リポジトリ関連設定の管理 |
| 119 | ブランチルール一覧 | 主機能 | ブランチルール設定の一覧 |
| 35 | ブランチ一覧 | 補助機能 | 保護ブランチ設定表示 |

## 機能種別

CRUD操作（CREATE/READ/UPDATE/DELETE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ブランチ名またはワイルドカードパターン | 有効なブランチ名形式 |
| allow_force_push | Boolean | No | force pushの許可フラグ | true/false |
| merge_access_levels_attributes | Array | No | マージ権限設定 | 有効なアクセスレベル |
| push_access_levels_attributes | Array | No | プッシュ権限設定 | 有効なアクセスレベル |
| access_level | Integer | No | アクセスレベル | 0/30/40（権限レベル） |
| user_id | Integer | No | 特定ユーザーID | 有効なユーザーID |
| group_id | Integer | No | 特定グループID | 有効なグループID |
| deploy_key_id | Integer | No | デプロイキーID | 有効なデプロイキーID |

### 入力データソース

- URL パス: `/project_namespace/project_name/-/settings/repository`（設定画面）
- URL パス: `/project_namespace/project_name/-/protected_branches`（API）
- フォーム入力による設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| protected_branch | ProtectedBranch | 保護ブランチオブジェクト |
| protected_branch.id | Integer | 保護ブランチID |
| protected_branch.name | String | ブランチ名/パターン |
| protected_branch.allow_force_push | Boolean | force push許可フラグ |
| protected_branch.push_access_levels | Array | プッシュ権限一覧 |
| protected_branch.merge_access_levels | Array | マージ権限一覧 |
| matching_refs | Array | パターンにマッチするブランチ一覧 |

### 出力先

- HTML: リダイレクト先のリポジトリ設定画面
- JSON: API レスポンス

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信・認証確認
   └─ authorize_admin_project!
2. パラメータのバリデーション
   └─ protected_ref_params でパラメータ取得・検証
3. 保護ブランチの作成/更新/削除
   └─ CreateService/UpdateService/DestroyService 呼び出し
4. キャッシュの更新
   └─ refresh_cache でブランチ保護キャッシュ更新
5. イベント発行（作成時）
   └─ ProtectedBranchCreatedEvent 発行
6. レスポンス出力
   └─ リダイレクトまたはJSON
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{管理者権限?}
    B -->|No| C[アクセス拒否]
    B -->|Yes| D{操作種別}
    D -->|CREATE| E[CreateService実行]
    D -->|UPDATE| F[UpdateService実行]
    D -->|DELETE| G[DestroyService実行]
    D -->|SHOW| H[マッチングブランチ取得]
    E --> I{保存成功?}
    I -->|Yes| J[キャッシュ更新]
    I -->|No| K[エラー表示]
    J --> L[イベント発行]
    L --> M[リダイレクト]
    F --> N{更新成功?}
    N -->|Yes| O[JSON成功]
    N -->|No| P[JSON エラー]
    G --> Q[リダイレクト]
    H --> R[ブランチ一覧表示]
    K --> M
    M --> S[終了]
    O --> S
    P --> S
    Q --> S
    R --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-25-01 | 名前の一意性 | プロジェクト内で保護ブランチ名は一意 | 常時 |
| BR-25-02 | ワイルドカード | *を使用してパターンマッチ可能 | 名前に*を含む場合 |
| BR-25-03 | 空リポジトリ | 空リポジトリでもデフォルトブランチ保護は管理者に許可 | プロジェクトが空の場合 |
| BR-25-04 | 初期プッシュ | 開発者にもデフォルトブランチ保護設定により初期プッシュ可能 | initial_push_to_default_branch_allowed_for_developer 設定時 |
| BR-25-05 | グループレベル | グループレベルでの保護ブランチ設定が可能 | グループ設定時 |

### 計算ロジック

**アクセスレベル判定**：
- 0: No one
- 30: Developers + Maintainers
- 40: Maintainers

**ブランチマッチング**：
- 正確な名前一致
- ワイルドカードパターンマッチ（`feature/*`など）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | protected_branches | INSERT | 保護ブランチレコード作成 |
| 作成 | protected_branch_push_access_levels | INSERT | プッシュ権限レコード作成 |
| 作成 | protected_branch_merge_access_levels | INSERT | マージ権限レコード作成 |
| 更新 | protected_branches | UPDATE | 保護ブランチ設定更新 |
| 削除 | protected_branches | DELETE | 保護ブランチ削除（カスケード） |
| 参照 | branches | - | Gitalyからブランチ一覧取得 |

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

#### protected_branches

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name, project_id, namespace_id, allow_force_push | フォーム入力値 | - |
| UPDATE | name, allow_force_push | 更新フォーム入力値 | - |
| DELETE | - | id = params[:id] | カスケード削除 |

#### protected_branch_push_access_levels

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | protected_branch_id, access_level, user_id, group_id, deploy_key_id | アクセスレベル設定 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 権限不足 | アクセス拒否 |
| 422 | UnprocessableEntity | バリデーションエラー | エラーメッセージ表示 |
| Flash Alert | ValidationError | 保存失敗 | フラッシュメッセージ表示 |

### リトライ仕様

特になし

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

保護ブランチ作成時は、protected_branches と access_levels の挿入をトランザクションで管理

## パフォーマンス要件

- ProtectedBranches::CacheService によるキャッシュ
- ブランチ保護チェックはプッシュ時に頻繁に呼ばれるため高速化が重要

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

- authorize_admin_project! による管理者権限の確認
- can?(:create_protected_branch) による作成権限の確認
- force push の制御によるコミット履歴保護

## 備考

- グループレベルの保護ブランチはプロジェクトの保護ブランチと統合して適用
- デプロイキーによるプッシュ許可はCI/CD自動化で重要

---

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

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

### 推奨読解順序

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

保護ブランチのデータモデルを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protected_branch.rb | `app/models/protected_branch.rb` | 保護ブランチモデル |
| 1-2 | protected_ref.rb | `app/models/concerns/protected_ref.rb` | 保護参照の共通ロジック |

**読解のコツ**: ProtectedBranch が ProtectedRef の振る舞いを継承していることを理解する。access_levels の関連に注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | protected_branches_controller.rb | `app/controllers/projects/protected_branches_controller.rb` | コントローラー実装 |
| 2-2 | protected_refs_controller.rb | `app/controllers/projects/protected_refs_controller.rb` | 親コントローラー |

**主要処理フロー**:
1. **4-8行目**: show - マッチングブランチ表示
2. **12-14行目**: ref_type - :branches を返す
3. **20-26行目**: load_protected_ref - 保護ブランチの読み込み
4. **28-30行目**: access_levels - マージ/プッシュアクセスレベル定義
5. **32-39行目**: protected_ref_params - パラメータ処理

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/protected_branches/create_service.rb` | 作成サービス |
| 3-2 | base_service.rb | `app/services/protected_branches/base_service.rb` | 基底サービス |

**主要処理フロー**:
- **5-13行目**: execute - 作成処理のメインロジック
- **21-28行目**: save_protected_branch - 保存とキャッシュ更新
- **30-46行目**: publish_created_event - イベント発行

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

```
ProtectedBranchesController#create
    │
    ├─ authorize_admin_protected_refs!
    │      └─ authorize_admin_project!
    │
    ├─ protected_ref_params
    │      └─ パラメータ取得・検証
    │
    └─ CreateService#execute
           ├─ authorized? チェック
           ├─ save_protected_branch
           │      └─ ProtectedBranch#save
           ├─ refresh_cache
           │      └─ CacheService
           └─ publish_created_event
                  └─ EventStore.publish
```

### データフロー図

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

フォーム入力       ───▶  ProtectedBranchesController  ───▶  リダイレクト/JSON
(name, access_levels)    │
                         ▼
                    CreateService
                         │
                         ▼
                    ProtectedBranch.save ─────────────▶  DB INSERT
                         │
                         ▼
                    CacheService ─────────────────────▶  キャッシュ更新
                         │
                         ▼
                    EventStore.publish ───────────────▶  イベント発行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| protected_branches_controller.rb | `app/controllers/projects/protected_branches_controller.rb` | コントローラー | 保護ブランチのエントリーポイント |
| protected_refs_controller.rb | `app/controllers/projects/protected_refs_controller.rb` | コントローラー | 保護参照の基底クラス |
| protected_branch.rb | `app/models/protected_branch.rb` | モデル | 保護ブランチモデル |
| protected_ref.rb | `app/models/concerns/protected_ref.rb` | Concern | 保護参照の共通ロジック |
| create_service.rb | `app/services/protected_branches/create_service.rb` | サービス | 作成サービス |
| update_service.rb | `app/services/protected_branches/update_service.rb` | サービス | 更新サービス |
| destroy_service.rb | `app/services/protected_branches/destroy_service.rb` | サービス | 削除サービス |
| cache_service.rb | `app/services/protected_branches/cache_service.rb` | サービス | キャッシュサービス |
| show.html.haml | `app/views/protected_branches/show.html.haml` | ビュー | マッチングブランチ表示 |
