Reject scope=all on root issues REST API endpoints
What does this MR do and why?
The root GET /issues and GET /issues_statistics REST API endpoints allow scope=all without authentication. With no project or group to bound the query, IssuesFinder resolves the accessible projects to every visible project on the instance (Project.public_or_visible_to_user), so the query scans issues across all public projects and runs an unbounded COUNT for pagination. On a large instance such as GitLab.com this statement-times-out and returns 500 Internal Server Error, for both anonymous and authenticated requests.
This MR rejects scope=all on the two root endpoints with a clear 400 Bad Request instead of running the unbounded query. scope=all remains supported on the group and project issues endpoints, where the query is bounded by the parent.
The restriction applies to GitLab.com only. It is gated behind the restrict_global_issues_scope_all feature flag (gitlab_com_derisk, disabled by default), which is the rollout control and the kill switch on GitLab.com. GitLab Self-Managed and GitLab Dedicated keep the existing behavior whatever the flag says. The endpoint checks Gitlab.com? directly, with a rubocop disable marked as a temporary guard that goes away with the flag.
Closes #478744
Behavior
| Request | Flag off (default, today) | Flag on (GitLab.com only) |
|---|---|---|
GET /issues?scope=all |
500 at scale / 200 small instance | 400 with guidance message |
GET /issues_statistics?scope=all |
500 at scale / 200 | 400 |
GET /issues (no scope) |
401 if anonymous | unchanged |
scope=created_by_me / assigned_to_me |
unchanged | unchanged |
/groups/:id/issues, /projects/:id/issues with scope=all |
unchanged | unchanged |
| Any of the above on Self-Managed or Dedicated | unchanged | unchanged |
Breaking change
On GitLab.com, when the flag is enabled, a previously documented scope value returns 400 on the root endpoints. This is a deliberate correction of behavior that currently returns 500. Callers needing a global list should use created_by_me/assigned_to_me or the group/project endpoints. Self-Managed and Dedicated are not affected.
Feature flag rollout
Rollout issue: #634324
- Enable for
gitlab-orgfirst as a smoke test. The actor iscurrent_user, so anonymous requests (nil actor) are only covered once the flag is fully enabled. - Enable on GitLab.com for everyone via ChatOps and confirm the endpoint 500 rate / SLO recovers.
- Remove the flag together with the
Gitlab.com?guard once stable, or decide at that point to keep the.comcheck as a SaaS-only behavior.
Testing
spec/requests/api/issues/issues_spec.rb, GitLab.com with the flag on: anonymous and authenticatedscope=allon/issuesand/issues_statisticsreturn 400,assigned_to_mestill returns 200, no scope still returns 401 for anonymous.- Same spec, GitLab.com with the flag off:
scope=allreturns 200. - Same spec, not GitLab.com with the flag on:
scope=allreturns 200. spec/requests/api/issues/get_project_issues_spec.rb: the project endpoint withscope=allstill returns 200 on GitLab.com with the flag on.