# 帳票設計書 6-SARIF Report

## 概要

本ドキュメントは、scan-buildツールのSARIF形式レポート機能の設計仕様を記載する。静的解析結果をSARIF（Static Analysis Results Interchange Format）形式で出力・マージする機能である。

### 本帳票の処理概要

SARIF Reportは、Clang Static Analyzerの解析結果をSARIF形式（JSON）で出力し、複数の解析結果ファイルを1つにマージする機能を提供する。SARIFは静的解析ツール間でのデータ交換標準フォーマットである。

**業務上の目的・背景**：異なる静的解析ツールの結果を統一的に扱うため、業界標準のSARIF形式が普及している。本機能は、Clang Static Analyzerの結果をSARIF形式に変換することで、GitHub Code Scanning、Visual Studio、その他のSARIF対応ツールとの連携を可能にする。複数のコンパイル単位から生成された解析結果を1つのファイルにマージすることで、プロジェクト全体の解析結果を一元管理できる。

**帳票の利用シーン**：GitHub Code Scanningへのアップロード、Visual Studioでの解析結果表示、CI/CDパイプラインでのセキュリティスキャン結果統合、複数ツール間での解析結果比較時に利用される。

**主要な出力内容**：
1. SARIF 2.1.0形式のJSONファイル
2. 複数の.sarifファイルをマージしたresults-merged.sarif
3. runs配列（各解析実行を表す）
4. results配列（検出された問題）
5. 埋め込みリンクのrun index更新

**帳票の出力タイミング**：scan-buildコマンドでsarifまたはsarif-html形式を指定した場合に生成される。

**帳票の利用者**：DevSecOpsエンジニア、セキュリティエンジニア、CI/CD管理者、品質管理者

## 帳票種別

JSON形式レポート（SARIF 2.1.0）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | コマンドライン | `scan-build --output-format sarif` | ビルド完了時 |
| - | GitHub | Code Scanning | SARIFアップロード |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（SARIF 2.1.0） |
| 用紙サイズ | - |
| 向き | - |
| ファイル名 | *.sarif（個別）、results-merged.sarif（マージ後） |
| 出力方法 | ファイル出力 |
| 文字コード | UTF-8 |

### SARIF固有設定

| 項目 | 内容 |
|-----|------|
| スキーマバージョン | 2.1.0 |
| JSONインデント | 4スペース |
| ソートキー | sort_keys=True |

## 帳票レイアウト

### レイアウト概要

SARIF JSONの構造は以下の通り。

```json
{
  "$schema": "https://...",
  "version": "2.1.0",
  "runs": [
    {
      "tool": { ... },
      "results": [
        {
          "ruleId": "...",
          "message": { "text": "..." },
          "locations": [ ... ]
        }
      ]
    }
  ]
}
```

### トップレベル構造

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | $schema | SARIFスキーマURL | 固定値 | URL文字列 |
| 2 | version | SARIFバージョン | 固定値 | "2.1.0" |
| 3 | runs | 解析実行配列 | 各.sarifファイル | 配列 |

### runs配列要素

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | tool | ツール情報 | Clang情報 | オブジェクト |
| 2 | results | 検出結果配列 | 解析結果 | 配列 |
| 3 | artifacts | 解析対象ファイル | ソースファイル | 配列 |

### results配列要素

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ruleId | ルールID | BugType | 文字列 |
| 2 | level | 重大度 | warning/error | 文字列 |
| 3 | message | メッセージ | Description | オブジェクト |
| 4 | locations | 位置情報 | SourceLocation | 配列 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| output_format | sarif, sarif-html | Yes |
| .sarifファイル存在 | 出力ディレクトリに.sarifあり | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | JSONキー | 昇順（sort_keys=True） |

### マージ条件

- 各.sarifファイルのrunsをマージ
- 埋め込みリンク（sarif:/runs/N）のrun indexを更新

## データベース参照仕様

### 参照データソース一覧

| データソース | 用途 | 取得方法 |
|-------------|------|---------|
| *.sarif | 個別SARIF | json.load() |

### 埋め込みリンク更新

| パターン | 説明 |
|---------|------|
| `sarif:/runs/(\d+)` | run indexを参照する埋め込みリンク |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| runs_count | 累積runs数 | - | マージ時のオフセット |
| new_run_index | runs_count_offset + int(match.group(1)) | - | 更新後のindex |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[document関数] --> B{sarif形式?}
    B -->|Yes| C[merge_sarif_files呼出]
    B -->|No| Z[終了]
    C --> D[.sarifファイル一覧取得]
    D --> E[merged辞書初期化]
    E --> F{次のファイル?}
    F -->|Yes| G[json.load]
    G --> H{runsあり?}
    H -->|No| F
    H -->|Yes| I{初回?}
    I -->|Yes| J[mergedに設定]
    I -->|No| K[各runについて]
    K --> L[update_sarif_object]
    L --> M[merged.runs.append]
    M --> N[runs_count更新]
    N --> F
    J --> F
    F -->|No| O[results-merged.sarif出力]
    O --> Z
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| JSON読込エラー | 不正なJSON | json.JSONDecodeError | 例外発生 |
| ファイルなし | .sarifファイル0個 | (空のマージ結果) | 正常終了 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数十〜数百.sarifファイル |
| 目標出力時間 | 数秒 |
| 同時出力数上限 | 1 |

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

- ソースコードパスがJSONに含まれる
- セキュリティ脆弱性情報が含まれる可能性

## 備考

- SARIF 2.1.0はOASIS標準
- GitHub Code Scanning、Azure DevOps、Visual Studioで利用可能
- 埋め込みリンクのrun index更新により、マージ後も内部リンクが正しく機能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | report.py | `clang/tools/scan-build-py/lib/libscanbuild/report.py` | document()内のsarif_reports_available判定（行30, 62-64） |

**読解のコツ**: output_formatが"sarif"または"sarif-html"の場合にmerge_sarif_files()が呼ばれる。

#### Step 2: マージ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | report.py | 同上 | merge_sarif_files()関数（行360-458） |

**主要処理フロー**:
- **行367-369**: empty()ヘルパー関数定義
- **行371-402**: update_sarif_object()で再帰的にメッセージ更新
- **行404-426**: match_and_update_run()で埋め込みリンク更新
- **行428-436**: .sarifファイル一覧取得
- **行438-455**: ファイルごとのマージループ
- **行457-458**: results-merged.sarif出力

#### Step 3: 埋め込みリンク更新を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | report.py | 同上 | match_and_update_run()（行404-426）の正規表現処理 |

**主要処理フロー**:
- **行413**: `sarif:/runs/(\d+)` パターンでマッチ
- **行420-423**: 右から左へマッチを置換（文字長増加対応）

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

```
document()
    │
    └─ merge_sarif_files()
           │
           ├─ glob.iglob("*.sarif")
           │
           └─ ファイルごとのループ
                  │
                  ├─ json.load()
                  │
                  ├─ update_sarif_object() [再帰]
                  │      │
                  │      └─ match_and_update_run()
                  │             └─ re.finditer("sarif:/runs/(\d+)")
                  │
                  └─ merged["runs"].append()

           └─ json.dump(merged, "results-merged.sarif")
```

### データフロー図

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

file1.sarif ────────┐
                    │
file2.sarif ────────┼──▶ merge_sarif_files()
                    │           │
file3.sarif ────────┘           │
                                ▼
                    ┌───────────────────────┐
                    │ runs_count = 0        │
                    │ merged = {}           │
                    └───────────┬───────────┘
                                │
                    ┌───────────┴───────────┐
                    │ 各ファイルについて:    │
                    │ 1. json.load()         │
                    │ 2. update_sarif_object │
                    │ 3. runs_count += len   │
                    └───────────┬───────────┘
                                │
                                ▼
                    results-merged.sarif
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| report.py | `clang/tools/scan-build-py/lib/libscanbuild/report.py` | ソース | merge_sarif_files()実装（行360-458） |
| *.sarif | output_dir/ | 入力 | 個別SARIF結果 |
| results-merged.sarif | output_dir/ | 出力 | マージ済みSARIF |
