# 帳票設計書 12-subresource-integrity-manifest

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `subresource-integrity-manifest`（SRIマニフェスト）の設計仕様を定義する。本マニフェストは、Subresource Integrity（SRI）ハッシュ情報を管理し、ブラウザが読み込むリソースの改ざん検知を可能にするセキュリティ機能を提供する。

### 本帳票の処理概要

本マニフェストは、Next.jsのビルド時に `SubresourceIntegrityPlugin` によって生成されるJSON/JSファイルであり、コンパイル済みアセット全てのSRIハッシュ値を算出し、ファイル名とハッシュ値の対応関係をマッピングする。

**業務上の目的・背景**：Webアプリケーションのセキュリティ強化のため、配信されるJavaScript・CSSなどのリソースが改ざんされていないことをブラウザが検証できる仕組みが必要である。Subresource Integrity（SRI）は、W3C標準仕様であり、`<script>` や `<link>` タグに `integrity` 属性を付与することで、CDN等を介したリソースの改ざんを検知する。本マニフェストはその基盤となるハッシュ情報を一括管理する。

**帳票の利用シーン**：`next.config.js` の `experimental.sri.algorithm` が設定されている場合にのみ生成される。ビルド時（`next build`）にWebpackコンパイルフェーズで自動生成され、サーバーサイドレンダリング時にHTMLの `<script>` / `<link>` タグに `integrity` 属性を付与するために参照される。

**主要な出力内容**：
1. 全コンパイル済みアセットのファイルパスとSRIハッシュ値の対応マップ
2. ハッシュアルゴリズムの識別子（sha256, sha384, sha512）を含む完全なSRIハッシュ文字列

**帳票の出力タイミング**：`next build` コマンド実行時のWebpackコンパイルフェーズ（`PROCESS_ASSETS_STAGE_ADDITIONS` 後の `afterProcessAssets` フック）で生成される。SRI機能が有効（`experimental.sri.algorithm` 設定あり）な場合のみ生成される。

**帳票の利用者**：Next.jsフレームワーク内部のサーバーレンダリングエンジン（`load-components.ts`）。エッジランタイムでも `middleware-plugin.ts` を通じて参照される。開発者がセキュリティ監査目的で参照する場合もある。

## 帳票種別

ビルドマニフェスト（JSON/JavaScript形式・セキュリティ用途）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `next build` | ビルド実行（SRI有効時のみ） |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON (.json) および JavaScript (.js) |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | `subresource-integrity-manifest.json` / `subresource-integrity-manifest.js` |
| 出力方法 | ファイルシステムへの書き込み |
| 文字コード | UTF-8 |

### JSON形式

```json
{
  "static/chunks/main-abc123.js": "sha256-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "static/css/styles-def456.css": "sha256-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
}
```

### JavaScript形式（エッジランタイム向け）

```javascript
self.__SUBRESOURCE_INTEGRITY_MANIFEST="{\"static/chunks/main-abc123.js\":\"sha256-XXXX...\"}"
```

## 帳票レイアウト

### レイアウト概要

マニフェストはフラットなキー・バリューマップで構成される。

```
┌─────────────────────────────────────────────────────┐
│  { [assetPath: string]: sriHash: string }           │
│                                                     │
│  例:                                                │
│  "static/chunks/main.js": "sha256-base64hash..."   │
│  "static/css/style.css": "sha256-base64hash..."    │
└─────────────────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | アセットパス（キー） | コンパイル済みアセットの相対パス | Webpackコンパイルのアセットリスト | 文字列 |
| 2 | SRIハッシュ（値） | `algorithm-base64hash` 形式のSRIハッシュ文字列 | アセットのバイナリコンテンツからcryptoモジュールで算出 | `sha256-xxx` / `sha384-xxx` / `sha512-xxx` |

### 明細部

N/A（フラットマップ構造）

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| SRI機能有効 | `config.experimental.sri.algorithm` が設定されていること | Yes |
| 全アセット対象 | コンパイル結果の全アセットが対象 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| N/A | ソート指定なし | アセット登録順 |

### 改ページ条件

N/A（データファイル）

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

### 参照テーブル一覧

N/A（データベースを使用しない）

### テーブル別参照項目詳細

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| SRIハッシュ | `crypto.createHash(algorithm).update(buffer).digest().toString('base64')` | N/A | アルゴリズムは sha256, sha384, sha512 のいずれか |
| SRI文字列 | `${algorithm}-${hash}` | N/A | アルゴリズム名とBase64ハッシュをハイフンで連結 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Webpackコンパイル開始] --> B[SubresourceIntegrityPlugin.apply]
    B --> C[afterProcessAssets フック]
    C --> D[全アセットファイルを収集・重複排除]
    D --> E[各ファイルのバイナリ取得]
    E --> F[crypto.createHashでハッシュ計算]
    F --> G[algorithm-base64hash形式で格納]
    G --> H{全アセット処理完了?}
    H -->|No| E
    H -->|Yes| I[JSON文字列化]
    I --> J[server/subresource-integrity-manifest.json出力]
    I --> K[server/subresource-integrity-manifest.js出力]
    J --> L[終了]
    K --> L
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| アセット取得失敗 | compilation.getAsset(file)がnullを返す場合 | `could not get asset: ${file}` | ビルドエラーとして報告。アセット生成の問題を調査 |
| SRI未設定 | experimental.sri.algorithmが未設定 | エラーなし（プラグイン未登録） | 対処不要（機能が無効） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | プロジェクトのアセット総数に依存（通常数十〜数百件） |
| 目標出力時間 | 暗号ハッシュ計算のため、アセット数・サイズに比例。通常は数秒以内 |
| 同時出力数上限 | 1（ビルドプロセスごとに1回） |

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

本マニフェスト自体がセキュリティ機能の基盤である。サーバーサイドに格納され、クライアントには直接配信されない。マニフェスト内のハッシュ値はHTMLレンダリング時に `integrity` 属性としてタグに付与される。マニフェストファイルへの不正アクセスや改ざんはSRI機能の無効化につながるため、サーバーファイルの保護が重要である。

## 備考

- 対応するハッシュアルゴリズムは `sha256`, `sha384`, `sha512` の3種類（`SubresourceIntegrityAlgorithm` 型で定義）。
- エッジランタイムではJS形式のマニフェストが `self.__SUBRESOURCE_INTEGRITY_MANIFEST` として読み込まれる。
- ミドルウェアプラグインでは、SRI有効時にサーバーコンポーネントのエッジファイルリストに `server/subresource-integrity-manifest.js` が追加される（middleware-plugin.ts 111-113行目）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | subresource-integrity-plugin.ts | `packages/next/src/build/webpack/plugins/subresource-integrity-plugin.ts` | 7行目: `SubresourceIntegrityAlgorithm` 型定義（`'sha256' \| 'sha384' \| 'sha512'`） |
| 1-2 | constants.ts | `packages/next/src/shared/lib/constants.ts` | 93行目: `SUBRESOURCE_INTEGRITY_MANIFEST` 定数（値: `'subresource-integrity-manifest'`） |
| 1-3 | load-components.ts | `packages/next/src/server/load-components.ts` | 78行目: `subresourceIntegrityManifest` フィールドの型（`Record<string, string>`） |

**読解のコツ**: マニフェストの構造は単純なキー・バリューマップであり、キーがアセットパス、値がSRIハッシュ文字列である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | subresource-integrity-plugin.ts | `packages/next/src/build/webpack/plugins/subresource-integrity-plugin.ts` | 9-10行目: コンストラクタでアルゴリズムを受け取る。12-69行目: `apply` メソッドでWebpackフックに登録 |

**主要処理フロー**:
1. **13行目**: `compiler.hooks.make.tap` でコンパイルフェーズにフック登録
2. **14-17行目**: `compilation.hooks.afterProcessAssets.tap` で `PROCESS_ASSETS_STAGE_ADDITIONS` 後に実行
3. **21-24行目**: 全アセットをSetに収集（重複排除）
4. **28-46行目**: 各アセットのバッファを取得しハッシュを計算
5. **48-65行目**: JSON形式とJS形式で出力

#### Step 3: マニフェストの利用箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | load-components.ts | `packages/next/src/server/load-components.ts` | 24行目: `SUBRESOURCE_INTEGRITY_MANIFEST` のインポート。ページコンポーネント読み込み時にマニフェストも読み込まれる |
| 3-2 | middleware-plugin.ts | `packages/next/src/build/webpack/plugins/middleware-plugin.ts` | 111-113行目: SRI有効時にエッジファイルリストにSRIマニフェストを追加 |

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

```
next build (packages/next/src/build/index.ts)
    |
    +-- Webpack Compilation (SRI有効時のみ)
    |       |
    |       +-- SubresourceIntegrityPlugin.apply()
    |               |
    |               +-- compiler.hooks.make.tap()
    |                       |
    |                       +-- compilation.hooks.afterProcessAssets.tap()
    |                               |
    |                               +-- compilation.getAssets() [全アセット収集]
    |                               +-- crypto.createHash() [各アセットのハッシュ計算]
    |                               +-- compilation.emitAsset() [.json]
    |                               +-- compilation.emitAsset() [.js]
    |
    +-- サーバーレンダリング時
            |
            +-- loadComponents()
                    +-- loadManifest(SUBRESOURCE_INTEGRITY_MANIFEST)
```

### データフロー図

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

Webpack compiled     SubresourceIntegrityPlugin         .next/server/subresource-integrity-manifest.json
  assets         -->   (全アセットのSRIハッシュ計算)  --> .next/server/subresource-integrity-manifest.js
  (JS/CSS等)           crypto.createHash(algorithm)

                       loadComponents()                 HTML <script integrity="...">
  manifest.json  -->   (マニフェスト読み込み)       -->  HTML <link integrity="...">
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| subresource-integrity-plugin.ts | `packages/next/src/build/webpack/plugins/subresource-integrity-plugin.ts` | ソース | Webpackプラグイン。SRIハッシュ計算とマニフェスト生成 |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | `SUBRESOURCE_INTEGRITY_MANIFEST` 定数定義 |
| load-components.ts | `packages/next/src/server/load-components.ts` | ソース | サーバーサイドでのマニフェスト読み込み |
| middleware-plugin.ts | `packages/next/src/build/webpack/plugins/middleware-plugin.ts` | ソース | エッジランタイムでのSRIマニフェスト参照 |
| route-loader.ts | `packages/next/src/client/route-loader.ts` | ソース | クライアントサイドの `__SUBRESOURCE_INTEGRITY_MANIFEST` グローバル変数宣言 |
| route-module.ts | `packages/next/src/server/route-modules/route-module.ts` | ソース | ルートモジュールでのマニフェスト利用 |
| index.ts | `packages/next/src/build/index.ts` | ソース | ビルドプロセスでのSRI設定確認 |
