Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 943ad3e

Browse files
authored
feat: Use env var for GQL rate limit instead of hard code val (#904)
1 parent 1203a60 commit 943ad3e

File tree

4 files changed

+31
-5
lines changed

4 files changed

+31
-5
lines changed

codecov/settings_base.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,22 @@
9292

9393
WSGI_APPLICATION = "codecov.wsgi.application"
9494

95-
# Database
96-
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
95+
96+
# GraphQL
9797

9898
GRAPHQL_QUERY_COST_THRESHOLD = get_config(
9999
"setup", "graphql", "query_cost_threshold", default=10000
100100
)
101101

102+
GRAPHQL_RATE_LIMIT_ENABLED = get_config(
103+
"setup", "graphql", "rate_limit_enabled", default=True
104+
)
105+
106+
GRAPHQL_RATE_LIMIT_RPM = get_config("setup", "graphql", "rate_limit_rpm", default=300)
107+
108+
# Database
109+
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
110+
102111
DATABASE_ROUTERS = ["codecov.db.DatabaseRouter"]
103112

104113
# Password validation

codecov/settings_staging.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
# 25MB in bytes
6666
DATA_UPLOAD_MAX_MEMORY_SIZE = 26214400
6767

68+
GRAPHQL_RATE_LIMIT_RPM = get_config("setup", "graphql", "rate_limit_rpm", default=1000)
69+
6870
# Same site is set to none on Staging as we want to be able to call the API
6971
# From Netlify preview deploy
7072
COOKIE_SAME_SITE = "None"

graphql_api/tests/test_views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ async def test_query_metrics_extension_set_type_and_name_timeout(
203203

204204
@patch("sentry_sdk.metrics.incr")
205205
@patch("graphql_api.views.AsyncGraphqlView._check_ratelimit")
206+
@override_settings(DEBUG=False, GRAPHQL_RATE_LIMIT_RPM=1000)
206207
async def test_when_rate_limit_reached(
207208
self, mocked_check_ratelimit, mocked_sentry_incr
208209
):
@@ -213,7 +214,7 @@ async def test_when_rate_limit_reached(
213214
assert response["status"] == 429
214215
assert (
215216
response["detail"]
216-
== "It looks like you've hit the rate limit of 300 req/min. Try again later."
217+
== "It looks like you've hit the rate limit of 1000 req/min. Try again later."
217218
)
218219

219220
expected_calls = [
@@ -222,6 +223,17 @@ async def test_when_rate_limit_reached(
222223
]
223224
mocked_sentry_incr.assert_has_calls(expected_calls)
224225

226+
@override_settings(
227+
DEBUG=False, GRAPHQL_RATE_LIMIT_RPM=0, GRAPHQL_RATE_LIMIT_ENABLED=False
228+
)
229+
def test_rate_limit_disabled(self):
230+
# rate limit is 0, so any request would cause a rate limit if the GQL rate limit was enabled
231+
view = AsyncGraphqlView()
232+
request = Mock()
233+
234+
result = view._check_ratelimit(request)
235+
assert result == False
236+
225237
def test_client_ip_from_x_forwarded_for(self):
226238
view = AsyncGraphqlView()
227239
request = Mock()

graphql_api/views.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ async def post(self, request, *args, **kwargs):
233233
return JsonResponse(
234234
data={
235235
"status": 429,
236-
"detail": "It looks like you've hit the rate limit of 300 req/min. Try again later.",
236+
"detail": f"It looks like you've hit the rate limit of {settings.GRAPHQL_RATE_LIMIT_RPM} req/min. Try again later.",
237237
},
238238
status=429,
239239
)
@@ -306,6 +306,9 @@ def _get_user(self, request):
306306
request.user.pk
307307

308308
def _check_ratelimit(self, request):
309+
if not settings.GRAPHQL_RATE_LIMIT_ENABLED:
310+
return False
311+
309312
redis = get_redis_connection()
310313

311314
try:
@@ -320,7 +323,7 @@ def _check_ratelimit(self, request):
320323
user_ip = self.get_client_ip(request)
321324
key = f"rl-ip:{user_ip}"
322325

323-
limit = 300
326+
limit = settings.GRAPHQL_RATE_LIMIT_RPM
324327
window = 60 # in seconds
325328

326329
current_count = redis.get(key)

0 commit comments

Comments
 (0)