# 機能設計書 39-CLIコマンド基盤

## 概要

本ドキュメントは、JenkinsにおけるCLIコマンド基盤機能の設計を記載したものである。CLIコマンド基盤は、コマンドラインインターフェースの基盤を提供し、様々なCLIコマンドの実装を支援する。

### 本機能の処理概要

本機能は、JenkinsのCLI（コマンドラインインターフェース）の基盤となる抽象クラスとフレームワークを提供し、各種CLIコマンドの実装を標準化する。

**業務上の目的・背景**：CI/CDパイプラインでは、WebUIだけでなくコマンドラインからJenkinsを操作する需要が高い。自動化スクリプト、他システムとの連携、一括操作などでCLIは重要な役割を果たす。CLIコマンド基盤により、統一されたインターフェースで様々な操作を実行でき、開発者は新しいコマンドを容易に追加できる。

**機能の利用シーン**：
- jenkins-cli.jarを使用したリモートからのJenkins操作
- 自動化スクリプトからのジョブ実行・管理
- バルク操作（複数ジョブの一括操作）
- プラグインによる独自コマンドの追加
- SSHを通じたCLIアクセス

**主要な処理内容**：
1. コマンドライン引数のパース（args4jを使用）
2. 認証・認可の処理
3. 標準入出力のリモーティング
4. エラーハンドリングと終了コード管理
5. コマンドの動的検出と実行

**関連システム・外部連携**：jenkins-cli.jarがクライアントとして動作。SSH経由でのアクセスもサポート。args4jライブラリで引数パースを実行。CLIListenerでコマンド実行を監視。

**権限による制御**：デフォルトでJenkins.READ権限が必要。各コマンドで追加の権限チェックを実装。HelpCommandとWhoAmICommandは権限チェックなし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （画面なし） | - | CLIはコマンドラインインターフェース |

## 機能種別

CLI基盤 / コマンドフレームワーク / リモート操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| args | List<String> | Yes | コマンドライン引数 | args4jでパース |
| locale | Locale | Yes | クライアントのロケール | - |
| stdin | InputStream | Yes | 標準入力 | - |
| stdout | PrintStream | Yes | 標準出力 | - |
| stderr | PrintStream | Yes | 標準エラー出力 | - |

### 入力データソース

- CLIクライアント（jenkins-cli.jar）からのネットワーク接続
- SSH経由の接続
- HTTPトンネリング経由の接続

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| exitCode | int | コマンド終了コード（0=成功、1-15=予約、16+=カスタム） |
| stdout | PrintStream | 標準出力（結果表示） |
| stderr | PrintStream | エラー出力 |

### 終了コード定義

| コード | 意味 |
|-------|------|
| 0 | 成功 |
| 1 | 一般的な例外 |
| 2 | CmdLineException（引数エラー） |
| 3 | IllegalArgumentException |
| 4 | IllegalStateException |
| 5 | AbortException |
| 6 | AccessDeniedException |
| 7 | BadCredentialsException |
| 8-15 | 将来の拡張用に予約 |
| 16+ | カスタム終了コード |

## 処理フロー

### 処理シーケンス

```
1. コマンド受信
   └─ CLIクライアントからコマンド名と引数を受信
2. コマンド解決
   └─ CLICommand.clone(name)でコマンドインスタンスを取得
3. 認証処理
   └─ getTransportAuthentication2()で認証情報を取得
4. SecurityContext設定
   └─ 認証情報をSecurityContextHolderに設定
5. 権限チェック
   └─ Jenkins.READ権限をチェック（Help/WhoAmI以外）
6. 引数パース
   └─ args4jでコマンドライン引数をパース
7. コマンド実行
   └─ run()メソッドを呼び出し
8. 終了コード返却
   └─ 結果に応じた終了コードを返却
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド受信] --> B[コマンド解決]
    B --> C{コマンド存在?}
    C -->|No| D[エラー終了]
    C -->|Yes| E[認証情報取得]
    E --> F[SecurityContext設定]
    F --> G{Jenkins.READ?}
    G -->|No| H[AccessDeniedException]
    G -->|Yes| I[args4jで引数パース]
    I --> J{パース成功?}
    J -->|No| K[CmdLineException]
    J -->|Yes| L[run実行]
    L --> M{例外発生?}
    M -->|Yes| N[handleException]
    M -->|No| O[終了コード0]
    N --> P[適切な終了コード]
    H --> P
    K --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | デフォルト権限 | Jenkins.READ権限がデフォルトで必要 | Help/WhoAmI以外 |
| BR-39-02 | @構文制限 | ALLOW_AT_SYNTAXでファイル読込を制御 | システムプロパティ |
| BR-39-03 | 終了コード予約 | 1-15は予約済み、カスタムは16以上 | run()実装時 |
| BR-39-04 | コマンド名変換 | FooBarZotCommand → foo-bar-zot | getName()自動変換 |
| BR-39-05 | ExtensionPoint | @Extensionで動的にコマンド登録 | コマンド実装時 |

### 計算ロジック

コマンド名変換:
```
name = クラス名.substring(lastIndexOf('.') + 1)
if (name.endsWith("Command")) name = name.substring(0, length - 7)
return name.replaceAll("([a-z0-9])([A-Z])", "$1-$2").toLowerCase(Locale.ENGLISH)
```

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

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

CLIコマンド基盤自体はデータベースを操作しない。各コマンドの実装が必要に応じてデータを操作する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | 一般例外 | 予期しない例外 | スタックトレースを確認 |
| 2 | CmdLineException | 引数エラー | 使用方法を確認 |
| 3 | IllegalArgumentException | 不正な引数値 | 引数値を確認 |
| 4 | IllegalStateException | 不正な状態 | Jenkinsの状態を確認 |
| 5 | AbortException | 中断 | エラーメッセージを確認 |
| 6 | AccessDeniedException | 権限不足 | 権限を確認 |
| 7 | BadCredentialsException | 認証失敗 | 認証情報を確認 |

### リトライ仕様

CLIコマンドは冪等でない場合があるため、リトライ前に状態を確認する必要がある。

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

CLIコマンド基盤はトランザクション管理を行わない。各コマンドが必要に応じてトランザクションを管理する。

## パフォーマンス要件

- コマンド解決は高速（拡張リストからの検索）
- 認証処理はSecurityRealmに依存
- 大量のデータを扱うコマンドは適切なストリーミングが必要

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

- ALLOW_AT_SYNTAXはデフォルトでfalse（ファイル読込攻撃防止）
- 認証情報はgetTransportAuthentication2()で安全に取得
- BadCredentialsExceptionでは詳細情報を隠蔽（correlationIdでログ参照）
- Remoting経由のアクセスは廃止（SECURITY-218対策）

## 備考

- CLICommandはExtensionPointであり、@Extensionで動的に登録
- ThreadLocalでCURRENT_COMMANDを管理（getCurrent()で取得可能）
- CLIListenerでコマンド実行を監視可能
- Channelベースのリモーティングは廃止、SSH/HTTPのみサポート

---

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

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

### 推奨読解順序

#### Step 1: CLICommandの構造を理解する

CLIコマンドの基底クラスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CLICommand.java | `core/src/main/java/hudson/cli/CLICommand.java` | 基底クラス全体 |

**主要処理フロー**:
- **105行目**: CLICommandクラス定義（ExtensionPoint実装）
- **112-114行目**: ALLOW_AT_SYNTAX設定
- **125-154行目**: stdin, stdout, stderr, locale, encoding, transportAuthフィールド
- **168-188行目**: getName() - コマンド名の自動生成
- **194行目**: getShortDescription() - 概要（抽象メソッド）
- **236-273行目**: main() - メインエントリーポイント
- **404行目**: run() - 実行メソッド（抽象メソッド）

**読解のコツ**: main()メソッドが実際のエントリーポイントで、認証設定、引数パース、run()呼び出しを行う。run()は各サブクラスで実装。

#### Step 2: エラーハンドリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CLICommand.java | `core/src/main/java/hudson/cli/CLICommand.java` | handleException()メソッド |

**主要処理フロー**:
- **278-306行目**: handleException() - 例外種別ごとの終了コード決定
- **280-283行目**: CmdLineException → 終了コード2
- **284-286行目**: IllegalArgumentException → 終了コード3
- **287-289行目**: IllegalStateException → 終了コード4
- **290-292行目**: AbortException → 終了コード5
- **293-295行目**: AccessDeniedException → 終了コード6
- **296-299行目**: BadCredentialsException → 終了コード7

#### Step 3: コマンドの登録と取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CLICommand.java | `core/src/main/java/hudson/cli/CLICommand.java` | all()とclone()静的メソッド |

**主要処理フロー**:
- **531-533行目**: all() - ExtensionList.lookup(CLICommand.class)
- **538-543行目**: clone(name) - 名前からコマンドインスタンスを取得

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

```
CLIクライアント
    │
    └─ HTTP/SSH経由でJenkinsに接続
           │
           └─ CLICommand.clone(commandName)
                  │
                  ├─ all()でExtensionListを取得
                  │
                  └─ 名前一致でcreateClone()
                         │
                         └─ CLICommand.main(args, locale, stdin, stdout, stderr)
                                │
                                ├─ getTransportAuthentication2()
                                │
                                ├─ SecurityContext設定
                                │
                                ├─ Jenkins.READ権限チェック
                                │
                                ├─ CmdLineParser.parseArgument()
                                │
                                ├─ CLIListener.onExecution()
                                │
                                ├─ run() [サブクラス実装]
                                │
                                └─ CLIListener.onCompleted() または onThrowable()
```

### データフロー図

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

args ─────────────────▶ CLICommand.main() ─────────────▶ exitCode
locale ───────────────▶        │
stdin ────────────────▶        │                         stdout
stdout ───────────────▶        ▼                         stderr
stderr ───────────────▶ CmdLineParser.parseArgument()
                               │
                               ▼
                         run() [サブクラス]
                               │
                               ▼
                     ┌─────────┴─────────┐
                     ▼                   ▼
               成功(return 0)      例外発生
                                        │
                                        ▼
                               handleException()
                                        │
                                        ▼
                               終了コード決定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CLICommand.java | `core/src/main/java/hudson/cli/CLICommand.java` | ソース | CLIコマンドの基底クラス |
| CLI.java | `core/src/main/java/hudson/cli/CLI.java` | ソース | CLIクライアント |
| HelpCommand.java | `core/src/main/java/hudson/cli/HelpCommand.java` | ソース | ヘルプコマンド実装 |
| WhoAmICommand.java | `core/src/main/java/hudson/cli/WhoAmICommand.java` | ソース | 認証確認コマンド |
| CLIRegisterer.java | `core/src/main/java/hudson/cli/declarative/CLIRegisterer.java` | ソース | @CLIMethod登録 |
| CLIListener.java | `core/src/main/java/jenkins/cli/listeners/CLIListener.java` | ソース | コマンド実行監視 |
| CLIContext.java | `core/src/main/java/jenkins/cli/listeners/CLIContext.java` | ソース | 実行コンテキスト |
