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) andai_session_artifact_download(user, 10 per minute). Both are fixed integers, like the otherai_*keys there. - Both checks sit behind the
ai_governance_rate_limitsfeature 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::BaseSessionsResolverchecks 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::AgentArtifactsDownloadableadds abefore_actioncallingcheck_rate_limit!fordownloadanddownload_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::ApplicationRateLimiterover 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
duoWorkflowSessionArtifactsfield gets no new limit. Its window, count cap and per-request limit already bound it, and the UI uses it only when theai_governance_sessions_apiflag is off. - Changing the numbers later is a one-line edit of the key.
Related to #635324.