Skip to content

fix: rate limit the ask and live pull endpoints - #7

Merged
elsisiem merged 1 commit into
mainfrom
fix/rate-limit-costly-endpoints
Oct 27, 2026
Merged

elsisiem merged 1 commit into
mainfrom
fix/rate-limit-costly-endpoints

Conversation

@elsisiem

@elsisiem elsisiem commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

/ask and /live/pull spend OpenAI, Exa and Bright Data credits and had no limit. The per-client limiter from /note is now generic and applied at 10 asks and 2 pulls per 60 s; the background live loop calls an internal pull and is not limited. Verified with a TestClient run.

POST /api/conf/{id}/ask and POST /api/conf/{id}/live/pull spend OpenAI,
Exa and Bright Data credits and had no limit. Generalize the in-memory
per-client limiter used by /note and apply it at 10 asks and 2 pulls per
60 s. The background live loop calls the pull directly and is not limited.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e9414b03-ba48-4fa3-a514-7b8f9099059e
Commits

Reviewing files that changed from the base of the PR and between 36f5c5b and 057325b.

Files selected for processing: 2
  • README.md
  • app/server.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Rate-limit costly ask and manual live-pull endpoints

🐞 Bug fix 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Limit each client to 10 questions and 2 manual pulls per minute to protect API credits.
• Reuse the room-report limiter while keeping scheduled live pulls outside the client budget.
• Document the limits and their in-memory, per-instance scope.
Diagram

graph TD
  Client["API client"] --> Ask["Ask endpoint"] --> AskLimit{"10 per minute"} --> Answer["Graph and OpenAI"]
  Client --> Manual["Manual pull"] --> PullLimit{"2 per minute"} --> Ingest["Live ingestion"]
  Loop["Background loop"] --> Ingest
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Shared-store rate limiter
  • ➕ Enforces budgets consistently across instances and restarts.
  • ➖ Adds infrastructure and operational complexity for the current deployment.

Recommendation: The existing in-memory limiter is the proportionate choice for this focused credit-protection fix, and separating the internal pull preserves scheduled ingestion. Consider a shared store if the service runs multiple instances or needs durable limits.

Files changed (2) +30 / -13

Bug fix (1) +29 / -12
server.pyApply per-client budgets to costly endpoints +29/-12

Apply per-client budgets to costly endpoints

• Generalizes the room-report limiter and adds separate 10-per-minute ask and 2-per-minute manual-pull budgets, returning HTTP 429 when exceeded. Extracts the pull operation so scheduled ingestion can call it without consuming the manual-pull budget.

app/server.py

Documentation (1) +1 / -1
README.mdDocument endpoint budgets and their scope +1/-1

Document endpoint budgets and their scope

• Lists the per-client limits for questions, manual pulls, and room reports. Clarifies that limits reset on restart, are not shared across instances, and do not apply to the background loop.

README.md

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Venue guests share one question budget 🐞 Bug ≡ Correctness
Description
ask() keys _ask_hits solely by _client_ip(request), so visitors behind the same public IP
consume the same ten-request allowance. When attendees use a venue network with shared egress, ten
questions from any combination of them cause subsequent attendees' questions to receive 429, even if
those attendees have made no requests.
Code

app/server.py[R475-476]

+    if not _allowed(_ask_hits, _client_ip(request), ASK_LIMIT, ASK_WINDOW):
+        raise HTTPException(429, "easy. ten questions a minute per person is plenty")
Relevance

●● Moderate

Valid shared-IP fairness concern, but changing anonymous client identity is architectural and lacks
close historical precedent.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new ask check passes the value returned by _client_ip to _allowed. That helper uses a
forwarded or socket IP address, and _allowed stores request timestamps under exactly that key; it
cannot distinguish visitors who share an address. The console sends its question requests to this
endpoint.

app/server.py[50-68]
app/server.py[473-477]
app/static/app.js[418-420]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Visitors sharing a public IP also share the new ask budget, so one group can exhaust it for other attendees.
## Fix Focus Areas
- app/server.py[50-54]
- app/server.py[473-476]
## Recommended Fix
Use a visitor-specific identity for the ask budget, such as a server-issued signed session identifier, while retaining a separate, appropriately sized IP-level backstop against anonymous abuse.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


Grey Divider

Context sources
Review mode: Auto: ⚖️ Balanced: Rate limiting costly public endpoints changes security-sensitive runtime behavior.

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread app/server.py
Comment on lines +475 to +476
if not _allowed(_ask_hits, _client_ip(request), ASK_LIMIT, ASK_WINDOW):
raise HTTPException(429, "easy. ten questions a minute per person is plenty")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Venue guests share one question budget 🐞 Bug ≡ Correctness

ask() keys _ask_hits solely by _client_ip(request), so visitors behind the same public IP
consume the same ten-request allowance. When attendees use a venue network with shared egress, ten
questions from any combination of them cause subsequent attendees' questions to receive 429, even if
those attendees have made no requests.
Agent Prompt
## Issue description
Visitors sharing a public IP also share the new ask budget, so one group can exhaust it for other attendees.
## Fix Focus Areas
- app/server.py[50-54]
- app/server.py[473-476]
## Recommended Fix
Use a visitor-specific identity for the ask budget, such as a server-issued signed session identifier, while retaining a separate, appropriately sized IP-level backstop against anonymous abuse.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

@elsisiem
elsisiem merged commit 3a577e2 into main Oct 27, 2026
3 checks passed
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