Rate limit the bulk AI tool rules mutation per user

What does this MR do and why?

One group Owner can call bulkUpdateAiToolRules as often as the generic GraphQL throttle allows, about 2,000 times a minute, and every call writes up to 100 rule rows plus one audit event with its streaming job. This MR adds a per-user limit of 10 calls a minute, behind the ai_tool_rules_bulk_update_rate_limit feature flag: the same number as the AI Catalog bulk enable mutation, and the same shape as the model selection update mutation (the throttled call raises, so the response is a 429 and nothing is written or audited).

  1. Registry entry ai_tool_rules_bulk_update (10 a minute, per user) in the EE rate limit registry.
  2. check_rate_limit! right after the namespace lookup and authorization, the order the sibling mutations use: flag on and over the limit raises the standard "requested too many times" error; nothing is written or audited.
  3. Feature flag ai_tool_rules_bulk_update_rate_limit (gitlab_com_derisk, disabled by default, actor is the user).
  4. Docs row in the non-configurable rate limits page.

Review notes

  • Alternatives considered: no flag (the Bulkhead sibling limits all shipped flagged, so the limit can be turned off per user if a scripted caller is hit); an admin setting for the limit (not asked for; the issue records 60 a minute as the ceiling such a setting could expose).
  • Not done, tracked at https://gitlab.com/gitlab-org/gitlab/-/work_items/636289: the two no-op write skips from the same issue follow in separate MRs.
  • Approvals: backend maintainer (ee/config/feature_flags/ is owned by rails-backend maintainers); technical writer for the docs row; no database review (no query change).
  • No UI calls this mutation; the limit touches API and scripted callers only.
  • No changelog entry: the change sits behind a flag that is disabled by default.
  • A request that aliases the mutation more than ten times gets a 429 after the first ten writes committed, the same as the model selection mutation; the per-call limit is the point.
  • The single-rule mutation updateAiToolRule is not limited here; it writes one row and one audit event per call.
  • Specs run locally: ee/spec/graphql/mutations/ai/bulk_update_ai_tool_rules_spec.rb (33 examples), ee/spec/requests/api/graphql/mutations/ai/bulk_update_ai_tool_rules_spec.rb (17), ee/spec/lib/ee/gitlab/application_rate_limiter/labkit_adapter/supported_rate_limits_spec.rb (16). Negative controls, one line each: removing the check_rate_limit! call, the feature flag check, or the per-user scope each fails at least two examples.
  • Verified on a GDK over HTTP with the flag on for one user: calls 1 to 10 succeed, calls 11 and 12 return 429 with no rule write and no audit event, the flag off lets the same user through, and the next minute resets the count.

Manual verification (GDK, SaaS mode, flag enabled per user)

Results, mutation driven through POST /api/graphql
Case Expected Result
Flag off, 12 calls in a minute all succeed, 12 audit events pass
Flag on, calls 1 to 10 succeed pass
Flag on, call 11 429 with the standard message, nothing written, no audit event, one auth_json.log line pass
Second Owner right after the 429 succeeds pass
User without access, 11 calls same not-available error every time, never a 429 pass
Project-scoped payload, 11 calls call 11 is a 429 pass
After the one-minute window succeeds pass
11 aliased fields in one request 429 after the first ten writes committed pass, documented above

References

How to set up and validate locally

bin/rspec ee/spec/requests/api/graphql/mutations/ai/bulk_update_ai_tool_rules_spec.rb -e 'rate limiting'

With the flag enabled for a user (Feature.enable(:ai_tool_rules_bulk_update_rate_limit, user)), the eleventh bulkUpdateAiToolRules call within a minute returns the error "This endpoint has been requested too many times. Try again later." and writes no rule.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Pratyaksh Golash

Merge request reports

Loading
Loading