Block all requests during organization maintenance mode
What does this MR do and why?
Extends organization read-only enforcement to block all requests — including GETs and GraphQL read queries — while an organization is in maintenance (read-only) mode, and renames the touched enforcement surfaces from "read-only" to "maintenance mode".
HTTP verb is an unreliable proxy for "no write": some GET endpoints perform DB writes or enqueue Sidekiq jobs (#586370 (closed)), risking data loss during cross-Cell migration cutover. Per the updated ADR (gitlab-com/content-sites/handbook!20741 (merged)), the initial iteration denies every request rather than enumerating safe reads.
Changes per surface:
- Controllers (
EnforcesOrganizationMaintenanceMode, renamed fromEnforcesReadOnlyOrganization): thewrite_request?gate is removed so every request is blocked. HTML responses render a full 503 error page instead of flash +redirect_back, since any redirect target would itself be blocked and loop. - REST API (
lib/api/helpers.rb):check_organization_maintenance_mode!/check_organization_maintenance_mode_for!(renamed) no longer gate on HTTP method; the unusedwrite_request?helper is removed. - GraphQL (
GraphqlController):disallow_requests_for_organization_maintenance_mode(renamed) blocks read queries as well as mutations, since queries can invoke resolvers with write side effects. - User-facing message unified to:
This organization is temporarily unavailable due to maintenance.
The JSON/API 503-vs-403 split (time-bounded vs indefinite reasons, Retry-After header) is unchanged.
What this MR does NOT rename
The model layer (Organizations::Stateful states/events such as start_read_only, read_only_enforced?), the organization_read_only_enforcement feature flag, Gitlab::GitAccess#check_organization_read_only!, and OAuth's NewUserOrganizationReadOnlyError keep their read-only names for a follow-up rename. The OAuth code is removed by !249855 (merged) anyway.
Everything remains behind the default-off organization_read_only_enforcement feature flag, so there is no user-visible change until rollout (#603377 (closed)).
References
- Resolves #607966 (closed)
- ADR update (block all requests, rename to Maintenance Mode): gitlab-com/content-sites/handbook!20741 (merged)
- Source discussion: !241161 (comment 3641124703)
- Epic: &20404
- Related reverts (auth exemption removal): !249739 (merged), !249855 (merged)
Screenshots or screen recordings
| Before | After |
|---|---|
How to set up and validate locally
-
In rails console, enable the feature flag and put an organization into maintenance mode:
org = Organizations::Organization.find_by(path: 'my-org') # any non-default org Feature.enable(:organization_read_only_enforcement, org) org.start_read_only(read_only_reason: 'migration') org.confirm_read_only -
Visit any page of the organization (a simple
GET, e.g. a project page) — you should see the 503 error page withThis organization is temporarily unavailable due to maintenance. -
Issue a
GETREST API request, e.g.curl -H "PRIVATE-TOKEN: <token>" "http://gdk.test:3000/api/v4/projects/<id>"for a project in that organization — expect503with aRetry-After: 60header. -
Issue a GraphQL read query — expect a 503 with the maintenance mode error message.
-
Exit maintenance mode with
org.exit_read_onlyand confirm requests succeed again.
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.