Skip to content

[FEATURE] LSP Hybrid Analysis Support with Optional Binary Path Configuration #137

@HikaruEgashira

Description

@HikaruEgashira

Feature Summary

Parsentryの既存Tree-sitter解析基盤に、オプション設定によるLSP(Language Server Protocol)統合を追加する。ユーザーが言語ごとにLSP binパスを指定した場合のみLSPを利用し、指定がない場合は従来のTree-sitter解析を継続する柔軟なハイブリッドアプローチを実装する。

前提条件: このissueは #138 (Configuration File Support) の完了後に実装予定

Problem Statement

現在のParsentryはTree-sitterベースの構文解析のみを提供しており、以下の制限があります:

構文レベル解析の限界:

  • 型情報・スコープ解決が不正確
  • インポート関係・モジュール依存の追跡困難
  • IDE統合機能の欠如
  • 動的型付け言語での解析精度低下

セキュリティ分析への影響:

  • 型起因の脆弱性(型強制、デシリアライゼーション等)の検出困難
  • クラス継承・インターフェース実装を通じたデータフロー追跡の限界
  • ジェネリクス・テンプレートでの型安全性検証不足

ユーザビリティの課題:

  • エディタでのリアルタイム脆弱性検出不可
  • 開発者のワークフローとの統合困難
  • CI/CDパイプラインでの段階的導入が困難

Proposed Solution

既存Tree-sitter基盤を維持しながら、設定ファイル(#138)を活用したLSP統合を実現するハイブリッドアーキテクチャを実装します。

1. 設定ファイル統合(#138依存)

# parsentry.toml - LSP設定セクション
[extensions.lsp]
enabled = true

[extensions.lsp.servers]
rust-analyzer = "/usr/bin/rust-analyzer"
typescript-language-server = "/usr/local/bin/typescript-language-server"
pylsp = "/usr/bin/pylsp"
gopls = "/usr/bin/gopls"
java-language-server = "/usr/bin/jdtls"

[extensions.lsp.settings]
use_lsp_when_available = true
lsp_timeout_ms = 5000
fallback_to_tree_sitter = true
max_concurrent_lsp_servers = 3

[extensions.lsp.features]
enhanced_definition_resolution = true
semantic_token_analysis = true
hover_information_extraction = true
reference_counting = true

2. CLI オプション拡張

# 設定ファイル経由での使用(推奨)
parsentry --config parsentry.toml

# 個別LSP指定(オーバーライド用)
parsentry --config parsentry.toml --lsp-rust-analyzer /custom/path/rust-analyzer

# 環境変数での設定
PARSENTRY_LSP_RUST_ANALYZER=/usr/bin/rust-analyzer parsentry

3. ハイブリッド解析エンジン

pub struct HybridCodeParser {
    tree_sitter_parser: CodeParser,
    lsp_managers: HashMap<Language, LspManager>,
    config: LspConfig,  // #138から提供される設定システム
}

pub struct EnhancedDefinition {
    pub basic_info: Definition,           // Tree-sitter基本情報
    pub type_info: Option<TypeInfo>,      // LSP型情報
    pub documentation: Option<String>,    // LSPドキュメント
    pub semantic_tokens: Vec<SemanticToken>, // LSPセマンティック情報
}

impl HybridCodeParser {
    pub async fn find_definition_enhanced(
        &mut self, 
        name: &str, 
        file: &Path
    ) -> Result<EnhancedDefinition> {
        let language = self.get_language(file);
        
        // LSPが設定で有効化されている場合のみ使用
        if self.config.extensions.lsp.enabled {
            if let Some(lsp) = self.lsp_managers.get(&language) {
                match timeout(
                    Duration::from_millis(self.config.extensions.lsp.settings.lsp_timeout_ms),
                    lsp.find_definition(name, file)
                ).await {
                    Ok(Ok(lsp_result)) => {
                        return Ok(EnhancedDefinition::from_lsp(lsp_result));
                    }
                    Ok(Err(e)) => log::warn\!("LSP error: {}, falling back to Tree-sitter", e),
                    Err(_) => log::warn\!("LSP timeout, falling back to Tree-sitter"),
                }
            }
        }
        
        // フォールバック:Tree-sitter使用
        let ts_result = self.tree_sitter_parser.find_definition(name, file)?;
        Ok(EnhancedDefinition::from_tree_sitter(ts_result))
    }
}

4. セキュリティ分析統合

pub struct SecurityAnalysisEnhancer {
    hybrid_parser: HybridCodeParser,
    security_patterns: SecurityRiskPatterns,
}

impl SecurityAnalysisEnhancer {
    pub async fn analyze_with_type_safety(
        &mut self, 
        file: &Path
    ) -> Result<Vec<EnhancedSecurityFinding>> {
        let mut findings = Vec::new();
        
        // 型情報を活用したセキュリティパターン検出
        for pattern in &self.security_patterns.type_safety_patterns {
            let enhanced_defs = self.hybrid_parser
                .find_pattern_matches(pattern, file).await?;
                
            for def in enhanced_defs {
                if let Some(type_info) = &def.type_info {
                    // 型安全性違反の検出
                    if self.check_type_vulnerability(type_info, pattern) {
                        findings.push(EnhancedSecurityFinding {
                            basic_finding: def.basic_info,
                            vulnerability_type: pattern.vuln_type,
                            type_context: Some(type_info.clone()),
                            severity: self.calculate_severity(type_info, pattern),
                        });
                    }
                }
            }
        }
        
        Ok(findings)
    }
}

Use Cases

1. 段階的LSP導入

# フェーズ1: Rustプロジェクトのみrust-analyzer使用
[extensions.lsp]
enabled = true

[extensions.lsp.servers]
rust-analyzer = "/usr/bin/rust-analyzer"

# フェーズ2: TypeScriptも追加
[extensions.lsp.servers]
rust-analyzer = "/usr/bin/rust-analyzer"
typescript-language-server = "/usr/bin/typescript-language-server"

効果: プロジェクト特性に応じた柔軟なLSP導入、従来環境への影響ゼロ

2. IDE統合向けリアルタイム分析

# エディタプラグイン向け軽量モード
parsentry --config editor-mode.toml --realtime-mode

効果: エディタでのリアルタイム脆弱性検出、開発者体験向上

3. CI/CDでの段階的精度向上

# CI設定例
- name: Security Analysis (Fast)
  run: parsentry --config ci-fast.toml  # Tree-sitterのみ
  
- name: Security Analysis (Enhanced)
  run: parsentry --config ci-enhanced.toml  # LSP有効
  if: github.event_name == 'pull_request'

効果: 通常のCI実行速度維持、重要時のみ高精度分析

4. 型安全性脆弱性の高精度検出

# 型情報を活用したセキュリティ分析
parsentry --config lsp-enabled.toml --focus-type-safety

効果:

  • unsafeブロック内の未定義動作検出
  • 型強制による情報漏洩リスク特定
  • ジェネリクス境界違反の検出

5. マルチ言語プロジェクトでの統一分析

[extensions.lsp.servers]
rust-analyzer = "/usr/bin/rust-analyzer"
typescript-language-server = "/usr/bin/typescript-language-server"
pylsp = "/usr/bin/pylsp"
gopls = "/usr/bin/gopls"

効果: 言語横断的なデータフロー追跡、FFI境界での脆弱性検出

Feature Type

Analysis improvement

Priority

High - Critical for adoption

Dependencies

Implementation Subtasks (Maintainer Use)

Design Subtasks

  • ハイブリッドアーキテクチャ設計: HybridCodeParserとLSP統合レイヤー設計
  • 設定統合設計: #138の設定システムとLSP設定の統合設計
  • LSPクライアントアーキテクチャ: 非同期LSP通信、タイムアウト、フォールバック機構
  • 型情報データモデル: LSP型情報のセキュリティ分析用データ構造設計
  • パフォーマンス要件定義: LSP起動オーバーヘッド、メモリ使用量の上限設定

Implementation Subtasks

  • 基本LSP統合: tower-lspを使用したLSPクライアント実装
  • 設定システム統合: #138の設定システムとLSP設定の統合実装
  • ハイブリッドパーサー実装: Tree-sitter + LSPの統合解析エンジン
  • 型安全性分析: LSP型情報を活用したセキュリティパターン検出
  • 非同期フォールバック: LSPタイムアウト時のTree-sitterフォールバック
  • リソース管理: LSPサーバープロセスのライフサイクル管理
  • エラーハンドリング: LSP通信エラー、プロセス異常終了の適切な処理

Documentation Subtasks

  • LSP設定ガイド: 各言語LSPサーバーのインストール・設定手順
  • パフォーマンス比較: Tree-sitter vs LSPハイブリッドの性能ベンチマーク
  • セキュリティ分析向上例: LSP導入による脆弱性検出精度向上の実例
  • CI/CD統合ベストプラクティス: 段階的LSP導入のパターン集
  • エディタ統合ガイド: VS Code、Vim、Emacsでの設定例

Validation Subtasks

  • 単体テスト: LSPクライアント、設定統合、ハイブリッドパーサーのテスト
  • 統合テスト: 各言語LSPサーバーとの実際の通信テスト
  • パフォーマンステスト: LSP使用時の起動時間、メモリ使用量測定
  • 精度比較テスト: Tree-sitter vs LSPハイブリッドの脆弱性検出精度比較
  • エラー処理テスト: LSPサーバー異常時のフォールバック動作検証
  • 実プロジェクト検証: validation-benchmarksでのLSPハイブリッド分析検証

Alternative Solutions

1. 完全LSP移行

メリット: 最高精度の解析、IDE統合の容易さ
デメリット:

  • 既存Tree-sitter資産の廃棄
  • LSP依存による複雑性増大
  • 起動時間の大幅増加(現在<10ms → 500-2000ms)
    判断: 既存基盤を活かしつつ段階的に精度向上できるハイブリッドが最適

2. Tree-sitter強化のみ

メリット: 実装コストが低い、高速性の維持
デメリット:

  • 型情報取得の根本的困難
  • IDE統合機能の実現困難
  • セマンティック解析の限界
    判断: セキュリティ分析の精度向上には限界があり、LSP統合が必要

3. プラグインシステム

メリット: モジュラーな設計、サードパーティ拡張可能
デメリット:

  • 設計・実装の複雑性増大
  • プラグイン品質管理の困難
  • LSP統合の標準化困難
    判断: コア機能としてのLSP統合が使いやすさで優位

Additional Context

技術的実装詳細

LSP統合レイヤー:

pub struct LspManager {
    process: Child,
    stdin: ChildStdin,
    stdout: BufReader<ChildStdout>,
    request_id: AtomicU64,
    pending_requests: HashMap<u64, oneshot::Sender<LspResponse>>,
}

impl LspManager {
    pub async fn initialize(&mut self, root_uri: &str) -> Result<()> {
        let init_request = lsp_types::InitializeParams {
            root_uri: Some(Url::parse(root_uri)?),
            capabilities: ClientCapabilities::default(),
            ..Default::default()
        };
        
        self.send_request("initialize", init_request).await?;
        self.send_notification("initialized", InitializedParams {}).await?;
        Ok(())
    }
}

設定ファイル統合(#138依存):

// #138で提供される設定システムを活用
impl HybridCodeParser {
    pub fn from_config(config: &ParsentryConfig) -> Result<Self> {
        let mut lsp_managers = HashMap::new();
        
        if config.extensions.lsp.enabled {
            for (language, bin_path) in &config.extensions.lsp.servers {
                let lsp_manager = LspManager::new(bin_path)?;
                lsp_managers.insert(language.parse()?, lsp_manager);
            }
        }
        
        Ok(Self {
            tree_sitter_parser: CodeParser::new()?,
            lsp_managers,
            config: config.extensions.lsp.clone(),
        })
    }
}

パフォーマンス最適化戦略

  1. LSPサーバープール: 頻繁に使用される言語のLSPサーバーを事前起動
  2. 段階的フォールバック: LSPタイムアウト時の即座なTree-sitter切り替え
  3. キャッシュ戦略: LSPレスポンスの効率的なキャッシュ
  4. 並列解析: 複数ファイルの同時LSP解析

セキュリティ分析向上の具体例

型安全性違反の検出:

  • Rust: unsafeブロック内の未チェックド変換
  • TypeScript: any型を通じた型安全性バイパス
  • Python: 動的属性アクセスでの型エラー
  • Java: キャスト操作での型安全性違反

デシリアライゼーション脆弱性:

  • Java: ObjectInputStreamでの任意クラス生成
  • Python: pickleモジュールでのコード実行
  • C#: BinaryFormatterでの型混同攻撃

このハイブリッドアプローチにより、Parsentryは既存の高速性を維持しながら、LSPによる高精度セマンティック解析を段階的に導入できます。#138の設定システムを基盤として、ユーザーは自身の環境とニーズに合わせて柔軟にLSP機能を活用でき、セキュリティ分析の精度を大幅に向上させることができます。

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