Convert top_level_group_creation_enabled FF into an application_setting

Related to #506673 (closed)

What does this MR do?

Converts the :top_level_group_creation_enabled feature flag into an application_setting.

  • Adds group_setting jsonB column
  • Adds an object constraint
  • Converts the :top_level_group_creation_enabled feature flag to an application_setting
  • Updates the policy condition to rely on the new application_setting
  • Removes the :top_level_group_creation_enabled feature flag` from the codebase

Why?

Previously, the top_level_group_creation_enabled feature flag was disabled on gitlab.com to limit group creation abuse but enabled by default on self-managed. Due to the reasons mentioned here, feature flags should not be used for long-lived settings.

Database Review

bin/rails db:migrate
hakeem@habdul-razak--20240918-F45T4 gitlab % bin/rails db:migrate             
DEPRECATION WARNING: Support for Rails versions < 7.1 is deprecated and will be removed from ViewComponent 4.0.0 (ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025) (called from <main> at /Users/hakeem/gitlab-development-kit/gitlab/config/environment.rb:7)
main: == [advisory_lock_connection] object_id: 132960, pg_backend_pid: 45348
main: == 20250410032730 AddGroupSettingsToApplicationSettings: migrating ============
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- add_column(:application_settings, :group_settings, :jsonb, {:default=>{}, :null=>false})
main:    -> 0.0033s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- execute("ALTER TABLE application_settings\nADD CONSTRAINT check_application_settings_group_settings_is_hash\nCHECK ( (jsonb_typeof(group_settings) = 'object') )\nNOT VALID;\n")
main:    -> 0.0017s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0002s
main: -- execute("ALTER TABLE application_settings VALIDATE CONSTRAINT check_application_settings_group_settings_is_hash;")
main:    -> 0.0013s
main: -- execute("RESET statement_timeout")
main:    -> 0.0002s
main: == 20250410032730 AddGroupSettingsToApplicationSettings: migrated (0.0437s) ===

main: == [advisory_lock_connection] object_id: 132960, pg_backend_pid: 45348
ci: == [advisory_lock_connection] object_id: 133300, pg_backend_pid: 45350
ci: == 20250410032730 AddGroupSettingsToApplicationSettings: migrating ============
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- add_column(:application_settings, :group_settings, :jsonb, {:default=>{}, :null=>false})
ci:    -> 0.0036s
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- execute("ALTER TABLE application_settings\nADD CONSTRAINT check_application_settings_group_settings_is_hash\nCHECK ( (jsonb_typeof(group_settings) = 'object') )\nNOT VALID;\n")
ci:    -> 0.0022s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0002s
ci: -- execute("ALTER TABLE application_settings VALIDATE CONSTRAINT check_application_settings_group_settings_is_hash;")
ci:    -> 0.0011s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0002s
ci: == 20250410032730 AddGroupSettingsToApplicationSettings: migrated (0.0201s) ===

ci: == [advisory_lock_connection] object_id: 133300, pg_backend_pid: 45350
VERSION=20250410032730 bin/rails db:rollback:main && VERSION=20250410032730 bin/rails db:rollback:ci
hakeem@habdul-razak--20240918-F45T4 gitlab % VERSION=20250410032730 bin/rails db:rollback:main && VERSION=20250410032730 bin/rails db:rollback:ci
DEPRECATION WARNING: Support for Rails versions < 7.1 is deprecated and will be removed from ViewComponent 4.0.0 (ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025) (called from <main> at /Users/hakeem/gitlab-development-kit/gitlab/config/environment.rb:7)
main: == [advisory_lock_connection] object_id: 132640, pg_backend_pid: 42695
main: == 20250410032730 AddGroupSettingsToApplicationSettings: reverting ============
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- execute("            ALTER TABLE application_settings\n            DROP CONSTRAINT IF EXISTS check_application_settings_group_settings_is_hash\n")
main:    -> 0.0014s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- remove_column(:application_settings, :group_settings)
main:    -> 0.0017s
main: == 20250410032730 AddGroupSettingsToApplicationSettings: reverted (0.0229s) ===

main: == [advisory_lock_connection] object_id: 132640, pg_backend_pid: 42695
DEPRECATION WARNING: Support for Rails versions < 7.1 is deprecated and will be removed from ViewComponent 4.0.0 (ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025) (called from <main> at /Users/hakeem/gitlab-development-kit/gitlab/config/environment.rb:7)
ci: == [advisory_lock_connection] object_id: 132640, pg_backend_pid: 42804
ci: == 20250410032730 AddGroupSettingsToApplicationSettings: reverting ============
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- execute("            ALTER TABLE application_settings\n            DROP CONSTRAINT IF EXISTS check_application_settings_group_settings_is_hash\n")
ci:    -> 0.0014s
ci: -- transaction_open?(nil)
ci:    -> 0.0000s
ci: -- remove_column(:application_settings, :group_settings)
ci:    -> 0.0018s
ci: == 20250410032730 AddGroupSettingsToApplicationSettings: reverted (0.0246s) ===

ci: == [advisory_lock_connection] object_id: 132640, pg_backend_pid: 42804

How to set up and validate locally

  • Create a user, impersonate & create a PAT with an API scope
  • Open a terminal & make an API request to create a top_level_group
curl -X POST --header "PRIVATE-TOKEN: <token>" "https://gdk.test:3443/api/v4/groups?name=top_level_group1&path=top_level_group1&visibility=public"
  • Verify that it successfully creates a top-level-group
  • As an admin, disable the new top_level_group_creation_enabled application_setting
curl -X PUT --header "PRIVATE-TOKEN: <token>" "https://gdk.test:3443/api/v4/application/settings?top_level_group_creation_enabled=false"
  • Restart GDK
gdk restart 
  • Make an API request to create another top_level_group
curl -X POST --header "PRIVATE-TOKEN: <token>" "https://gdk.test:3443/api/v4/groups?name=top_level_group2&path=top_level_group2&visibility=public"
  • Verify that it returns a 403 => 'Forbidden' HTTP status code

Next Steps

  • Tag an SRE to disable the top_level_group_creation_enabled application_setting on Gitlab.com after merging
  • Create a feature-flag cleanup issue for :top_level_group_creation_enabled & link to the original issue #506673 (closed)

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.

Edited by Hakeem Abdul-Razak

Merge request reports

Loading