Skip to content

Feat: rate limiting#470

Merged
S1ro1 merged 1 commit intomainfrom
rate-limits
Mar 17, 2026
Merged

Feat: rate limiting#470
S1ro1 merged 1 commit intomainfrom
rate-limits

Conversation

@S1ro1
Copy link
Member

@S1ro1 S1ro1 commented Mar 17, 2026

No description provided.

Copilot AI review requested due to automatic review settings March 17, 2026 20:12
@github-actions
Copy link

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/libkernelbot
  backend.py
  consts.py 108
  db_types.py
  leaderboard_db.py 1465
  submission.py 72-73, 77-80
  utils.py
Project Total  

This report was generated by python-coverage-comment-action

@S1ro1 S1ro1 merged commit 01a0072 into main Mar 17, 2026
6 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds per-leaderboard submission rate limiting by persisting rate-limit configuration in Postgres, tagging submissions with a rate-limit category, and exposing admin endpoints to manage limits.

Changes:

  • Add leaderboard.rate_limit table and mode_category column on leaderboard.submission via migration.
  • Implement DB APIs to set/list/delete/check rate limits and enforce checks during submission preparation.
  • Add admin API endpoints and tests for rate limit configuration, plus DB-level tests for rate limit behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/test_leaderboard_db.py Adds DB-level tests for rate limit CRUD and check behavior.
tests/test_admin_api.py Adds tests for new admin rate limit endpoints.
tests/conftest.py Ensures test DB truncation clears the new rate_limit table.
src/migrations/20260317_01_rate-limits.py Introduces rate_limit table and submission.mode_category column.
src/libkernelbot/submission.py Enforces rate limits during submission preparation; stores mode_category on processed request.
src/libkernelbot/leaderboard_db.py Adds rate limit CRUD + check_rate_limit; records mode_category on submissions.
src/libkernelbot/db_types.py Introduces RateLimitItem TypedDict.
src/libkernelbot/consts.py Adds get_mode_category() mapping submission modes to rate-limit categories.
src/libkernelbot/backend.py Records submissions with UTC timestamps and mode_category.
src/kernelbot/cogs/leaderboard_cog.py Passes submission mode into prepare_submission for rate limit enforcement.
src/kernelbot/api/main.py Uses UTC timestamps, passes mode into prepare_submission, adds admin rate limit endpoints.
src/kernelbot/api/api_utils.py Updates prepare_submission call signature in streaming submission path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 148 to 151
try:
req = prepare_submission(submission, backend)
req = prepare_submission(submission, backend, mode)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
Comment on lines +77 to +85
with backend.db as db:
rate_check = db.check_rate_limit(req.leaderboard, str(req.user_id), mode_category)
if rate_check and not rate_check["allowed"]:
raise KernelBotError(
f"Rate limit exceeded: {rate_check['current_count']}/{rate_check['max_per_hour']} "
f"{mode_category} submissions per hour. "
f"Try again in {rate_check['retry_after_seconds']}s.",
code=429,
)
Comment on lines +77 to +85
with backend.db as db:
rate_check = db.check_rate_limit(req.leaderboard, str(req.user_id), mode_category)
if rate_check and not rate_check["allowed"]:
raise KernelBotError(
f"Rate limit exceeded: {rate_check['current_count']}/{rate_check['max_per_hour']} "
f"{mode_category} submissions per hour. "
f"Try again in {rate_check['retry_after_seconds']}s.",
code=429,
)
Comment on lines +1577 to +1582
if not allowed and oldest_time is not None:
import datetime as dt

expiry = oldest_time + dt.timedelta(hours=1)
now = dt.datetime.now(dt.timezone.utc)
retry_after = max(0, int((expiry - now).total_seconds()))
Comment on lines +75 to +85
mode_category = get_mode_category(mode) if mode else None
if mode_category is not None:
with backend.db as db:
rate_check = db.check_rate_limit(req.leaderboard, str(req.user_id), mode_category)
if rate_check and not rate_check["allowed"]:
raise KernelBotError(
f"Rate limit exceeded: {rate_check['current_count']}/{rate_check['max_per_hour']} "
f"{mode_category} submissions per hour. "
f"Try again in {rate_check['retry_after_seconds']}s.",
code=429,
)
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.

2 participants