feat: add AI chatbot assistant with RAG support#118
Conversation
|
@pranavshankar1221 is attempting to deploy a commit to the karan3431's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
TF-IDF RAG retriever backend/rag_retriever.py |
RAGChunk container, tokenize(), RAGRetriever class (doc loading, markdown header splitting, large-text sub-splitting, TF-IDF indexing, query scoring with substring fallback), and get_retriever() singleton. |
LLM provider interface and implementations backend/llm_provider.py, backend/.env.example |
LLMProvider base class, concrete Gemini/OpenAI/Claude/Ollama HTTP-calling implementations, keyword-based MockProvider, and get_llm_provider() factory that reads LLM_PROVIDER env var and falls back to mock when credentials are absent. .env.example adds provider key placeholders. |
SQLite chat logger backend/chat_logger.py |
init_db() creates chat_logs table; log_chat_message() inserts Q&A rows; update_chat_feedback() sets thumbs up/down by message ID; per-call open/close with error printing. |
FastAPI chat endpoints and backend wiring backend/chat_router.py, backend/main.py |
Pydantic models for request/response, /message endpoint (RAG context → prompt assembly → LLM call → best-effort log), /feedback endpoint (validates up/down, writes to logger); main.py registers the router, switches dotenv to override=True, and removes the rate-limit decorator from get_markets. |
Frontend API client chat methods src/lib/api.ts |
Adds api.chatMessage() (POST /api/v1/chat/message) and api.submitChatFeedback() (POST /api/v1/chat/feedback) with typed request/response shapes; minor reformatting of loginUrl and getMarkets. |
ChatAssistant component and layout integration src/components/ChatAssistant.tsx, src/components/Layout.tsx |
Full floating chat panel: route-based page context, send-message flow with history building, per-message thumbs feedback, formatText markdown renderer, empty-state suggestions, loading indicator, controlled input form; Layout imports and renders <ChatAssistant />. |
Sequence Diagram(s)
sequenceDiagram
actor User
participant ChatAssistant as ChatAssistant (React)
participant APIClient as api.ts
participant ChatRouter as POST /api/v1/chat/message
participant RAGRetriever
participant LLMProvider
participant ChatLogger as chat_logger (SQLite)
User->>ChatAssistant: types question, clicks SEND
ChatAssistant->>APIClient: chatMessage(question, page, feature, history)
APIClient->>ChatRouter: POST /api/v1/chat/message
ChatRouter->>RAGRetriever: retrieve_relevant_context(question)
RAGRetriever-->>ChatRouter: context string
ChatRouter->>LLMProvider: generate_response(system_prompt, prompt+context, history)
LLMProvider-->>ChatRouter: response text
ChatRouter->>ChatLogger: log_chat_message(msg_id, question, response, page, feature)
ChatRouter-->>APIClient: { message_id, response }
APIClient-->>ChatAssistant: { message_id, response }
ChatAssistant->>User: renders assistant message + thumbs buttons
User->>ChatAssistant: clicks thumbs up/down
ChatAssistant->>APIClient: submitChatFeedback(message_id, "up"|"down")
APIClient->>ChatRouter: POST /api/v1/chat/feedback
ChatRouter->>ChatLogger: update_chat_feedback(msg_id, feedback)
ChatRouter-->>APIClient: { success: true }
APIClient-->>ChatAssistant: updates local message state
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
🐰 A rabbit hops through docs and code,
RAG-indexing every markdown road.
Gemini, Claude, or Ollama's call—
The chat floats up to answer all!
Ask your question, thumb it right,
SQLite logs it through the night. ✨
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Out of Scope Changes check | Critical issue: The PR removes rate limiting decorators (@limiter.limit) from the GET /api/v1/maps/markets endpoint in backend/main.py, which is out of scope and unintended per maintainer feedback. |
Rebase the feature branch on the latest main branch to preserve the rate limiting functionality that was previously merged. Ensure @limiter.limit decorators are retained on the markets endpoint. |
|
| Docstring Coverage | Docstring coverage is 37.93% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The PR title accurately summarizes the main change: adding an AI chatbot with RAG support, which is the core objective of the changeset. |
| Linked Issues check | ✅ Passed | The PR implements all key objectives from issue #62: interactive guidance for users, instant answers to queries, improved onboarding, and reduced documentation dependency through a fully-featured AI chat assistant with RAG support. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
src/components/ChatAssistant.tsx (2)
98-112: 💤 Low valueConsider using message ID instead of index for state update.
The feedback handler uses
idxto update the message in state, but if themessagesarray were to change between the button click and state update completion, the wrong message could be updated. While unlikely due to the loading guard, an ID-based lookup would be more robust.♻️ Suggested improvement
try { await api.submitChatFeedback(msgId, type); - setMessages(prev => { - const updated = [...prev]; - updated[idx] = { ...updated[idx], feedback: type }; - return updated; - }); + setMessages(prev => prev.map(m => + m.id === msgId ? { ...m, feedback: type } : m + )); } catch (err) {🤖 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 `@src/components/ChatAssistant.tsx` around lines 98 - 112, The handleFeedback function uses the array index idx to update the message state, which is fragile if the messages array changes between the button click and state update. Replace the index-based approach in the setMessages callback with an ID-based lookup that finds the message by matching its msgId property instead of using updated[idx]. This ensures the correct message is updated regardless of array order changes.
317-324: ⚡ Quick winAdd aria-label to the chat input for screen reader accessibility.
The input field relies on placeholder text, which is not announced by all screen readers. Adding
aria-labelimproves accessibility for users with assistive technologies.♿ Suggested fix
<input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} placeholder="ASK CHAT ASSISTANT..." disabled={isLoading} + aria-label="Chat message input" className="flex-1 bg-surface-lowest text-xs text-on-surface px-4 py-3.5 border-none focus:outline-none focus:bg-surface-mid placeholder:font-mono placeholder:text-[9px] placeholder:text-outline disabled:opacity-60" />🤖 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 `@src/components/ChatAssistant.tsx` around lines 317 - 324, The input field in ChatAssistant.tsx lacks an aria-label attribute, which is necessary for screen reader accessibility. Add an aria-label prop to the input element that has type="text", value={inputValue}, and the onChange handler that calls setInputValue. Provide a descriptive label such as "Chat assistant input" that clearly describes the purpose of the input field for users relying on assistive technologies.
🤖 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 `@backend/.env.example`:
- Around line 35-44: Remove the duplicate CORS_ALLOW_ALL configuration key from
the .env.example file. Keep the first occurrence of CORS_ALLOW_ALL=true that
appears at the beginning of the configuration section, and delete the second
duplicate occurrence that appears at the end of the LLM Provider section. This
ensures each configuration key is declared only once, removing any ambiguity
about which value takes precedence.
In `@backend/chat_logger.py`:
- Around line 62-65: The exception handling in ChatLogger is swallowing SQLite
write errors by catching exceptions, printing them, and then returning normally,
which causes API handlers to report success when writes actually fail. Instead
of just printing the exception in the except blocks (around lines 62-65 and
83-86), re-raise the exception after logging it so that the error properly
propagates to the caller and API handlers can detect and report the failure
appropriately.
- Around line 74-82: The UPDATE statement in the chat_logs feedback update logic
does not validate whether the update actually affected any rows. After the
cursor.execute() call that updates feedback, check cursor.rowcount to determine
if any rows were actually modified. Only proceed with conn.commit() if
cursor.rowcount is greater than 0, and return an appropriate response indicating
failure or success based on whether the msg_id matched an existing record in the
database.
In `@backend/chat_router.py`:
- Around line 43-44: The chat_message function and chat_feedback function are
defined as async but perform blocking synchronous I/O operations (LLM HTTP calls
and SQLite operations) that block the event loop under concurrent load. Remove
the async keyword from the function definitions of chat_message and
chat_feedback to convert them to synchronous handlers, which allows the ASGI
framework to properly schedule and execute these blocking operations on thread
pools without blocking concurrent requests.
In `@backend/llm_provider.py`:
- Around line 38-42: The Gemini API key is currently passed as a query parameter
in the URL string within the generateContent endpoint call, which poses a
security risk as query parameters are easily exposed in logs and caches. Remove
the `?key={self.api_key}` query parameter from the URL construction and instead
pass the API key as an HTTP header in the request (following the same pattern
used by the OpenAI and Claude providers in the same file). Ensure that any
exception handling and logging does not expose raw error details that might
reveal authentication information. Apply this same fix to the similar code at
lines 78-79 where the API key is also passed in the URL.
In `@backend/main.py`:
- Line 775: Add a rate limiting decorator to the `get_markets()` async function
to protect it from burst traffic, following the same pattern used by other
endpoints in the codebase. Place the `@limiter.limit("20/minute")` decorator
directly above the function definition to enforce consistent rate limiting
across all API endpoints.
- Line 22: In the load_dotenv function call, change the override parameter from
override=True to override=False. This ensures that environment variables set by
your deployment platform (Docker, Kubernetes, CI/CD) are preserved and not
overridden by values from the .env file, protecting production secrets and
configuration from being accidentally replaced by local development values.
In `@src/components/ChatAssistant.tsx`:
- Around line 114-162: The formatText function applies bold formatting to the
content variable but then returns raw text (listText, numMatch[2], and the
blockquote substring) in list items and blockquotes, losing the formatting. To
fix this, ensure inline formatting is applied before checking for
list/blockquote detection. Move the bold formatting logic to happen first, then
use the formatted content variable when returning list items (instead of
listText), numbered lists (instead of numMatch[2]), and blockquotes (instead of
the raw substring). This way, a paragraph like "- **Important** item" will
preserve the bold formatting when rendered as a list item.
---
Nitpick comments:
In `@src/components/ChatAssistant.tsx`:
- Around line 98-112: The handleFeedback function uses the array index idx to
update the message state, which is fragile if the messages array changes between
the button click and state update. Replace the index-based approach in the
setMessages callback with an ID-based lookup that finds the message by matching
its msgId property instead of using updated[idx]. This ensures the correct
message is updated regardless of array order changes.
- Around line 317-324: The input field in ChatAssistant.tsx lacks an aria-label
attribute, which is necessary for screen reader accessibility. Add an aria-label
prop to the input element that has type="text", value={inputValue}, and the
onChange handler that calls setInputValue. Provide a descriptive label such as
"Chat assistant input" that clearly describes the purpose of the input field for
users relying on assistive technologies.
🪄 Autofix (Beta)
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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a0e07b89-fece-47a4-8220-d5da981a3636
📒 Files selected for processing (9)
backend/.env.examplebackend/chat_logger.pybackend/chat_router.pybackend/llm_provider.pybackend/main.pybackend/rag_retriever.pysrc/components/ChatAssistant.tsxsrc/components/Layout.tsxsrc/lib/api.ts
| CORS_ALLOW_ALL=true | ||
|
|
||
| # ── LLM Provider (for AI Chat Assistant) ────────────────────────────────────── | ||
| # Options: gemini (default), openai, claude, ollama | ||
| LLM_PROVIDER=gemini | ||
| GEMINI_API_KEY= | ||
| OPENAI_API_KEY= | ||
| CLAUDE_API_KEY= | ||
| OLLAMA_BASE_URL=http://localhost:11434 | ||
| CORS_ALLOW_ALL=true |
There was a problem hiding this comment.
Remove duplicated CORS_ALLOW_ALL.
The key is declared twice, which makes configuration precedence ambiguous during audits/debugging.
🧹 Proposed fix
CORS_ALLOW_ALL=true
@@
OLLAMA_BASE_URL=http://localhost:11434
-CORS_ALLOW_ALL=true📝 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.
| CORS_ALLOW_ALL=true | |
| # ── LLM Provider (for AI Chat Assistant) ────────────────────────────────────── | |
| # Options: gemini (default), openai, claude, ollama | |
| LLM_PROVIDER=gemini | |
| GEMINI_API_KEY= | |
| OPENAI_API_KEY= | |
| CLAUDE_API_KEY= | |
| OLLAMA_BASE_URL=http://localhost:11434 | |
| CORS_ALLOW_ALL=true | |
| CORS_ALLOW_ALL=true | |
| # ── LLM Provider (for AI Chat Assistant) ────────────────────────────────────── | |
| # Options: gemini (default), openai, claude, ollama | |
| LLM_PROVIDER=gemini | |
| GEMINI_API_KEY= | |
| OPENAI_API_KEY= | |
| CLAUDE_API_KEY= | |
| OLLAMA_BASE_URL=http://localhost:11434 |
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 40-40: [UnorderedKey] The GEMINI_API_KEY key should go before the LLM_PROVIDER key
(UnorderedKey)
[warning] 42-42: [UnorderedKey] The CLAUDE_API_KEY key should go before the GEMINI_API_KEY key
(UnorderedKey)
[warning] 43-43: [UnorderedKey] The OLLAMA_BASE_URL key should go before the OPENAI_API_KEY key
(UnorderedKey)
[warning] 44-44: [DuplicatedKey] The CORS_ALLOW_ALL key is duplicated
(DuplicatedKey)
[warning] 44-44: [UnorderedKey] The CORS_ALLOW_ALL key should go before the GEMINI_API_KEY key
(UnorderedKey)
🤖 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 `@backend/.env.example` around lines 35 - 44, Remove the duplicate
CORS_ALLOW_ALL configuration key from the .env.example file. Keep the first
occurrence of CORS_ALLOW_ALL=true that appears at the beginning of the
configuration section, and delete the second duplicate occurrence that appears
at the end of the LLM Provider section. This ensures each configuration key is
declared only once, removing any ambiguity about which value takes precedence.
Source: Linters/SAST tools
| except Exception as e: | ||
| print(f"ChatLogger Error logging message: {e}") | ||
| finally: | ||
| conn.close() |
There was a problem hiding this comment.
Do not swallow SQLite write errors.
Both functions print exceptions and return normally, so API handlers can report success even when writes fail.
🛠️ Proposed fix
- except Exception as e:
- print(f"ChatLogger Error logging message: {e}")
+ except sqlite3.Error as e:
+ conn.rollback()
+ raise RuntimeError("Failed to log chat message") from e
@@
- except Exception as e:
- print(f"ChatLogger Error updating feedback: {e}")
+ except sqlite3.Error as e:
+ conn.rollback()
+ raise RuntimeError("Failed to update chat feedback") from eAlso applies to: 83-86
🤖 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 `@backend/chat_logger.py` around lines 62 - 65, The exception handling in
ChatLogger is swallowing SQLite write errors by catching exceptions, printing
them, and then returning normally, which causes API handlers to report success
when writes actually fail. Instead of just printing the exception in the except
blocks (around lines 62-65 and 83-86), re-raise the exception after logging it
so that the error properly propagates to the caller and API handlers can detect
and report the failure appropriately.
| cursor.execute( | ||
| """ | ||
| UPDATE chat_logs | ||
| SET feedback = ? | ||
| WHERE id = ? | ||
| """, | ||
| (feedback, msg_id) | ||
| ) | ||
| conn.commit() |
There was a problem hiding this comment.
Validate that feedback updates actually match a message ID.
UPDATE can affect 0 rows (unknown msg_id) and still commit; downstream currently returns {success: true}.
✅ Proposed fix
cursor.execute(
@@
(feedback, msg_id)
)
+ if cursor.rowcount == 0:
+ raise ValueError(f"Message ID not found: {msg_id}")
conn.commit()📝 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.
| cursor.execute( | |
| """ | |
| UPDATE chat_logs | |
| SET feedback = ? | |
| WHERE id = ? | |
| """, | |
| (feedback, msg_id) | |
| ) | |
| conn.commit() | |
| cursor.execute( | |
| """ | |
| UPDATE chat_logs | |
| SET feedback = ? | |
| WHERE id = ? | |
| """, | |
| (feedback, msg_id) | |
| ) | |
| if cursor.rowcount == 0: | |
| raise ValueError(f"Message ID not found: {msg_id}") | |
| conn.commit() |
🤖 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 `@backend/chat_logger.py` around lines 74 - 82, The UPDATE statement in the
chat_logs feedback update logic does not validate whether the update actually
affected any rows. After the cursor.execute() call that updates feedback, check
cursor.rowcount to determine if any rows were actually modified. Only proceed
with conn.commit() if cursor.rowcount is greater than 0, and return an
appropriate response indicating failure or success based on whether the msg_id
matched an existing record in the database.
| async def chat_message(request: ChatMessageRequest): | ||
| """ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify async route + sync call chain
rg -n -C2 'async def chat_message|async def chat_feedback|get_retriever\(|generate_response\(|log_chat_message\(|update_chat_feedback\(' backend/chat_router.py
rg -n -C2 'httpx\.post\(' backend/llm_provider.py
rg -n -C2 'sqlite3\.connect\(' backend/chat_logger.pyRepository: jpdevhub/FreshScanAi
Length of output: 2340
Remove async from blocking I/O handlers.
These routes execute synchronous LLM HTTP and SQLite calls that block the event loop under concurrent load. Converting to synchronous handlers allows proper concurrent request handling.
Proposed fix
-async def chat_message(request: ChatMessageRequest):
+def chat_message(request: ChatMessageRequest):Also applies to chat_feedback() (line 151).
Also applies to: 115-117, 151-158
🤖 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 `@backend/chat_router.py` around lines 43 - 44, The chat_message function and
chat_feedback function are defined as async but perform blocking synchronous I/O
operations (LLM HTTP calls and SQLite operations) that block the event loop
under concurrent load. Remove the async keyword from the function definitions of
chat_message and chat_feedback to convert them to synchronous handlers, which
allows the ASGI framework to properly schedule and execute these blocking
operations on thread pools without blocking concurrent requests.
| url = ( | ||
| "https://generativelanguage.googleapis.com" | ||
| f"/v1beta/models/{self.model}:generateContent" | ||
| f"?key={self.api_key}" | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify key-in-URL + raw exception propagation paths
rg -n -C2 'generateContent\?key=|Gemini API error: \{e\}|Gemini provider failed: \{e\}' backend/llm_provider.py
rg -n -C2 'LLM Provider execution failed' backend/chat_router.pyRepository: jpdevhub/FreshScanAi
Length of output: 585
Replace query-parameter authentication with header-based auth to prevent API key exposure.
Line 41 uses ?key={self.api_key} in the URL, which puts the Gemini API key in the query string. Query parameters are more likely to be exposed in logs, browser history, caches, and debugging output compared to HTTP headers. Additionally, exception messages should not propagate raw details that might reveal authentication info in error logs.
Update to pass the API key in a request header instead (like OpenAI and Claude providers do), and remove exception details from log messages:
🔐 Proposed fix
- url = (
- "https://generativelanguage.googleapis.com"
- f"/v1beta/models/{self.model}:generateContent"
- f"?key={self.api_key}"
- )
+ url = "https://generativelanguage.googleapis.com/v1beta/models/{self.model}:generateContent"
+ headers = {"x-goog-api-key": self.api_key}- except Exception as e:
- logger.error(f"Gemini API error: {e}")
- raise RuntimeError(f"Gemini provider failed: {e}")
+ except Exception:
+ logger.error("Gemini API request failed")
+ raise RuntimeError("Gemini provider failed")Also applies to: lines 78–79
🤖 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 `@backend/llm_provider.py` around lines 38 - 42, The Gemini API key is
currently passed as a query parameter in the URL string within the
generateContent endpoint call, which poses a security risk as query parameters
are easily exposed in logs and caches. Remove the `?key={self.api_key}` query
parameter from the URL construction and instead pass the API key as an HTTP
header in the request (following the same pattern used by the OpenAI and Claude
providers in the same file). Ensure that any exception handling and logging does
not expose raw error details that might reveal authentication information. Apply
this same fix to the similar code at lines 78-79 where the API key is also
passed in the URL.
| from dotenv import load_dotenv | ||
|
|
||
| load_dotenv(Path(__file__).parent / ".env") | ||
| load_dotenv(Path(__file__).parent / ".env", override=True) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify dotenv loading behavior in startup code
rg -n -C3 'load_dotenv|override=' backend/main.pyRepository: jpdevhub/FreshScanAi
Length of output: 270
🏁 Script executed:
# Check if .env is in .gitignore
cat -n .gitignore | grep -i env || echo "No .env entry found in .gitignore"Repository: jpdevhub/FreshScanAi
Length of output: 663
🏁 Script executed:
# Look for get_markets endpoint and route limiter context
rg -n 'get_markets|@.*limiter|`@limiter`' backend/ --type py -B2 -A2Repository: jpdevhub/FreshScanAi
Length of output: 1099
🌐 Web query:
python-dotenv override=True security best practices environment variables
💡 Result:
When using python-dotenv, the override parameter determines whether values in your.env file take precedence over existing environment variables [1][2]. Setting override=True forces the application to prioritize the.env file, which is generally discouraged in production environments where system-level configuration should take precedence [3]. Security Best Practices: 1. Prevent Secret Exposure: Never commit your.env file to version control [4][3]. Always add.env to your.gitignore file [4][3]. If a secret file is accidentally committed, rotate the credentials immediately, as removing the file from history is insufficient for security [4][3]. 2. Prefer System-Level Environment Variables in Production: Avoid using override=True in production [3]. Allow actual system environment variables (injected by your hosting platform, CI/CD pipeline, or container orchestrator) to maintain priority [3]. This ensures the deployment environment controls the application configuration [3]. 3. Validate Configuration: Do not rely solely on the existence of variables. Implement startup validation to check for required keys and fail immediately with clear error messages if configuration is missing or malformed [4][3]. 4. Keep python-dotenv Updated: A security vulnerability (CVE-2026-28684) previously allowed arbitrary file overwrites via symbolic links when using set_key or unset_key [5][6]. Ensure you are using version 1.2.2 or later, which resolves this issue by defaulting to safer file handling practices [5][6]. 5. Minimize.env Usage: For complex applications, consider using robust configuration management libraries like pydantic-settings, which provide built-in type safety, validation, and advanced loading capabilities without relying solely on manual.env management [7]. 6. Disable in Production: If your deployment process manages environment variables externally, you can disable python-dotenv's automatic loading by setting the environment variable PYTHON_DOTENV_DISABLED=1 [8][2]. This prevents accidental loading of local.env files in server environments [8].
Citations:
- 1: https://github.com/theskumar/python-dotenv?tab=readme-ov-file
- 2: https://bbc2.github.io/python-dotenv/reference/
- 3: https://envmanager.com/blog/environment-variables-python
- 4: https://pyguides.dev/guides/python-dotenv/
- 5: GHSA-mf9w-mj56-hr94
- 6: https://nvd.nist.gov/vuln/detail/cve-2026-28684
- 7: https://env.dev/guides/python-env-variables
- 8: https://pypi.org/project/python-dotenv/1.2.1/
Change override=True to override=False to avoid overriding deployment environment variables.
When override=True, .env values will override system environment variables set by your deployment platform (Docker, Kubernetes, CI/CD), potentially replacing production secrets with local development values. Use override=False (the default) to allow .env to fill missing variables while preserving deployment-provided configuration.
Proposed fix
- load_dotenv(Path(__file__).parent / ".env", override=True)
+ load_dotenv(Path(__file__).parent / ".env", override=False)🤖 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 `@backend/main.py` at line 22, In the load_dotenv function call, change the
override parameter from override=True to override=False. This ensures that
environment variables set by your deployment platform (Docker, Kubernetes,
CI/CD) are preserved and not overridden by values from the .env file, protecting
production secrets and configuration from being accidentally replaced by local
development values.
| @app.get("/api/v1/maps/markets") | ||
| @limiter.limit("20/minute") | ||
| async def get_markets(request: Request): | ||
| async def get_markets(): |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify limiter coverage for markets endpoint
rg -n -C4 '/api/v1/maps/markets|get_markets|limiter\.limit' backend/main.pyRepository: jpdevhub/FreshScanAi
Length of output: 1479
Add rate limiting to /api/v1/maps/markets endpoint.
The endpoint lacks the per-route limiter that other endpoints implement consistently (e.g., scan endpoints use @limiter.limit("20/minute")), leaving it vulnerable to burst traffic and unnecessary database load.
Proposed fix
+@limiter.limit("20/minute")
`@app.get`("/api/v1/maps/markets")
-async def get_markets():
+async def get_markets(request: Request):📝 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.
| async def get_markets(): | |
| `@limiter.limit`("20/minute") | |
| `@app.get`("/api/v1/maps/markets") | |
| async def get_markets(request: Request): |
🤖 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 `@backend/main.py` at line 775, Add a rate limiting decorator to the
`get_markets()` async function to protect it from burst traffic, following the
same pattern used by other endpoints in the codebase. Place the
`@limiter.limit("20/minute")` decorator directly above the function definition
to enforce consistent rate limiting across all API endpoints.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This is a great implementation! However, your branch is out of date and accidentally deletes the rate limiting feature we recently merged into backend/main.py. Please run git fetch upstream and git rebase upstream/main, ensuring you do not delete the @limiter.limit decorators. Once synced, we can merge it! |
|
Also dont forget to update and sync the branch in your github |
b2ea6c1 to
2d290da
Compare
|
Thanks for pointing that out. I've rebased the branch onto the latest upstream main and pushed the updated changes. I verified that the |
closes #62
Description
Checklist
npm run lintpasses with no errorsnpm run buildcompiles without TypeScript errorspython -m pytestpasses (including new tests I added).envfiles, API keys, secrets, model weights, or__pycache__in this diffmain, not mergedSummary by CodeRabbit
Summary by CodeRabbit
Release Notes