# 機能設計書 26-保護タグ

## 概要

本ドキュメントは、GitLabにおける保護タグ機能の設計を定義する。特定タグの作成権限を制限し、重要なタグを意図しない作成・削除から保護する機能である。

### 本機能の処理概要

保護タグ機能は、リリースタグなどの重要なタグを保護し、誰がタグを作成できるかを制御できる機能である。

**業務上の目的・背景**：ソフトウェアリリース管理において、バージョンタグは本番環境へのデプロイや配布物の識別に使用される重要な参照点である。本機能により、認可されていないユーザーによる不正なタグ作成を防止し、リリース管理の信頼性を確保できる。特にセマンティックバージョニング（v1.0.0形式）を採用するプロジェクトでは、タグの一貫性維持が重要である。

**機能の利用シーン**：
- リリースタグ（v*形式）の作成権限を特定のユーザーに限定する
- 自動リリースパイプラインにのみタグ作成を許可する
- 特定のプレフィックスを持つタグの保護（release-*など）
- 開発者によるテストタグ作成は許可しつつ、本番タグは制限する

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

**関連システム・外部連携**：Gitalyサーバーとの連携（タグ一覧取得）、GitLab Shellとの連携（タグ作成時の権限チェック）

**権限による制御**：プロジェクト管理者権限（admin_project）が必要。保護タグの作成には create_protected_tags 権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 111 | リポジトリ設定 | 主機能 | リポジトリ関連設定の管理 |
| 37 | タグ一覧 | 補助機能 | 保護タグ設定表示 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | タグ名またはワイルドカードパターン | 有効なタグ名形式 |
| create_access_levels_attributes | Array | No | 作成権限設定 | 有効なアクセスレベル |
| access_level | Integer | No | アクセスレベル | 0/30/40（権限レベル） |
| user_id | Integer | No | 特定ユーザーID | 有効なユーザーID |
| group_id | Integer | No | 特定グループID | 有効なグループID |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| protected_tag | ProtectedTag | 保護タグオブジェクト |
| protected_tag.id | Integer | 保護タグID |
| protected_tag.name | String | タグ名/パターン |
| protected_tag.create_access_levels | Array | 作成権限一覧 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信・認証確認
   └─ authorize_admin_project!
2. パラメータのバリデーション
   └─ protected_ref_params でパラメータ取得・検証
3. 保護タグの作成/更新/削除
   └─ CreateService/UpdateService/DestroyService 呼び出し
4. レスポンス出力
   └─ リダイレクトまたはJSON
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{管理者権限?}
    B -->|No| C[アクセス拒否]
    B -->|Yes| D{操作種別}
    D -->|CREATE| E[CreateService実行]
    D -->|UPDATE| F[UpdateService実行]
    D -->|DELETE| G[DestroyService実行]
    E --> H{保存成功?}
    H -->|Yes| I[リダイレクト]
    H -->|No| J[エラー表示]
    F --> K{更新成功?}
    K -->|Yes| L[JSON成功]
    K -->|No| M[JSON エラー]
    G --> N[リダイレクト]
    J --> I
    I --> O[終了]
    L --> O
    M --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-26-01 | 名前の一意性 | プロジェクト内で保護タグ名は一意 | 常時 |
| BR-26-02 | ワイルドカード | *を使用してパターンマッチ可能 | 名前に*を含む場合 |
| BR-26-03 | 作成権限のみ | 保護タグは作成権限のみ制御（プッシュ/マージはなし） | 常時 |

### 計算ロジック

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

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

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | protected_tags | INSERT | 保護タグレコード作成 |
| 作成 | protected_tag_create_access_levels | INSERT | 作成権限レコード作成 |
| 更新 | protected_tags | UPDATE | 保護タグ設定更新 |
| 削除 | protected_tags | DELETE | 保護タグ削除（カスケード） |
| 参照 | tags | - | Gitalyからタグ一覧取得 |

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

#### protected_tags

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

#### protected_tag_create_access_levels

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

特になし

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

保護タグ作成時は、protected_tags と access_levels の挿入をトランザクションで管理

## パフォーマンス要件

- SafeRequestStore によるキャッシュ
- タグ保護チェックはプッシュ時に頻繁に呼ばれるため高速化が重要

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

- authorize_admin_project! による管理者権限の確認
- can?(:create_protected_tags) による作成権限の確認

## 備考

- 保護タグは保護ブランチと異なり、作成権限のみ制御
- 既存タグの削除は管理者のみ可能

---

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

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

### 推奨読解順序

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

保護タグのデータモデルを把握する。

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

**読解のコツ**: ProtectedTag が ProtectedRef の振る舞いを継承していることを理解する。create_access_levels のみ存在することに注目。

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

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

**主要処理フロー**:
1. **6-8行目**: ref_type - :tags を返す
2. **10-12行目**: project_refs - プロジェクトのタグ取得
3. **18-20行目**: load_protected_ref - 保護タグの読み込み
4. **22-24行目**: access_levels - 作成アクセスレベルのみ定義
5. **26-28行目**: protected_ref_params - パラメータ処理

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

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

**主要処理フロー**:
- **7-11行目**: execute - 作成処理のメインロジック
- 権限チェック後、project.protected_tags.create で保存

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

```
ProtectedTagsController#create
    │
    ├─ authorize_admin_protected_refs!
    │      └─ authorize_admin_project!
    │
    ├─ protected_ref_params
    │      └─ パラメータ取得・検証
    │
    └─ CreateService#execute
           ├─ can? 権限チェック
           └─ project.protected_tags.create
```

### データフロー図

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

フォーム入力       ───▶  ProtectedTagsController   ───▶  リダイレクト/JSON
(name, access_levels)    │
                         ▼
                    CreateService
                         │
                         ▼
                    ProtectedTag.create ──────────────▶  DB INSERT
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| protected_tags_controller.rb | `app/controllers/projects/protected_tags_controller.rb` | コントローラー | 保護タグのエントリーポイント |
| protected_refs_controller.rb | `app/controllers/projects/protected_refs_controller.rb` | コントローラー | 保護参照の基底クラス |
| protected_tag.rb | `app/models/protected_tag.rb` | モデル | 保護タグモデル |
| protected_ref.rb | `app/models/concerns/protected_ref.rb` | Concern | 保護参照の共通ロジック |
| create_service.rb | `app/services/protected_tags/create_service.rb` | サービス | 作成サービス |
