Skip to content

Commit 5822980

Browse files
desioracclaude
andcommitted
fix: stop bot-UA guard from silently blocking real customers in checkout
Bot UA detection (python-requests, curl) was forcing test mode in /v1/keys/setup and /v1/keys/trial endpoints. Real SDK users calling the API would get Stripe test sessions and could never pay. Rate-limiting already protects against abuse. - Remove bot-UA → test-mode forcing from both checkout endpoints - Remove redundant _classify_visitor guard (covered by IP check) - Keep bot classification for analytics/funnel attribution - Update test to verify new behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6eefe0c commit 5822980

2 files changed

Lines changed: 10 additions & 15 deletions

File tree

tests/test_visitor_attribution.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,19 +192,21 @@ def test_setup_internal_ip_forces_test_mode(self, client, monkeypatch):
192192
assert mock_create.call_args.kwargs["api_key"] == "sk_test_fake"
193193
assert mock_checkout.call_args.kwargs["metadata"]["stripe_mode"] == "test"
194194

195-
def test_setup_bot_ua_forces_test_mode(self, client, monkeypatch):
195+
def test_setup_bot_ua_keeps_live_mode(self, client, monkeypatch):
196+
"""Bot-like UAs (python-requests, curl) should NOT be forced to test mode —
197+
real SDK users would be silently blocked from paying. Rate-limiting protects against abuse."""
196198
from unittest.mock import MagicMock, patch
197199
import trust_layer.app as app_mod
198200
monkeypatch.setattr(app_mod, "STRIPE_TEST_KEY", "sk_test_fake")
199201
monkeypatch.setattr(app_mod, "STRIPE_PRO_PRICE_ID_TEST", "price_test_pro")
200202

201203
mock_customer = MagicMock()
202-
mock_customer.id = "cus_test_bot"
204+
mock_customer.id = "cus_live_sdk"
203205
mock_list = MagicMock()
204206
mock_list.data = []
205207
mock_session = MagicMock()
206-
mock_session.url = "https://checkout.stripe.com/pay/cs_test"
207-
mock_session.id = "cs_test"
208+
mock_session.url = "https://checkout.stripe.com/pay/cs_live"
209+
mock_session.id = "cs_live"
208210

209211
with patch("stripe.Customer.list", return_value=mock_list), \
210212
patch("stripe.Customer.create", return_value=mock_customer) as mock_create, \
@@ -214,5 +216,5 @@ def test_setup_bot_ua_forces_test_mode(self, client, monkeypatch):
214216
}, headers={"user-agent": "python-requests/2.31.0", "x-real-ip": "8.8.8.8"})
215217

216218
assert r.status_code == 200
217-
assert mock_create.call_args.kwargs["api_key"] == "sk_test_fake"
218-
assert mock_checkout.call_args.kwargs["metadata"]["stripe_mode"] == "test"
219+
assert mock_create.call_args.kwargs["api_key"] != "sk_test_fake"
220+
assert mock_checkout.call_args.kwargs["metadata"]["stripe_mode"] == "live"

trust_layer/app.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -886,11 +886,7 @@ async def setup_key(request: Request):
886886
logger.warning("keys/setup: email %r looks like test — forcing test mode", email)
887887
req_mode = "test"
888888
if req_mode == "live" and user_agent and _BOT_UA_RE.search(user_agent):
889-
logger.warning("keys/setup: bot UA %r — forcing test mode", user_agent[:80])
890-
req_mode = "test"
891-
if req_mode == "live" and not visitor.get("is_external", True):
892-
logger.warning("keys/setup: visitor classified non-external (%s) — forcing test mode", visitor.get("reason", "unknown"))
893-
req_mode = "test"
889+
logger.info("keys/setup: bot-like UA %r — keeping live mode (rate-limit protects)", user_agent[:80])
894890
lang = body.get("lang", "fr")
895891
if lang not in ("en", "fr"):
896892
lang = "fr"
@@ -1207,10 +1203,7 @@ async def create_trial(request: Request):
12071203
if "test" in local_part or "diag" in local_part or "e2e" in local_part or "healthcheck" in local_part or "verify" in local_part or "flow-" in local_part:
12081204
req_mode = "test"
12091205
if req_mode == "live" and user_agent and _BOT_UA_RE.search(user_agent):
1210-
req_mode = "test"
1211-
if req_mode == "live" and not visitor.get("is_external", True):
1212-
logger.warning("keys/free-signup: visitor classified non-external (%s) — forcing test mode", visitor.get("reason", "unknown"))
1213-
req_mode = "test"
1206+
logger.info("keys/trial: bot-like UA %r — keeping live mode (rate-limit protects)", user_agent[:80])
12141207

12151208
lang = body.get("lang", "en")
12161209
if lang not in ("en", "fr"):

0 commit comments

Comments
 (0)