Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/application_setting.rb')
-rw-r--r--app/models/application_setting.rb586
1 files changed, 323 insertions, 263 deletions
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 98adbd3ab06..d2ca88aae0e 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -13,7 +13,8 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
ignore_column :user_email_lookup_limit, remove_with: '15.0', remove_after: '2022-04-18'
ignore_column :send_user_confirmation_email, remove_with: '15.8', remove_after: '2022-12-18'
ignore_column :web_ide_clientside_preview_enabled, remove_with: '15.11', remove_after: '2023-04-22'
- ignore_column :clickhouse_connection_string, remove_with: '15.11', remove_after: '2023-04-22'
+ ignore_column :clickhouse_connection_string, remove_with: '16.1', remove_after: '2023-05-22'
+ ignore_columns %i[instance_administration_project_id instance_administrators_group_id], remove_with: '16.2', remove_after: '2023-06-22'
INSTANCE_REVIEW_MIN_USERS = 50
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
@@ -22,21 +23,24 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
KROKI_URL_ERROR_MESSAGE = 'Please check your Kroki URL setting in ' \
'Admin Area > Settings > General > Kroki'
+ # Validate URIs in this model according to the current value of the `deny_all_requests_except_allowed` property,
+ # rather than the persisted value.
+ ADDRESSABLE_URL_VALIDATION_OPTIONS = { deny_all_requests_except_allowed: ->(settings) { settings.deny_all_requests_except_allowed } }.freeze
+
+ HUMANIZED_ATTRIBUTES = {
+ archive_builds_in_seconds: 'Archive job value'
+ }.freeze
+
enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true
- add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption) ? :optional : :required }
+ add_authentication_token_field :runners_registration_token, encrypted: :required
add_authentication_token_field :health_check_access_token
add_authentication_token_field :static_objects_external_storage_auth_token, encrypted: :required
add_authentication_token_field :error_tracking_access_token, encrypted: :required
- belongs_to :self_monitoring_project, class_name: "Project", foreign_key: 'instance_administration_project_id'
belongs_to :push_rule
- alias_attribute :self_monitoring_project_id, :instance_administration_project_id
- belongs_to :instance_group, class_name: "Group", foreign_key: 'instance_administrators_group_id'
- alias_attribute :instance_group_id, :instance_administrators_group_id
- alias_attribute :instance_administrators_group, :instance_group
alias_attribute :housekeeping_optimize_repository_period, :housekeeping_incremental_repack_period
sanitizes! :default_branch_name
@@ -90,336 +94,357 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
validates :grafana_url,
- system_hook_url: {
- blocked_message: "is blocked: %{exception_message}. #{GRAFANA_URL_ERROR_MESSAGE}"
- },
- if: :grafana_url_absolute?
+ system_hook_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({
+ blocked_message: "is blocked: %{exception_message}. #{GRAFANA_URL_ERROR_MESSAGE}"
+ }),
+ if: :grafana_url_absolute?
validate :validate_grafana_url
validates :uuid, presence: true
validates :outbound_local_requests_whitelist,
- length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') },
- allow_nil: false,
- qualified_domain_array: true
+ length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') },
+ allow_nil: false,
+ qualified_domain_array: true
validates :session_expire_delay,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :minimum_password_length,
- presence: true,
- numericality: { only_integer: true,
- greater_than_or_equal_to: DEFAULT_MINIMUM_PASSWORD_LENGTH,
- less_than_or_equal_to: Devise.password_length.max }
+ presence: true,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: DEFAULT_MINIMUM_PASSWORD_LENGTH,
+ less_than_or_equal_to: Devise.password_length.max
+ }
validates :home_page_url,
- allow_blank: true,
- addressable_url: true,
- if: :home_page_url_column_exists?
+ allow_blank: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
+ if: :home_page_url_column_exists?
validates :help_page_support_url,
- allow_blank: true,
- addressable_url: true,
- if: :help_page_support_url_column_exists?
+ allow_blank: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
+ if: :help_page_support_url_column_exists?
validates :help_page_documentation_base_url,
- length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") },
- allow_blank: true,
- addressable_url: true
+ length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") },
+ allow_blank: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
validates :after_sign_out_path,
- allow_blank: true,
- addressable_url: true
+ allow_blank: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
validates :abuse_notification_email,
- devise_email: true,
- allow_blank: true
+ devise_email: true,
+ allow_blank: true
validates :two_factor_grace_period,
- numericality: { greater_than_or_equal_to: 0 }
+ numericality: { greater_than_or_equal_to: 0 }
validates :recaptcha_site_key,
- presence: true,
- if: :recaptcha_or_login_protection_enabled
+ presence: true,
+ if: :recaptcha_or_login_protection_enabled
validates :recaptcha_private_key,
- presence: true,
- if: :recaptcha_or_login_protection_enabled
+ presence: true,
+ if: :recaptcha_or_login_protection_enabled
validates :akismet_api_key,
- presence: true,
- if: :akismet_enabled
+ presence: true,
+ if: :akismet_enabled
validates :spam_check_api_key,
- length: { maximum: 2000, message: N_('is too long (maximum is %{count} characters)') },
- allow_blank: true
+ length: { maximum: 2000, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true
validates :unique_ips_limit_per_user,
- numericality: { greater_than_or_equal_to: 1 },
- presence: true,
- if: :unique_ips_limit_enabled
+ numericality: { greater_than_or_equal_to: 1 },
+ presence: true,
+ if: :unique_ips_limit_enabled
validates :unique_ips_limit_time_window,
- numericality: { greater_than_or_equal_to: 0 },
- presence: true,
- if: :unique_ips_limit_enabled
+ numericality: { greater_than_or_equal_to: 0 },
+ presence: true,
+ if: :unique_ips_limit_enabled
- validates :kroki_url,
- presence: { if: :kroki_enabled }
+ validates :kroki_url, presence: { if: :kroki_enabled }
validate :validate_kroki_url, if: :kroki_enabled
validates :kroki_formats, json_schema: { filename: 'application_setting_kroki_formats' }
validates :metrics_method_call_threshold,
- numericality: { greater_than_or_equal_to: 0 },
- presence: true,
- if: :prometheus_metrics_enabled
+ numericality: { greater_than_or_equal_to: 0 },
+ presence: true,
+ if: :prometheus_metrics_enabled
- validates :plantuml_url,
- presence: true,
- if: :plantuml_enabled
+ validates :plantuml_url, presence: true, if: :plantuml_enabled
- validates :sourcegraph_url,
- presence: true,
- if: :sourcegraph_enabled
+ validates :sourcegraph_url, presence: true, if: :sourcegraph_enabled
validates :gitpod_url,
- presence: true,
- addressable_url: { enforce_sanitization: true },
- if: :gitpod_enabled
+ presence: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ enforce_sanitization: true }),
+ if: :gitpod_enabled
validates :mailgun_signing_key,
- presence: true,
- length: { maximum: 255 },
- if: :mailgun_events_enabled
+ presence: true,
+ length: { maximum: 255 },
+ if: :mailgun_events_enabled
validates :snowplow_collector_hostname,
- presence: true,
- hostname: true,
- if: :snowplow_enabled
+ presence: true,
+ hostname: true,
+ if: :snowplow_enabled
validates :max_attachment_size,
- presence: true,
- numericality: { only_integer: true, greater_than: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than: 0 }
validates :max_artifacts_size,
- presence: true,
- numericality: { only_integer: true, greater_than: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than: 0 }
validates :max_export_size,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :max_import_size,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :max_pages_size,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0,
- less_than: ::Gitlab::Pages::MAX_SIZE / 1.megabyte }
+ presence: true,
+ numericality: {
+ only_integer: true, greater_than_or_equal_to: 0,
+ less_than: ::Gitlab::Pages::MAX_SIZE / 1.megabyte
+ }
validates :max_pages_custom_domains_per_project,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :jobs_per_stage_page_size,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :max_terraform_state_size_bytes,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :default_artifacts_expire_in, presence: true, duration: true
validates :container_expiration_policies_enable_historic_entries,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :container_registry_token_expire_delay,
- presence: true,
- numericality: { only_integer: true, greater_than: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than: 0 }
validates :repository_storages, presence: true
validate :check_repository_storages
validate :check_repository_storages_weighted
validates :auto_devops_domain,
- allow_blank: true,
- hostname: { allow_numeric_hostname: true, require_valid_tld: true },
- if: :auto_devops_enabled?
+ allow_blank: true,
+ hostname: { allow_numeric_hostname: true, require_valid_tld: true },
+ if: :auto_devops_enabled?
validates :enabled_git_access_protocol,
- inclusion: { in: %w(ssh http), allow_blank: true }
+ inclusion: { in: %w(ssh http), allow_blank: true }
validates :domain_denylist,
- presence: { message: 'Domain denylist cannot be empty if denylist is enabled.' },
- if: :domain_denylist_enabled?
+ presence: { message: 'Domain denylist cannot be empty if denylist is enabled.' },
+ if: :domain_denylist_enabled?
validates :housekeeping_optimize_repository_period,
- presence: true,
- numericality: { only_integer: true, greater_than: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than: 0 }
validates :terminal_max_session_time,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :polling_interval_multiplier,
- presence: true,
- numericality: { greater_than_or_equal_to: 0 }
+ presence: true,
+ numericality: { greater_than_or_equal_to: 0 }
validates :gitaly_timeout_default,
- presence: true,
- if: :gitaly_timeout_default_changed?,
- numericality: {
- only_integer: true,
- greater_than_or_equal_to: 0,
- less_than_or_equal_to: Settings.gitlab.max_request_duration_seconds
- }
+ presence: true,
+ if: :gitaly_timeout_default_changed?,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: 0,
+ less_than_or_equal_to: Settings.gitlab.max_request_duration_seconds
+ }
validates :gitaly_timeout_medium,
- presence: true,
- if: :gitaly_timeout_medium_changed?,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ if: :gitaly_timeout_medium_changed?,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :gitaly_timeout_medium,
- numericality: { less_than_or_equal_to: :gitaly_timeout_default },
- if: :gitaly_timeout_default
+ numericality: { less_than_or_equal_to: :gitaly_timeout_default },
+ if: :gitaly_timeout_default
validates :gitaly_timeout_medium,
- numericality: { greater_than_or_equal_to: :gitaly_timeout_fast },
- if: :gitaly_timeout_fast
+ numericality: { greater_than_or_equal_to: :gitaly_timeout_fast },
+ if: :gitaly_timeout_fast
validates :gitaly_timeout_fast,
- presence: true,
- if: :gitaly_timeout_fast_changed?,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ presence: true,
+ if: :gitaly_timeout_fast_changed?,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :gitaly_timeout_fast,
- numericality: { less_than_or_equal_to: :gitaly_timeout_default },
- if: :gitaly_timeout_default
+ numericality: { less_than_or_equal_to: :gitaly_timeout_default },
+ if: :gitaly_timeout_default
validates :diff_max_patch_bytes,
- presence: true,
- numericality: { only_integer: true,
- greater_than_or_equal_to: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
- less_than_or_equal_to: Gitlab::Git::Diff::MAX_PATCH_BYTES_UPPER_BOUND }
+ presence: true,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
+ less_than_or_equal_to: Gitlab::Git::Diff::MAX_PATCH_BYTES_UPPER_BOUND
+ }
validates :diff_max_files,
- presence: true,
- numericality: { only_integer: true,
- greater_than_or_equal_to: Commit::DEFAULT_MAX_DIFF_FILES_SETTING,
- less_than_or_equal_to: Commit::MAX_DIFF_FILES_SETTING_UPPER_BOUND }
+ presence: true,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: Commit::DEFAULT_MAX_DIFF_FILES_SETTING,
+ less_than_or_equal_to: Commit::MAX_DIFF_FILES_SETTING_UPPER_BOUND
+ }
validates :diff_max_lines,
- presence: true,
- numericality: { only_integer: true,
- greater_than_or_equal_to: Commit::DEFAULT_MAX_DIFF_LINES_SETTING,
- less_than_or_equal_to: Commit::MAX_DIFF_LINES_SETTING_UPPER_BOUND }
+ presence: true,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: Commit::DEFAULT_MAX_DIFF_LINES_SETTING,
+ less_than_or_equal_to: Commit::MAX_DIFF_LINES_SETTING_UPPER_BOUND
+ }
validates :user_default_internal_regex, js_regex: true, allow_nil: true
validates :default_preferred_language, presence: true, inclusion: { in: Gitlab::I18n.available_locales }
validates :personal_access_token_prefix,
- format: { with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
- message: N_("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
- length: { maximum: 20, message: N_('is too long (maximum is %{count} characters)') },
- allow_blank: true
+ format: { with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
+ message: N_("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
+ length: { maximum: 20, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true
validates :commit_email_hostname, format: { with: /\A[^@]+\z/ }
validates :archive_builds_in_seconds,
- allow_nil: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 1.day.seconds }
+ allow_nil: true,
+ numericality: {
+ only_integer: true,
+ greater_than_or_equal_to: 1.day.seconds,
+ message: N_('must be at least 1 day')
+ }
validates :local_markdown_version,
- allow_nil: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 65536 }
+ allow_nil: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 65536 }
validates :asset_proxy_url,
- presence: true,
- allow_blank: false,
- url: true,
- if: :asset_proxy_enabled?
+ presence: true,
+ allow_blank: false,
+ url: true,
+ if: :asset_proxy_enabled?
validates :asset_proxy_secret_key,
- presence: true,
- allow_blank: false,
- if: :asset_proxy_enabled?
+ presence: true,
+ allow_blank: false,
+ if: :asset_proxy_enabled?
validates :static_objects_external_storage_url,
- addressable_url: true, allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true
validates :static_objects_external_storage_auth_token,
- presence: true,
- if: :static_objects_external_storage_url?
+ presence: true,
+ if: :static_objects_external_storage_url?
validates :protected_paths,
- length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
- allow_nil: false
+ length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
+ allow_nil: false
validates :push_event_hooks_limit,
- numericality: { greater_than_or_equal_to: 0 }
+ numericality: { greater_than_or_equal_to: 0 }
validates :push_event_activities_limit,
- numericality: { greater_than_or_equal_to: 0 }
+ numericality: { greater_than_or_equal_to: 0 }
validates :snippet_size_limit, numericality: { only_integer: true, greater_than: 0 }
validates :wiki_page_max_content_bytes, numericality: { only_integer: true, greater_than_or_equal_to: 1.kilobytes }
validates :max_yaml_size_bytes, numericality: { only_integer: true, greater_than: 0 }, presence: true
validates :max_yaml_depth, numericality: { only_integer: true, greater_than: 0 }, presence: true
+ validates :ci_max_includes, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, presence: true
+
validates :email_restrictions, untrusted_regexp: true
validates :hashed_storage_enabled, inclusion: { in: [true], message: N_("Hashed storage can't be disabled anymore for new projects") }
validates :container_registry_delete_tags_service_timeout,
- :container_registry_cleanup_tags_service_max_list_size,
- :container_registry_expiration_policies_worker_capacity,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ :container_registry_cleanup_tags_service_max_list_size,
+ :container_registry_expiration_policies_worker_capacity,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :container_registry_expiration_policies_caching,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :container_registry_import_max_tags_count,
- :container_registry_import_max_retries,
- :container_registry_import_start_max_retries,
- :container_registry_import_max_step_duration,
- :container_registry_pre_import_timeout,
- :container_registry_import_timeout,
- allow_nil: false,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ :container_registry_import_max_retries,
+ :container_registry_import_start_max_retries,
+ :container_registry_import_max_step_duration,
+ :container_registry_pre_import_timeout,
+ :container_registry_import_timeout,
+ allow_nil: false,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :container_registry_pre_import_tags_rate,
- allow_nil: false,
- numericality: { greater_than_or_equal_to: 0 }
+ allow_nil: false,
+ numericality: { greater_than_or_equal_to: 0 }
validates :container_registry_import_target_plan, presence: true
validates :container_registry_import_created_before, presence: true
validates :dependency_proxy_ttl_group_policy_worker_capacity,
- allow_nil: false,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ allow_nil: false,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :packages_cleanup_package_file_worker_capacity,
- :package_registry_cleanup_policies_worker_capacity,
- allow_nil: false,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ :package_registry_cleanup_policies_worker_capacity,
+ allow_nil: false,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :invisible_captcha_enabled,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :invitation_flow_enforcement, :can_create_group, :user_defaults_to_private_profile,
- allow_nil: false,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :deactivate_dormant_users_period,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 90, message: N_("'%{value}' days of inactivity must be greater than or equal to 90") },
- if: :deactivate_dormant_users?
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 90, message: N_("'%{value}' days of inactivity must be greater than or equal to 90") },
+ if: :deactivate_dormant_users?
validates :allow_possible_spam,
- allow_nil: false,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
+ validates :deny_all_requests_except_allowed,
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
+ validates :silent_mode_enabled,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
+ validates :remember_me_enabled,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
Gitlab::SSHPublicKey.supported_types.each do |type|
validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
@@ -448,93 +473,90 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validate :terms_exist, if: :enforce_terms?
validates :external_authorization_service_default_label,
- presence: true,
- if: :external_authorization_service_enabled
+ presence: true,
+ if: :external_authorization_service_enabled
validates :external_authorization_service_url,
- addressable_url: true, allow_blank: true,
- if: :external_authorization_service_enabled
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true,
+ if: :external_authorization_service_enabled
validates :external_authorization_service_timeout,
- numericality: { greater_than: 0, less_than_or_equal_to: 10 },
- if: :external_authorization_service_enabled
+ numericality: { greater_than: 0, less_than_or_equal_to: 10 },
+ if: :external_authorization_service_enabled
validates :spam_check_endpoint_url,
- addressable_url: { schemes: %w(tls grpc) }, allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ schemes: %w(tls grpc) }), allow_blank: true
validates :spam_check_endpoint_url,
- presence: true,
- if: :spam_check_endpoint_enabled
+ presence: true,
+ if: :spam_check_endpoint_enabled
validates :external_auth_client_key,
- presence: true,
- if: ->(setting) { setting.external_auth_client_cert.present? }
+ presence: true,
+ if: ->(setting) { setting.external_auth_client_cert.present? }
validates :lets_encrypt_notification_email,
- devise_email: true,
- format: { without: /@example\.(com|org|net)\z/,
- message: N_("Let's Encrypt does not accept emails on example.com") },
- allow_blank: true
+ devise_email: true,
+ format: { without: /@example\.(com|org|net)\z/, message: N_("Let's Encrypt does not accept emails on example.com") },
+ allow_blank: true
validates :lets_encrypt_notification_email,
- presence: true,
- if: :lets_encrypt_terms_of_service_accepted?
+ presence: true,
+ if: :lets_encrypt_terms_of_service_accepted?
validates :eks_integration_enabled,
- inclusion: { in: [true, false] }
+ inclusion: { in: [true, false] }
validates :eks_account_id,
- format: { with: Gitlab::Regex.aws_account_id_regex,
- message: Gitlab::Regex.aws_account_id_message },
- if: :eks_integration_enabled?
+ format: { with: Gitlab::Regex.aws_account_id_regex, message: Gitlab::Regex.aws_account_id_message },
+ if: :eks_integration_enabled?
validates :eks_access_key_id,
- length: { in: 16..128 },
- if: ->(setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
+ length: { in: 16..128 },
+ if: ->(setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
validates :eks_secret_access_key,
- presence: true,
- if: ->(setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
+ presence: true,
+ if: ->(setting) { setting.eks_integration_enabled? && setting.eks_access_key_id.present? }
validates_with X509CertificateCredentialsValidator,
- certificate: :external_auth_client_cert,
- pkey: :external_auth_client_key,
- pass: :external_auth_client_key_pass,
- if: ->(setting) { setting.external_auth_client_cert.present? }
+ certificate: :external_auth_client_cert,
+ pkey: :external_auth_client_key,
+ pass: :external_auth_client_key_pass,
+ if: ->(setting) { setting.external_auth_client_cert.present? }
validates :default_ci_config_path,
- format: { without: %r{(\.{2}|\A/)},
- message: N_('cannot include leading slash or directory traversal.') },
+ format: { without: %r{(\.{2}|\A/)}, message: N_('cannot include leading slash or directory traversal.') },
length: { maximum: 255 },
allow_blank: true
validates :issues_create_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :raw_blob_request_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :pipeline_limit_per_project_user_sha,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :ci_jwt_signing_key,
- rsa_key: true, allow_nil: true
+ rsa_key: true, allow_nil: true
validates :customers_dot_jwt_signing_key,
- rsa_key: true, allow_nil: true
+ rsa_key: true, allow_nil: true
validates :rate_limiting_response_text,
- length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
- allow_blank: true
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true
validates :jira_connect_application_key,
- length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
- allow_blank: true
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true
validates :jira_connect_proxy_url,
- length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
- allow_blank: true,
- public_url: true
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true,
+ public_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
with_options(presence: true, numericality: { only_integer: true, greater_than: 0 }) do
validates :throttle_unauthenticated_api_requests_per_period
@@ -563,54 +585,52 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :throttle_protected_paths_period_in_seconds
end
- validates :notes_create_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
-
- validates :search_rate_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
-
- validates :search_rate_limit_unauthenticated,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ with_options(numericality: { only_integer: true, greater_than_or_equal_to: 0 }) do
+ validates :notes_create_limit
+ validates :search_rate_limit
+ validates :search_rate_limit_unauthenticated
+ validates :projects_api_rate_limit_unauthenticated
+ end
validates :notes_create_limit_allowlist,
- length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
- allow_nil: false
+ length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
+ allow_nil: false
validates :admin_mode,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :external_pipeline_validation_service_url,
- addressable_url: true, allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true
validates :external_pipeline_validation_service_timeout,
- allow_nil: true,
- numericality: { only_integer: true, greater_than: 0 }
+ allow_nil: true,
+ numericality: { only_integer: true, greater_than: 0 }
validates :whats_new_variant,
- inclusion: { in: ApplicationSetting.whats_new_variants.keys }
+ inclusion: { in: ApplicationSetting.whats_new_variants.keys }
validates :floc_enabled,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
enum sidekiq_job_limiter_mode: {
- Gitlab::SidekiqMiddleware::SizeLimiter::Validator::TRACK_MODE => 0,
- Gitlab::SidekiqMiddleware::SizeLimiter::Validator::COMPRESS_MODE => 1 # The default
- }
+ Gitlab::SidekiqMiddleware::SizeLimiter::Validator::TRACK_MODE => 0,
+ Gitlab::SidekiqMiddleware::SizeLimiter::Validator::COMPRESS_MODE => 1 # The default
+ }
validates :sidekiq_job_limiter_mode,
- inclusion: { in: self.sidekiq_job_limiter_modes }
+ inclusion: { in: self.sidekiq_job_limiter_modes }
validates :sidekiq_job_limiter_compression_threshold_bytes,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :sidekiq_job_limiter_limit_bytes,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :sentry_enabled,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :sentry_dsn,
- addressable_url: true, presence: true, length: { maximum: 255 },
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, presence: true, length: { maximum: 255 },
if: :sentry_enabled?
validates :sentry_clientside_dsn,
- addressable_url: true, allow_blank: true, length: { maximum: 255 },
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true, length: { maximum: 255 },
if: :sentry_enabled?
validates :sentry_environment,
presence: true, length: { maximum: 255 },
@@ -620,32 +640,39 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :error_tracking_api_url,
presence: true,
- addressable_url: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
length: { maximum: 255 },
if: :error_tracking_enabled?
validates :users_get_by_id_limit,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :users_get_by_id_limit_allowlist,
- length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
- allow_nil: false
+ length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
+ allow_nil: false
- validates :public_runner_releases_url, addressable_url: true, presence: true
+ validates :update_runner_versions_enabled,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ validates :public_runner_releases_url,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
+ presence: true,
+ if: :update_runner_versions_enabled?
validates :inactive_projects_min_size_mb,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :inactive_projects_delete_after_months,
- numericality: { only_integer: true, greater_than: 0 }
+ numericality: { only_integer: true, greater_than: 0 }
validates :inactive_projects_send_warning_email_after_months,
- numericality: { only_integer: true, greater_than: 0, less_than: :inactive_projects_delete_after_months }
+ numericality: { only_integer: true, greater_than: 0, less_than: :inactive_projects_delete_after_months }
+
+ validates :database_apdex_settings, json_schema: { filename: 'application_setting_database_apdex_settings' }, allow_nil: true
attr_encrypted :asset_proxy_secret_key,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_truncated,
- algorithm: 'aes-256-cbc',
- insecure_mode: true
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-cbc',
+ insecure_mode: true
private_class_method def self.encryption_options_base_32_aes_256_gcm
{
@@ -683,24 +710,49 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
attr_encrypted :telesign_customer_xid, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :telesign_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :product_analytics_clickhouse_connection_string, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :product_analytics_configurator_connection_string, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :openai_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :anthropic_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ # TOFA API integration settngs
+ attr_encrypted :tofa_client_library_args, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_client_library_class, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_client_library_create_credentials_method, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_client_library_fetch_access_token_method, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_credentials, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_host, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_request_json_keys, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_request_payload, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_response_json_keys, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_url, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :tofa_access_token_expires_in, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
validates :disable_feed_token,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :disable_admin_oauth_scopes,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :bulk_import_enabled,
- allow_nil: false,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :allow_runner_registration_token,
- allow_nil: false,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
+ validates :default_syntax_highlighting_theme,
+ allow_nil: false,
+ numericality: { only_integer: true, greater_than: 0 },
+ inclusion: { in: Gitlab::ColorSchemes.valid_ids, message: N_('must be a valid syntax highlighting theme ID') }
+
+ validates :gitlab_dedicated_instance,
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
before_validation :ensure_uuid!
before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed?
before_validation :normalize_default_branch_name
+ before_validation :remove_old_import_sources
before_save :ensure_runners_registration_token
before_save :ensure_health_check_access_token
@@ -744,6 +796,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
users_count >= INSTANCE_REVIEW_MIN_USERS
end
+ def remove_old_import_sources
+ self.import_sources -= %w[phabricator gitlab] if self.import_sources
+ end
+
Recursion = Class.new(RuntimeError)
def self.create_from_defaults
@@ -824,6 +880,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
private
+ def self.human_attribute_name(attribute, *options)
+ HUMANIZED_ATTRIBUTES[attribute.to_sym] || super
+ end
+
def parsed_grafana_url
@parsed_grafana_url ||= Gitlab::Utils.parse_url(grafana_url)
end