feat(api): Allow per-org rate limit overrides for project transfer#113507
Conversation
The ProjectTransferEndpoint POST rate limit was a hardcoded 3/hour per
user. Some orgs legitimately need a higher ceiling (e.g. during a bulk
migration) and changing the value previously required a code deploy.
Introduce the `api.project-transfer.rate-limit-overrides` option, a dict
keyed by org id/slug mapping to `{"limit": int, "window": int}`. When a
request's org has no entry (or the option is unset), the endpoint falls
back to the original 3/hour default.
Co-Authored-By: Claude <noreply@anthropic.com>
The option is typed as Dict but nested values aren't validated, so a misconfiguration like `my-org: 100` would cause `override.get(...)` to raise AttributeError and return 500. Fall back to the default when the per-org entry isn't a dict.
Backend Test FailuresFailures on
|
| RateLimitCategory.USER: RateLimit( | ||
| limit=override.get("limit", 3), | ||
| window=override.get("window", 60 * 60), | ||
| ), |
There was a problem hiding this comment.
I'd probably recommend putting some kind of reasonable upper limit on this. In the past, when we allow increased limits we've usually just made it a feature flag with a hard coded higher rate limit/quota/whatever.
So we can either take that approach here, or cap it to some amount per hour.
I'd probably remove the ability to change the window, and just allow the limit to be modified. Just easier to reason about if we know that it's an hourly rate-limit and we allow you to increase it from 3 up to (say) 50
There was a problem hiding this comment.
I took it over from Michi, moved it to only a limit with a fixed window, we can set the limit to something reasonable in settings (e.g. 20 per hour) to help the user with migration, and bring it back down until there is a need again for it
Backend Test FailuresFailures on
|
The
ProjectTransferEndpointPOST rate limit was a hardcoded 3/hour peruser. Some orgs legitimately need a higher ceiling (e.g. during a bulk
project migration) and bumping the value previously required a code
deploy.
The callable form is required because the rate-limit middleware reads
view_cls.rate_limitsonce per class import for static configs — only acallable is re-evaluated per request, which is necessary for the option
to actually take effect at runtime.