Skip to content

Add RAG feature - #4

Merged
Meet-08 merged 1 commit into
mainfrom
feat/code-retriever-rag
Aug 4, 2026
Merged

Add RAG feature#4
Meet-08 merged 1 commit into
mainfrom
feat/code-retriever-rag

Conversation

@Meet-08

@Meet-08 Meet-08 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

This pull request introduces the initial implementation of the codebase import and code-aware chat streaming features, including API documentation, controller endpoints, service logic, and advisor integration for code retrieval. The most important changes are grouped below:


API Documentation and Contracts

  • Added a comprehensive API specification for the codebase feature in server/specs/codebase.md, detailing endpoints for codebase import and streaming chat, authentication, expected request/response schemas, error handling, and source references.

Controller and Service Layer

  • Implemented the POST /api/codebases/{codebaseId}/chat/stream endpoint in CodebaseController, enabling streaming chat over codebases using Server-Sent Events (SSE). [1] [2] [3]
  • Extended CodebaseService to support streaming chat, including dependency injection for ChatClient, advisor setup, and SSE response handling. [1] [2]

Retrieval-Augmented Generation (RAG) Integration

  • Introduced CodeAdvisor, a CallAdvisor and StreamAdvisor component that enriches chat requests with code context and citations by invoking the CodeRetriever during chat interactions.
  • Registered CodeAdvisor and chat memory advisor in the CodebaseService's ChatClient pipeline for retrieval-augmented chat.

Security and Validation

  • Ensured all codebase endpoints require authentication and proper codebase ownership, with error handling for unauthorized or forbidden access, as documented and implemented in controller/service. [1] [2]

Code Simplification

  • Removed complex internal network address validation from validateCloneUrl, simplifying clone URL checks to focus on basic URI structure and public accessibility.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added authenticated chat for imported codebases with real-time streaming responses.
    • Responses now include relevant code context and citations with file paths and line ranges.
    • Added support for configurable chat models, including a default model.
    • Improved construction of code search requests.
  • Bug Fixes

    • Improved similarity filtering and ranking for more accurate code results.
    • Requests with missing or blank messages are now rejected with validation feedback.
  • Documentation

    • Added API documentation covering codebase chat, authentication, responses, errors, and streaming events.

Walkthrough

Added retrieval-backed Spring AI chat for codebases. The API authenticates requests, retrieves relevant code, enriches prompts, and streams messages, citations, completion, and error events over SSE.

Changes

Codebase chat flow

Layer / File(s) Summary
Retrieval contracts and search
server/src/main/java/com/meet/server/feature/codebase/dto/*, server/src/main/java/com/meet/server/feature/embedding/SimilaritySearchRequest.java, server/src/main/java/com/meet/server/feature/codechunk/CodeChunkRepositoryImpl.java, server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java
Added chat and citation DTOs, a similarity-search builder, conditional distance filtering, and bounded code-context retrieval.
Prompt enrichment advisor
server/src/main/java/com/meet/server/feature/advisor/CodeAdvisor.java
Added synchronous and streaming advisors that retrieve code for requests with a codebase ID and store citations in request context.
Authenticated streaming chat
server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java, server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java, server/src/main/resources/application.yaml, server/specs/codebase.md
Added the authenticated SSE chat endpoint, Spring AI chat configuration, conversation memory, SSE event handling, model configuration, and API documentation. Clone URL validation no longer performs DNS-based internal-address checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • Meet-08/CodeCompass#2: Provides the Codebase and CodeChunk entities and repositories used by code retrieval.
  • Meet-08/CodeCompass#3: Extends the affected controller, service, repository, search request, and chat configuration.

Poem

A rabbit hops through code so bright,
Finds useful chunks by candlelight.
Prompts gain context, streams take flight,
Citations follow left and right.
SSE events complete the night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main RAG functionality added by the pull request.
Description check ✅ Passed The description directly explains the codebase import, streaming chat, RAG integration, security, and validation changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/code-retriever-rag

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java (1)

106-112: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

SSRF (CWE-918): Server-Side Request Forgery (SSRF)

Reachability: External

Reachability path
● Entry
  server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java:54
  streamChat
│
▼
● Sink
  server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java

Block non-public clone destinations before Git connections.

validateCloneUrl accepts https://127.0.0.1/... and HTTPS hostnames that resolve to loopback, link-local, private, or metadata addresses. startClone saves the caller-controlled clone URL, and process passes it directly to GitService.cloneRepository, creating an SSRF path. Reject non-public DNS/redirect hops or route clones through an egress proxy/allowlist that blocks loopback, link-local, private, and metadata ranges.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java`
around lines 106 - 112, Update validateCloneUrl and the startClone/process flow
to prevent SSRF: reject literal and DNS-resolved loopback, link-local, private,
and metadata destinations, and ensure redirects cannot reach non-public
addresses before GitService.cloneRepository connects. Prefer the existing egress
proxy or allowlist mechanism if available; otherwise validate every resolved
destination and redirect hop while preserving acceptance of public HTTPS clone
URLs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/specs/codebase.md`:
- Line 1: Update the document’s opening heading from the bracketed form to a
Markdown top-level heading, using `# Codebase API Specification` so the required
document heading is recognized.
- Line 177: Update the SecurityConfig.java entry in the codebase documentation
by removing the malformed `]([]())` suffix, leaving only the intended file
reference, and ensure the file ends with exactly one newline.

In `@server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java`:
- Around line 31-48: Update the retrieval method around the citations stream and
context-building loop so citations are created only for results whose nonblank
content is actually appended to the prompt. Remove the eager citation
collection, build each CodeCitation after appending its snippet, and retain the
existing truncation and remaining-budget behavior.

---

Outside diff comments:
In `@server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java`:
- Around line 106-112: Update validateCloneUrl and the startClone/process flow
to prevent SSRF: reject literal and DNS-resolved loopback, link-local, private,
and metadata destinations, and ensure redirects cannot reach non-public
addresses before GitService.cloneRepository connects. Prefer the existing egress
proxy or allowlist mechanism if available; otherwise validate every resolved
destination and redirect hop while preserving acceptance of public HTTPS clone
URLs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2cfaec77-c869-49be-aa0b-1ea06dd52b58

📥 Commits

Reviewing files that changed from the base of the PR and between b082483 and afe3b17.

📒 Files selected for processing (10)
  • server/specs/codebase.md
  • server/src/main/java/com/meet/server/feature/advisor/CodeAdvisor.java
  • server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java
  • server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java
  • server/src/main/java/com/meet/server/feature/codebase/dto/CodeChatRequest.java
  • server/src/main/java/com/meet/server/feature/codebase/dto/CodeCitation.java
  • server/src/main/java/com/meet/server/feature/codechunk/CodeChunkRepositoryImpl.java
  • server/src/main/java/com/meet/server/feature/embedding/SimilaritySearchRequest.java
  • server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java
  • server/src/main/resources/application.yaml
📜 Review details
🧰 Additional context used
🪛 markdownlint-cli2 (0.23.1)
server/specs/codebase.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)


[warning] 177-177: No empty links

(MD042, no-empty-links)


[warning] 177-177: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (10)
server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java (1)

6-6: LGTM!

Also applies to: 16-19, 48-55

server/src/main/resources/application.yaml (1)

7-10: LGTM!

Also applies to: 41-41

server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java (1)

68-70: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Denial of Service (CWE-400): Uncontrolled Resource Consumption

Reachability: External

Reachability path
● Entry
  server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java:54
  streamChat
│
▼
● Sink
  server/src/main/java/com/meet/server/feature/codebase/CodebaseService.java

Bound the number and lifetime of chat conversations.

chatId is caller-controlled, and each distinct value creates a new conversationId. maxMessages(20) limits messages per conversation, not the number of conversations. MessageWindowChatMemory uses in-memory conversation storage by default, so the shown configuration has no expiry or total-conversation limit. An authenticated caller can create unbounded entries and exhaust heap memory. (docs.spring.io)

Use a repository or cache with expiry and a per-user conversation limit. Delete conversation state when a chat is closed.

#!/bin/bash
set -euo pipefail

# Confirm the configured Spring AI version and inspect memory configuration.
fd -HI -t f '^(pom\.xml|build\.gradle|build\.gradle\.kts|gradle\.properties)$' \
  -x rg -n -C 3 'spring-ai|jackson|MessageWindowChatMemory|ChatMemoryRepository' {}

# Find all conversation-key creation, storage, expiry, and cleanup paths.
rg -n -C 5 'MessageWindowChatMemory|ChatMemoryRepository|CONVERSATION_ID|conversationId|chatId|\.clear\s*\(' server/src

Also applies to: 164-165

server/src/main/java/com/meet/server/feature/codebase/dto/CodeCitation.java (1)

3-5: LGTM!

server/src/main/java/com/meet/server/feature/embedding/SimilaritySearchRequest.java (1)

14-34: LGTM!

server/src/main/java/com/meet/server/feature/codechunk/CodeChunkRepositoryImpl.java (1)

229-241: LGTM!

server/src/main/java/com/meet/server/feature/advisor/CodeAdvisor.java (2)

33-34: 🩺 Stability & Availability

Verify that retrieval does not block a reactive request thread.

adviseStream evaluates enrich(request) before it returns the Flux. enrich calls CodeRetriever.retrieve, which performs synchronous EmbeddingModel.embed and JdbcClient.query(...).list() work. If this endpoint runs on a WebFlux event loop, each chat request blocks that loop. Verify the execution scheduler and timeouts. If the path is reactive, defer and offload retrieval or use nonblocking clients.

Also applies to: 42-42


25-29: LGTM!

Also applies to: 48-57

server/src/main/java/com/meet/server/feature/codebase/dto/CodeChatRequest.java (1)

5-5: 🔒 Security & Privacy

IDOR (CWE-639): Authorization Bypass Through User-Controlled Key (IDOR)

Verify chat-memory key isolation.

chatId accepts null, blank values, and caller-selected IDs. The supplied CodebaseService constructor creates MessageWindowChatMemory and installs MessageChatMemoryAdvisor. Verify that streamChat derives ChatMemory.CONVERSATION_ID from the authenticated user and codebaseId, or generates a server-side ID when chatId is absent. If it forwards the raw or default value, an authenticated caller can place another conversation's history into model context. This violates conversation confidentiality.

server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java (1)

23-29: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Sensitive Data Exposure (CWE-532): Insertion of Sensitive Information into Log File

Reachability: External

Reachability path
● Entry
  server/src/main/java/com/meet/server/feature/codebase/CodebaseController.java:24
  CodebaseController
│
▼
● Hop
  server/src/main/java/com/meet/server/feature/advisor/CodeAdvisor.java:37
  enrich
│
▼
● Sink
  server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java

Stop logging the raw chat prompt.

An authenticated caller can submit secrets or PII in the chat prompt. CodeAdvisor.enrich forwards that text to retrieve, and Line 24 logs it unchanged. Authentication and @NotBlank do not prevent log retention. If DEBUG output is stored, this violates chat-content confidentiality.

Proposed fix
-        log.debug("Retrieving code for {} using query {}", codebaseId, query);
+        log.debug("Retrieving code for {}", codebaseId);

Comment thread server/specs/codebase.md
Comment thread server/specs/codebase.md
Comment on lines +31 to +48
var citations = results.stream().map(result -> {
var chunk = result.chunk();
return new CodeCitation(chunk.getId(), chunk.getPath(), chunk.getStartLine(), chunk.getEndLine(), chunk.getLanguage(), result.distance());
}).toList();

StringBuilder context = new StringBuilder("\n\nRelevant code snippets:\n");
int remaining = 12000;
for (var result : results) {
String content = result.chunk().getContent();
if (content == null || content.isBlank() || remaining <= 0) continue;
String snippet = content.substring(0, Math.min(content.length(), remaining));
context.append("\n--- ").append(result.chunk().getPath()).append(":")
.append(result.chunk().getStartLine()).append("-").append(result.chunk().getEndLine())
.append(" ---\n").append(snippet).append('\n');
remaining -= snippet.length();
}
log.debug("Total relevant code snippets: {}", citations.size());
return new RetrievalContext(context.toString(), citations);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Build citations from snippets that enter the prompt.

When a result has null or blank content, the loop skips its text. The earlier stream still adds its citation. RetrievalContext can then cite code that the model did not receive. Add the citation after the snippet is appended.

Proposed fix
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-        var citations = results.stream().map(result -> {
-            var chunk = result.chunk();
-            return new CodeCitation(chunk.getId(), chunk.getPath(), chunk.getStartLine(), chunk.getEndLine(), chunk.getLanguage(), result.distance());
-        }).toList();
+        var citations = new ArrayList<CodeCitation>();
 
         StringBuilder context = new StringBuilder("\n\nRelevant code snippets:\n");
         int remaining = 12000;
         for (var result : results) {
-            String content = result.chunk().getContent();
+            var chunk = result.chunk();
+            String content = chunk.getContent();
             if (content == null || content.isBlank() || remaining <= 0) continue;
             String snippet = content.substring(0, Math.min(content.length(), remaining));
-            context.append("\n--- ").append(result.chunk().getPath()).append(":")
-                    .append(result.chunk().getStartLine()).append("-").append(result.chunk().getEndLine())
+            context.append("\n--- ").append(chunk.getPath()).append(":")
+                    .append(chunk.getStartLine()).append("-").append(chunk.getEndLine())
                     .append(" ---\n").append(snippet).append('\n');
             remaining -= snippet.length();
+            citations.add(new CodeCitation(chunk.getId(), chunk.getPath(), chunk.getStartLine(),
+                    chunk.getEndLine(), chunk.getLanguage(), result.distance()));
         }
-        return new RetrievalContext(context.toString(), citations);
+        return new RetrievalContext(context.toString(), List.copyOf(citations));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var citations = results.stream().map(result -> {
var chunk = result.chunk();
return new CodeCitation(chunk.getId(), chunk.getPath(), chunk.getStartLine(), chunk.getEndLine(), chunk.getLanguage(), result.distance());
}).toList();
StringBuilder context = new StringBuilder("\n\nRelevant code snippets:\n");
int remaining = 12000;
for (var result : results) {
String content = result.chunk().getContent();
if (content == null || content.isBlank() || remaining <= 0) continue;
String snippet = content.substring(0, Math.min(content.length(), remaining));
context.append("\n--- ").append(result.chunk().getPath()).append(":")
.append(result.chunk().getStartLine()).append("-").append(result.chunk().getEndLine())
.append(" ---\n").append(snippet).append('\n');
remaining -= snippet.length();
}
log.debug("Total relevant code snippets: {}", citations.size());
return new RetrievalContext(context.toString(), citations);
var citations = new ArrayList<CodeCitation>();
StringBuilder context = new StringBuilder("\n\nRelevant code snippets:\n");
int remaining = 12000;
for (var result : results) {
var chunk = result.chunk();
String content = chunk.getContent();
if (content == null || content.isBlank() || remaining <= 0) continue;
String snippet = content.substring(0, Math.min(content.length(), remaining));
context.append("\n--- ").append(chunk.getPath()).append(":")
.append(chunk.getStartLine()).append("-").append(chunk.getEndLine())
.append(" ---\n").append(snippet).append('\n');
remaining -= snippet.length();
citations.add(new CodeCitation(chunk.getId(), chunk.getPath(), chunk.getStartLine(),
chunk.getEndLine(), chunk.getLanguage(), result.distance()));
}
log.debug("Total relevant code snippets: {}", citations.size());
return new RetrievalContext(context.toString(), List.copyOf(citations));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/main/java/com/meet/server/feature/retriver/CodeRetriever.java`
around lines 31 - 48, Update the retrieval method around the citations stream
and context-building loop so citations are created only for results whose
nonblank content is actually appended to the prompt. Remove the eager citation
collection, build each CodeCitation after appending its snippet, and retain the
existing truncation and remaining-budget behavior.

@Meet-08
Meet-08 merged commit f2fb874 into main Aug 4, 2026
2 checks passed
@Meet-08
Meet-08 deleted the feat/code-retriever-rag branch August 4, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant