Restrict feature flag management by minimum role

What does this MR do and why?

Today, any project member with the Developer role or above can create, toggle, and delete feature flags, and there is no way to restrict this. This is a long-standing ask (see the References below) from teams with change-control or compliance requirements, particularly for production flags.

This MR is Phase 1 (backend gate) of adding feature flag management permissions. It introduces a project setting — the minimum role required to manage feature flags — and enforces it in ProjectPolicy.

Behavior

  • New project setting feature_flags_minimum_role: developer (default) · maintainer · owner · no_one_allowed.
  • Members below the configured role can still read feature flags and their on/off state, but cannot create, update (toggle), or delete them, and cannot manage feature flag user lists (a strategy can target a user list, so editing one changes which users a flag applies to).
  • Admins bypass the restriction, except when it is set to no_one_allowed.
  • A meta-permission controls who can change the setting: update_feature_flags_minimum_role_setting is granted to Maintainers, but loosening the setting away from a privileged state (owner / no_one_allowed) requires _update_privileged_feature_flags_minimum_role_setting, granted to Owners. This prevents a Maintainer from quietly weakening an Owner-set restriction.

Why no_one_allowed

no_one_allowed is a true freeze: it blocks feature flag management for everyone, including instance administrators. This is deliberate. It exists for change-control and compliance needs — locking down all feature flag changes during a change-freeze window, an active incident, or an audit.

It is not a lockout risk, because changing the setting is gated separately from managing flags. An Owner lifts the freeze via update_feature_flags_minimum_role_setting first, then manages flags. That separation is also why the value sits at the top of the scale (developermaintainerownerno_one_allowed) rather than being a distinct boolean.

Design

This mirrors the shipped ci_pipeline_variables_minimum_override_role pattern. All feature flag write surfaces (REST API, controllers, services, serializers) already authorize through the create_feature_flag / update_feature_flag / admin_feature_flag / destroy_feature_flag abilities, so a single policy gate covers every surface.

  • ProjectSetting#feature_flags_management_allowed?(access_level, user) performs the role comparison.
  • ProjectPolicy prevents the write abilities when the member is below the threshold (behind the feature_flag_management_permissions feature flag).

Not a breaking change

The behavior is guarded by the default-off feature_flag_management_permissions feature flag, and the setting's default value (developer) preserves today's behavior. No project changes behavior until an Owner/Maintainer opts in.

Scope of this MR

Backend gate only. Exposing the setting via GraphQL/REST (with UpdateService enforcement of the meta-permission) and a settings UI will follow in subsequent MRs. There are no user-facing docs in this MR because the setting is not yet writable through the API or UI; docs will accompany those MRs.

Screenshots or screen recordings

N/A — backend only, no UI in this MR.

How to set up and validate locally

  1. Create a project and add a Developer and a Maintainer.
  2. Enable the flag: Feature.enable(:feature_flag_management_permissions).
  3. Set project.project_setting.update!(feature_flags_minimum_role: :maintainer).
  4. As the Developer, Ability.allowed?(developer, :update_feature_flag, project) is false; as the Maintainer it is true. :read_feature_flag remains true for both.

Covered by specs:

  • spec/models/project_setting_spec.rb — role threshold logic and privileged-state helper.
  • spec/policies/project_policy_spec.rb — full role × minimum-role matrix, feature-flag-off short-circuit, read-still-allowed, admin bypass, and the meta-permission.

References

MR acceptance checklist

This change touches authorization; a review of the policy changes is appreciated.

Edited by Tim Rizzi

Merge request reports

Loading