application_setting.rb 9.42 KB
Newer Older
1 2
# frozen_string_literal: true

3
class ApplicationSetting < ApplicationRecord
4
  include CacheableAttributes
5
  include CacheMarkdownField
6
  include TokenAuthenticatable
7
  include IgnorableColumn
8
  include ChronicDurationAttribute
9

10
  add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption, default_enabled: true) ? :optional : :required }
11
  add_authentication_token_field :health_check_access_token
12

13 14 15 16 17 18
  # Include here so it can override methods from
  # `add_authentication_token_field`
  # We don't prepend for now because otherwise we'll need to
  # fix a lot of tests using allow_any_instance_of
  include ApplicationSettingImplementation

19 20 21 22 23 24
  serialize :restricted_visibility_levels # rubocop:disable Cop/ActiveRecordSerialize
  serialize :import_sources # rubocop:disable Cop/ActiveRecordSerialize
  serialize :disabled_oauth_sign_in_sources, Array # rubocop:disable Cop/ActiveRecordSerialize
  serialize :domain_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize
  serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize
  serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
25

26 27 28 29 30
  ignore_column :circuitbreaker_failure_count_threshold
  ignore_column :circuitbreaker_failure_reset_time
  ignore_column :circuitbreaker_storage_timeout
  ignore_column :circuitbreaker_access_retries
  ignore_column :circuitbreaker_check_interval
31 32
  ignore_column :koding_url
  ignore_column :koding_enabled
33

34 35 36 37 38
  cache_markdown_field :sign_in_text
  cache_markdown_field :help_page_text
  cache_markdown_field :shared_runners_text, pipeline: :plain_markdown
  cache_markdown_field :after_sign_up_text

39 40
  default_value_for :id, 1

41 42
  chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds

43 44
  validates :uuid, presence: true

45
  validates :session_expire_delay,
46 47
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
48

49
  validates :home_page_url,
50 51
            allow_blank: true,
            url: true,
52 53 54 55 56 57
            if: :home_page_url_column_exists?

  validates :help_page_support_url,
            allow_blank: true,
            url: true,
            if: :help_page_support_url_column_exists?
58

59
  validates :after_sign_out_path,
60 61
            allow_blank: true,
            url: true
62

63
  validates :admin_notification_email,
64
            devise_email: true,
65
            allow_blank: true
66

67
  validates :two_factor_grace_period,
68 69 70 71 72 73 74 75 76
            numericality: { greater_than_or_equal_to: 0 }

  validates :recaptcha_site_key,
            presence: true,
            if: :recaptcha_enabled

  validates :recaptcha_private_key,
            presence: true,
            if: :recaptcha_enabled
77

Jeroen Nijhof's avatar
Jeroen Nijhof committed
78 79 80 81
  validates :sentry_dsn,
            presence: true,
            if: :sentry_enabled

82 83 84 85
  validates :clientside_sentry_dsn,
            presence: true,
            if: :clientside_sentry_enabled

86 87 88 89
  validates :akismet_api_key,
            presence: true,
            if: :akismet_enabled

90 91 92 93 94 95 96 97 98 99
  validates :unique_ips_limit_per_user,
            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

100 101 102 103
  validates :plantuml_url,
            presence: true,
            if: :plantuml_enabled

104 105 106 107
  validates :max_attachment_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

108 109 110 111
  validates :max_artifacts_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

112
  validates :default_artifacts_expire_in, presence: true, duration: true
113

114 115 116 117
  validates :container_registry_token_expire_delay,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

118 119
  validates :repository_storages, presence: true
  validate :check_repository_storages
120

121 122 123 124 125
  validates :auto_devops_domain,
            allow_blank: true,
            hostname: { allow_numeric_hostname: true, require_valid_tld: true },
            if: :auto_devops_enabled?

126
  validates :enabled_git_access_protocol,
127
            inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
128

129
  validates :domain_blacklist,
130
            presence: { message: 'Domain blacklist cannot be empty if Blacklist is enabled.' },
131 132
            if: :domain_blacklist_enabled?

133 134 135 136 137 138
  validates :housekeeping_incremental_repack_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :housekeeping_full_repack_period,
            presence: true,
139
            numericality: { only_integer: true, greater_than_or_equal_to: :housekeeping_incremental_repack_period }
140 141 142

  validates :housekeeping_gc_period,
            presence: true,
143
            numericality: { only_integer: true, greater_than_or_equal_to: :housekeeping_full_repack_period }
144

145 146 147 148
  validates :terminal_max_session_time,
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

149 150 151 152
  validates :polling_interval_multiplier,
            presence: true,
            numericality: { greater_than_or_equal_to: 0 }

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  validates :gitaly_timeout_default,
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

  validates :gitaly_timeout_medium,
            presence: true,
            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
  validates :gitaly_timeout_medium,
            numericality: { greater_than_or_equal_to: :gitaly_timeout_fast },
            if: :gitaly_timeout_fast

  validates :gitaly_timeout_fast,
            presence: true,
            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

174 175 176 177 178 179
  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 }

180 181
  validates :user_default_internal_regex, js_regex: true, allow_nil: true

182 183
  validates :commit_email_hostname, format: { with: /\A[^@]+\z/ }

184 185 186 187
  validates :archive_builds_in_seconds,
            allow_nil: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 1.day.seconds }

188 189 190 191
  validates :local_markdown_version,
            allow_nil: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 65536 }

192
  SUPPORTED_KEY_TYPES.each do |type|
193
    validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
194
  end
195

Nick Thomas's avatar
Nick Thomas committed
196 197
  validates :allowed_key_types, presence: true

198
  validates_each :restricted_visibility_levels do |record, attr, value|
199
    value&.each do |level|
200
      unless Gitlab::VisibilityLevel.options.value?(level)
201
        record.errors.add(attr, "'#{level}' is not a valid visibility level")
202 203 204 205
      end
    end
  end

206
  validates_each :import_sources do |record, attr, value|
207
    value&.each do |source|
208
      unless Gitlab::ImportSources.options.value?(source)
209
        record.errors.add(attr, "'#{source}' is not a import source")
210 211 212 213
      end
    end
  end

214 215
  validate :terms_exist, if: :enforce_terms?

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  validates :external_authorization_service_default_label,
            presence: true,
            if: :external_authorization_service_enabled

  validates :external_authorization_service_url,
            url: true, 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

  validates :external_auth_client_key,
            presence: true,
            if: -> (setting) { setting.external_auth_client_cert.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? }

  attr_encrypted :external_auth_client_key,
                 mode: :per_attribute_iv,
                 key: Settings.attr_encrypted_db_key_base_truncated,
                 algorithm: 'aes-256-gcm',
                 encode: true

  attr_encrypted :external_auth_client_key_pass,
                 mode: :per_attribute_iv,
                 key: Settings.attr_encrypted_db_key_base_truncated,
                 algorithm: 'aes-256-gcm',
                 encode: true

250
  before_validation :ensure_uuid!
251
  before_validation :strip_sentry_values
252

253
  before_save :ensure_runners_registration_token
254
  before_save :ensure_health_check_access_token
255

256
  after_commit do
257
    reset_memoized_terms
258
  end
259
  after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> { previous_changes.key?('performance_bar_allowed_group_id') }
260 261 262 263 264 265 266

  def self.create_from_defaults
    super
  rescue ActiveRecord::RecordNotUnique
    # We already have an ApplicationSetting record, so just return it.
    current_without_cache
  end
267
end