Rate limit context commit writes per user

What does this MR do and why?

Merge request context commits are previously merged commits that you add to a merge request for context. You add and remove them with the REST API, or with the Add or remove previously merged commits modal, which calls the same API. Neither endpoint has a rate limit.

This MR adds a per-user rate limit of 10 requests per minute, shared between:

  • POST /projects/:id/merge_requests/:merge_request_iid/context_commits
  • DELETE /projects/:id/merge_requests/:merge_request_iid/context_commits

Over the limit, both endpoints return 429 Too Many Requests.

  • One unit per request, however many commits it lists. The modal sends all removed commits in one DELETE, and POST already accepts at most 20 commits per request.
  • The check runs after the authorization check, so requests from users who can't update the merge request don't count toward the limit.
  • Behind the rate_limit_context_commits_write feature flag (gitlab_com_derisk, disabled by default, user actor).
  • As with other application rate limits, requests that send the rate limit bypass header aren't limited.

References

Screenshots or screen recordings

Not applicable: no UI change. When a save is rate limited, the modal shows its existing "Please try again" alert. If a save both adds and removes commits and only one of the two requests is limited, the page reloads without an alert, as it already does for any partial failure.

How to set up and validate locally

  1. In the Rails console, enable the flag for your user:

    Feature.enable(:rate_limit_context_commits_write, User.find_by_username('<your username>'))
  2. Pick a merge request you can update, and a commit SHA from its target branch that isn't in the merge request.

  3. Add and remove that commit 6 times within a minute (12 requests):

    for i in $(seq 6); do
      curl --request POST --header "PRIVATE-TOKEN: <token>" --header "Content-Type: application/json" \
        --data '{"commits": ["<sha>"]}' \
        --url "http://gdk.test:3000/api/v4/projects/<project id>/merge_requests/<iid>/context_commits" \
        --output /dev/null --write-out "POST %{http_code}\n"
      curl --request DELETE --header "PRIVATE-TOKEN: <token>" --header "Content-Type: application/json" \
        --data '{"commits": ["<sha>"]}' \
        --url "http://gdk.test:3000/api/v4/projects/<project id>/merge_requests/<iid>/context_commits" \
        --output /dev/null --write-out "DELETE %{http_code}\n"
    done

    The first 10 requests return 201 or 204. The last 2 return 429.

  4. Disable the flag and repeat. No request returns 429.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Eugenia Grieff

Merge request reports

Loading
Loading