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 from EnforcesReadOnlyOrganization): the write_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 unused write_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

Screenshots or screen recordings

Before After

How to set up and validate locally

  1. 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
  2. Visit any page of the organization (a simple GET, e.g. a project page) — you should see the 503 error page with This organization is temporarily unavailable due to maintenance.

  3. Issue a GET REST API request, e.g. curl -H "PRIVATE-TOKEN: <token>" "http://gdk.test:3000/api/v4/projects/<id>" for a project in that organization — expect 503 with a Retry-After: 60 header.

  4. Issue a GraphQL read query — expect a 503 with the maintenance mode error message.

  5. Exit maintenance mode with org.exit_read_only and 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.

Merge request reports

Loading
Loading