Step 4: Enforce read-only mode for GraphQL mutations

Summary

Block GraphQL mutations that target namespaces in maintenance state. Rack middleware alone is insufficient for GraphQL because the namespace is embedded in the request body (all GraphQL requests are POST to /api/graphql).

POC approach: This will be part of a single POC MR (does not need to merge to master). Maintenance mode will be toggled via Rails console.

Dependencies

Context

Parent issue: #590009 (closed)

GraphQL mutations are all POST requests to a single endpoint, so the namespace-scoped middleware (Step 2) cannot determine the target namespace from the URL path alone. Enforcement must happen at the GraphQL layer.

Tasks

  • Investigate enforcement approaches:
    • Option A: Custom GraphQL::Analysis::AST::Analyzer that inspects mutation arguments for namespace/group/project references and checks maintenance state
    • Option B: Override in Mutations::BaseMutation to check namespace state before executing
    • Option C: Add a shared concern to resolvers/mutations that checks the namespace of the resolved object
  • Implement chosen approach
  • Ensure GraphQL queries (reads) still work — only mutations should be blocked
  • Return a structured GraphQL error with appropriate message and extensions (e.g., { "extensions": { "code": "NAMESPACE_MAINTENANCE" } })
  • Add specs covering: mutation blocking, query passthrough, nested namespace resolution

Key Files

  • app/graphql/mutations/base_mutation.rb
  • app/controllers/graphql_controller.rb
  • app/graphql/types/mutation_type.rb

Effort Estimate

Medium (2-3 days)

Edited by Chen Zhang