Skip to content

[Feature] インデックス共有モード(--shared / CI連携) #77

@Kewton

Description

@Kewton

概要

CI/CDパイプラインやチーム共有サーバーでインデックスを事前生成し、チームメンバーが再利用できる仕組みを提供する。

背景・動機

大規模リポジトリでは commandindex index の初回実行に時間がかかる。CIでインデックスを事前生成し、チームメンバーがダウンロードして利用できると、オンボーディングや日常利用が効率化する。

提案する解決策

インデックスのエクスポート/インポート

既存の index サブコマンドの単一責任パターンを維持するため、エクスポート/インポートは独立したサブコマンドとして設計する。

# インデックスをtar.gzにエクスポート
commandindex export index-snapshot.tar.gz

# エクスポートされたインデックスをインポート
commandindex import index-snapshot.tar.gz

# 既存インデックスを上書きインポート
commandindex import index-snapshot.tar.gz --force

# インデックスの整合性チェック
commandindex status --verify

CI連携例

# GitHub Actions
- name: Build CommandIndex
  run: |
    commandindex index
    commandindex export /tmp/commandindex-snapshot.tar.gz

- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: commandindex-snapshot
    path: /tmp/commandindex-snapshot.tar.gz

エクスポートフォーマット

  • .commandindex/ ディレクトリをtar.gzで圧縮(ストリーミングAPIを使用してメモリ使用量を抑制)
  • アーカイブ内に export_meta.json を含め、以下のメタデータを記録:
    • export_format_version: エクスポートフォーマットのバージョン(state.json の schema_version とは独立管理)
    • commandindex_version: CommandIndexのバージョン
    • git_commit_hash: エクスポート時のGitコミットハッシュ
    • exported_at: エクスポート日時
  • インポート時に export_format_version の互換性チェックを実施
  • インポート時にコミットハッシュの一致を確認(不一致の場合は警告)
  • インポート時に state.jsonindex_root をインポート先のパスに自動書き換え
  • エクスポート対象から config.local.toml を除外(個人設定・APIキー保護)
  • embeddings.db はデフォルトで除外し、--with-embeddings フラグで明示的に含める

エクスポート対象ファイル

ファイル 説明 パス形式 デフォルト
tantivy/ 全文検索インデックス - 含む
state.json インデックス状態 相対パス 含む
manifest.json ファイルマニフェスト 相対パス 含む
symbols.db シンボルデータベース 相対パス 含む
export_meta.json エクスポートメタデータ - 含む(自動生成)
embeddings.db Embeddingデータベース 相対パス 除外(--with-embeddingsで含む)

config.local.toml はセキュリティ上の理由からエクスポート対象外
※ SQLite内のファイルパスは全て相対パスで格納されており、index_root の書き換えのみでポータビリティを確保

セキュリティ要件

  • インポート時、アーカイブ内の全エントリが展開先ディレクトリ内に収まることを検証
  • パストラバーサル(../../ 等の相対パスや絶対パス)を検出した場合はエラーで中断
  • tar クレートの Archive::unpack() はデフォルトでパストラバーサルを防止しないため、エントリごとに path().starts_with(target_dir) で検証
  • 悪意あるアーカイブに対するテストケースを含める

既存インデックスがある場合の動作

  • インポート先に既に .commandindex/ が存在する場合は警告を表示
  • --force フラグがなければインポートを中断(明確なエラーメッセージを表示)
  • --force 指定時は既存インデックスを上書き

--verify オプション

  • state.jsonschema_version 確認
  • tantivy インデックスディレクトリの存在と読み取り可能性確認
  • tantivy インデックスのオープン可能性確認(整合性チェック)
  • manifest.json に記載されたファイルの存在確認
  • symbols.db のスキーマバージョン確認

依存クレート

  • tar (0.4): tarアーカイブの作成・展開(純Rust、クロスコンパイル影響なし)
  • flate2 (1): gzip圧縮・解凍(純Rust、クロスコンパイル影響なし)

※ 両クレートは既に lindera-dictionary の build-dependencies としてトランジティブに依存ツリーに存在

実装上の注意点

  • src/cli/mod.rspub mod export; pub mod import_index; を追加
  • src/main.rsCommands enum に Export / Import バリアントを追加
  • status --verifyStatusOptions 構造体を導入し、既存の run() シグネチャとの互換性を保つ
  • export/import 後の tantivy インデックス整合性を統合テストで検証
  • tests/cli_args.rs に export/import の存在検証を追加

受け入れ基準

  • commandindex export <PATH> でインデックスをtar.gzにエクスポートできる
  • commandindex import <PATH> でインデックスをインポートできる
  • --with-embeddings フラグで embeddings.db を含めてエクスポートできる
  • インポート後の検索が正常に動作する
  • インポート後に tantivy インデックスが正常にオープンできる
  • commandindex status --verify でインデックスの整合性チェックができる
  • コミットハッシュ不一致時に警告メッセージが表示される
  • export_format_version の互換性チェックが動作する
  • インポート時にパストラバーサル攻撃を検出してエラーで中断する
  • 既存インデックスがある場合に警告を表示し、--force なしでは中断する
  • インポート後に index_root がインポート先のパスに更新されている
  • config.local.toml がエクスポートに含まれない
  • embeddings.db がデフォルトでエクスポートに含まれない
  • cargo test / clippy / fmt 全パス

依存 Issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions