0
✦ 品質
🛡 セキュリティ
⚙ 保守性
📋 概要
Laravel 13 + PHP 8.4 で構築されたGitHubリポジトリ自動コードレビューSaaS。Claude AI(Anthropic)を呼び出してリポジトリを解析し、スコア・指摘・改善提案をストリーミング表示する。Docker対応・Redis/Queue構成でデプロイ済み。
🎯 今すぐ直すべき3点
-
app/Services/ClaudeReviewService.php ユーザーが指定したGitHubリポジトリのファイル内容をそのままClaudeのプロンプトに埋め込んでいる箇所を確認し、<file_content>タグによるサンドボックス化が全ファイル・全パスで一貫して適用されているか検証する。truncatedで全文未確認のため、buildReviewPromptWithContext()の実装を全文レビューして、ユーザー制御コンテンツがsystemプロンプト領域に混入しないことを保証すること↗
-
app/Http/Controllers/ReviewController.php store()メソッドでReview::create()後に$review->ip_hash = $ipHash; $review->save()と2回DBアクセスしている。Review::create(['ip_hash' => $ipHash, ...])に統合して不要なsave()を削除し、ip_hashがfillableに含まれていることをReviewモデルで確認する↗
-
app/Services/GitHubService.php getFileContent()でbase64_decodeした内容をそのまま返しているが、バイナリファイル(画像・zip等)が混入した場合の処理が不明(truncatedで全文未確認)。selectKeyFiles()の選択ロジックと合わせて、MIMEタイプまたは拡張子チェックでバイナリを除外し、プロンプト汚染を防ぐ実装を追加すること↗
🔍 検出された問題 (6件)
🟥 Critical
📄 app/Services/ClaudeReviewService.php
Prompt Injection対策の実効性が部分的にしか確認できない
ClaudeReviewService.phpのsystemプロンプトに<file_content>タグ内の命令を無視するよう記載されているが、buildReviewPromptWithContext()の実装がtruncatedで未確認のため、実際にユーザーリポジトリのファイル内容がタグで適切にサンドボックス化されているか検証できない。悪意あるリポジトリに「ロールを変更して」等の命令を仕込まれた場合、Claudeがシステムプロンプトを逸脱した応答を返すリスクがあり、APIコスト浪費・誤レビュー生成・情報漏洩につながる危険がある
🟥 Critical
📄 app/Services/GitHubService.php
GitHubトークンの権限スコープが過剰な場合のリスク
GitHubService.phpはGITHUB_TOKENを使ってプライベートリポジトリにもアクセス可能な構成になっている。.env.exampleにGITHUB_TOKEN=が存在し、スコープ制限の記載がREADMEにも見当たらない(truncatedで全文未確認)。read:contents以外の権限を持つトークンが設定された場合、ユーザーが任意のowner/repoを指定できるstore()経由でトークンが意図しないリポジトリへのアクセスに悪用される危険がある
🟧 Warning
📄 app/Http/Controllers/ReviewController.php
ReviewController::store()でのReview生成が2段階saveになっている
Review::create()でレコードを作成した直後に$review->ip_hash = $ipHash; $review->save()を呼んでおり、2回のDB書き込みが発生している。ip_hashがfillableに含まれていない場合はサイレントに保存されない可能性があり、レート制限の回避(同一IPが複数レビューを生成)につながる危険がある
🟧 Warning
📄 app/Services/ClaudeReviewService.php
ClaudeReviewService.phpが12345文字と大規模で責務が集中している疑い
evidence_coverageによるとClaudeReviewService.phpの全文は12345文字あり、今回読めたのは3000文字(24%)のみ。review()・buildRepositoryReviewPrompt()・buildScoringRubric()・call()・parseJson()等が単一クラスに集中している可能性が高く、プロンプト構築・API呼び出し・レスポンスパースの責務が混在していると保守性・テスト容易性が低下する
🟧 Warning
📄 Dockerfile
Dockerfileのfrontendステージでnpm installが.dockerignore依存で不安定になるリスク
frontendステージでCOPY package.json ./後にnpm installし、その後COPY . .でソース全体をコピーしているが、package-lock.jsonをCOPYしていないためnpm installの再現性が保証されない。依存パッケージのバージョンが環境によって変わり、ビルド成果物の差異が本番障害につながる危険がある
🟨 Suggestion
📄 app/Http/Controllers/ReviewController.php
ReviewController::fix()の実装がtruncatedで未確認
fix()メソッドはReviewController.phpの3000文字読み取り範囲で途中で切れており、$review->owner/$review->repoを使ったgetFileContent()呼び出しの全体像が確認できない。issue_titleやissue_descをClaudeに渡す際のサニタイズ・最大長制限が実装されているか不明であり、確認が必要
✅ 良い点
- app/Services/RepositoryFacts.php のdetected/none/unknownの3状態契約が明示的に定義されており、unknownをnoneとして扱う誤減点をコード・コメント両面で防止している設計は、AIスコアリングの信頼性を構造的に担保している
- app/Services/EvidenceCoverage.php がファイルごとにtotal_chars/read_chars/truncatedを追跡することで、AIが「読めていない範囲を根拠に不在と断定する」誤推論を防ぐメタ情報をプロンプトに付与できる点が優れている
- app/Services/ReviewRateLimiter.php がanalysis_source='generated'のみをカウント対象とし、キャッシュヒット('cached')や上限停止('limited')を除外することで、Claude API実コスト消費と正確に対応したレート制限を実現している
🔧 リファクタ提案
- ClaudeReviewService.phpをPromptBuilder・AnthropicApiClient・ReviewResponseParserの3クラスに分割し、各責務を単一化する。これによりAnthropicのモデル変更やプロンプト改修が他の処理に影響しなくなる
- ReviewController::store()のレート制限ロジック(RateLimiter::tooManyAttempts/hit)をReviewRateLimiterサービスに統合し、ReviewControllerとReviewRateLimiterで二重管理されているレート制限の実装を一本化する
- GitHubService::getFileTree()のmain→masterフォールバックロジックをgetRepoInfo()で取得したdefault_branchを使う形に変更し、ブランチ名のハードコードを排除する(getRepoStats()がすでにdefault_branchを返しているため流用可能)
🔒 セキュリティ注意点
- ANTHROPIC_API_KEYとGITHUB_TOKENは.env.exampleでは空欄になっており本番値のハードコードはないが、GITHUB_TOKENのスコープをread:contentsのみに制限するFine-grained Personal Access Tokenの使用をREADMEに明記し、過剰権限トークンの設定を防ぐガイドを追加すること
- SESSION_ENCRYPT=trueが.env.exampleで有効化されており、セッション暗号化は適切に設定されている。ただしAPP_DEBUG=trueが.env.exampleのデフォルトのままであり、本番環境でfalseに変更されているかdocker-entrypoint.shまたはCI/CDで強制する仕組みを確認・追加すること
📤 PRコメント出力
このレビューをGitHub PRコメントとして貼り付けられるMarkdown形式で出力します。