Rate limit the AI governance sessions field and artifact download

Adds per-user rate limits to the aiGovernanceSessions GraphQL field and to the two session artifact download actions, so repeated calls from one user cannot tie up the shared ClickHouse server and web workers.

Why

Both read paths query ClickHouse and build their result on a web worker. Earlier MRs bounded each call: a 180-day window and a capped count in Bound AI governance session listings to a 180-d... (!265842 - merged), and a capped download file in the stacked MR on Load AI audit event details after the ClickHous... (!265815). Only the generic GraphQL and request limits bounded how often one user repeats a call. A per-user limit closes that.

The change

  • Two keys in ee/lib/ee/gitlab/application_rate_limiter/labkit_adapter/supported_rate_limits.rb: ai_governance_sessions_api (user and namespace, 120 per minute) and ai_session_artifact_download (user, 10 per minute). Both are fixed integers, like the other ai_* keys there.
  • Both checks sit behind the ai_governance_rate_limits feature flag (gitlab_com_derisk, off by default), named for the area so it can map to a rate limit class later. Rollout: #637134+.
  • Resolvers::Ai::Governance::BaseSessionsResolver checks the first key before any finder runs, so an over-limit call costs no ClickHouse or PostgreSQL query. The field returns the standard GraphQL error "This endpoint has been requested too many times. Try again later.", the same path mutations use. The scope is the user and the top-level group.
  • Security::AgentArtifactsDownloadable adds a before_action calling check_rate_limit! for download and download_session, for groups and projects. Over the limit the response is 429 with the standard message.
  • Two rows in doc/rate_limits/non_configurable.md.
  • Specs: the group and project sessions request specs assert the key and scope are counted and that an over-limit call returns the error without instantiating the finder. The group and project download controller specs assert the key, the user scope and a 429 for both actions, and that nothing is counted with the flag off.

Where the numbers come from

Also under Limits on the tracking issue. One dashboard load makes one aiGovernanceSessions call, for the "Recent agent sessions" card. The Audit events tab makes one per page, filter change or drawer open, so a busy minute is about 20 calls. 120 leaves about five times that. A download is one click, and 10 per minute is one every 6 seconds.

Decisions

  • Gitlab::ApplicationRateLimiter over a LabKit request throttle. Each limit covers one action and counts by user and namespace, which is the case the application limits guide names for this limiter.
  • Fixed values over application settings. This matches the other ai_* keys, and a setting would need a migration and an admin control for a limit no one has asked to tune. The keys are non-configurable, so there is no separate hard limit and the enforced value is the only threshold.
  • One band. The feature is Ultimate only, so there is no per-plan value.
  • The check lives in the resolver, not the field's authorize, so it runs once per field call and before any work.

Out of scope

  • The legacy duoWorkflowSessionArtifacts field gets no new limit. Its window, count cap and per-request limit already bound it, and the UI uses it only when the ai_governance_sessions_api flag is off.
  • Changing the numbers later is a one-line edit of the key.

Related to #635324.

Edited by Dheeraj Joshi

Merge request reports

Loading
Loading