application_setting.rb 9.7 KB
Newer Older
1
class ApplicationSetting < ActiveRecord::Base
2
  include CacheMarkdownField
3
  include TokenAuthenticatable
4

5
  add_authentication_token_field :runners_registration_token
6
  add_authentication_token_field :health_check_access_token
7

D
Douwe Maan 已提交
8
  CACHE_KEY = 'application_setting.last'.freeze
9 10 11 12 13 14
  DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s*     # comma or semicolon, optionally surrounded by whitespace
                            |               # or
                            \s              # any whitespace character
                            |               # or
                            [\r\n]          # any number of newline characters
                          }x
15

16
  serialize :restricted_visibility_levels
17
  serialize :import_sources
18
  serialize :disabled_oauth_sign_in_sources, Array
19
  serialize :domain_whitelist, Array
20
  serialize :domain_blacklist, Array
21
  serialize :repository_storages
22
  serialize :sidekiq_throttling_queues, Array
23

24 25 26 27 28
  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

29
  attr_accessor :domain_whitelist_raw, :domain_blacklist_raw
30 31

  validates :session_expire_delay,
32 33
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }
34

35
  validates :home_page_url,
36 37 38
            allow_blank: true,
            url: true,
            if: :home_page_url_column_exist
39

40
  validates :after_sign_out_path,
41 42
            allow_blank: true,
            url: true
43

D
Douwe Maan 已提交
44
  validates :admin_notification_email,
45
            email: true,
46
            allow_blank: true
D
Douwe Maan 已提交
47

48
  validates :two_factor_grace_period,
49 50 51 52 53 54 55 56 57
            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
58

J
Jeroen Nijhof 已提交
59 60 61 62
  validates :sentry_dsn,
            presence: true,
            if: :sentry_enabled

63 64 65 66
  validates :akismet_api_key,
            presence: true,
            if: :akismet_enabled

67 68 69 70
  validates :koding_url,
            presence: true,
            if: :koding_enabled

71 72 73 74
  validates :plantuml_url,
            presence: true,
            if: :plantuml_enabled

75 76 77 78
  validates :max_attachment_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

79 80 81 82
  validates :max_artifacts_size,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

83
  validates :default_artifacts_expire_in, presence: true
84
  validate  :check_default_artifacts_expire_in
85

86 87 88 89
  validates :container_registry_token_expire_delay,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

90 91
  validates :repository_storages, presence: true
  validate :check_repository_storages
92

93
  validates :enabled_git_access_protocol,
94
            inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
95

96
  validates :domain_blacklist,
97
            presence: { message: 'Domain blacklist cannot be empty if Blacklist is enabled.' },
98 99
            if: :domain_blacklist_enabled?

100 101 102 103 104 105 106 107 108
  validates :sidekiq_throttling_factor,
            numericality: { greater_than: 0, less_than: 1 },
            presence: { message: 'Throttling factor cannot be empty if Sidekiq Throttling is enabled.' },
            if: :sidekiq_throttling_enabled?

  validates :sidekiq_throttling_queues,
            presence: { message: 'Queues to throttle cannot be empty if Sidekiq Throttling is enabled.' },
            if: :sidekiq_throttling_enabled?

J
Jacob Vosmaer 已提交
109 110 111 112 113 114 115 116 117 118 119 120
  validates :housekeeping_incremental_repack_period,
            presence: true,
            numericality: { only_integer: true, greater_than: 0 }

  validates :housekeeping_full_repack_period,
            presence: true,
            numericality: { only_integer: true, greater_than: :housekeeping_incremental_repack_period }

  validates :housekeeping_gc_period,
            presence: true,
            numericality: { only_integer: true, greater_than: :housekeeping_full_repack_period }

121 122 123 124
  validates :terminal_max_session_time,
            presence: true,
            numericality: { only_integer: true, greater_than_or_equal_to: 0 }

125
  validates_each :restricted_visibility_levels do |record, attr, value|
Z
Z.J. van de Weg 已提交
126 127 128
    value&.each do |level|
      unless Gitlab::VisibilityLevel.options.has_value?(level)
        record.errors.add(attr, "'#{level}' is not a valid visibility level")
129 130 131 132
      end
    end
  end

133
  validates_each :import_sources do |record, attr, value|
Z
Z.J. van de Weg 已提交
134 135 136
    value&.each do |source|
      unless Gitlab::ImportSources.options.has_value?(source)
        record.errors.add(attr, "'#{source}' is not a import source")
137 138 139 140
      end
    end
  end

141
  validates_each :disabled_oauth_sign_in_sources do |record, attr, value|
Z
Z.J. van de Weg 已提交
142 143 144
    value&.each do |source|
      unless Devise.omniauth_providers.include?(source.to_sym)
        record.errors.add(attr, "'#{source}' is not an OAuth sign-in source")
145 146 147 148
      end
    end
  end

149
  before_save :ensure_runners_registration_token
150
  before_save :ensure_health_check_access_token
151

152
  after_commit do
153
    Rails.cache.write(CACHE_KEY, self)
154 155
  end

156
  def self.current
157
    Rails.cache.fetch(CACHE_KEY) do
158 159
      ApplicationSetting.last
    end
160
  end
161

162
  def self.expire
163
    Rails.cache.delete(CACHE_KEY)
164 165
  rescue
    # Gracefully handle when Redis is not available. For example,
166
    # omnibus may fail here during gitlab:assets:compile.
167 168
  end

169 170 171 172
  def self.cached
    Rails.cache.fetch(CACHE_KEY)
  end

173 174 175 176 177
  def self.defaults_ce
    {
      after_sign_up_text: nil,
      akismet_enabled: false,
      container_registry_token_expire_delay: 5,
178
      default_artifacts_expire_in: '30 days',
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
      default_branch_protection: Settings.gitlab['default_branch_protection'],
      default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
      default_projects_limit: Settings.gitlab['default_projects_limit'],
      default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
      disabled_oauth_sign_in_sources: [],
      domain_whitelist: Settings.gitlab['domain_whitelist'],
      gravatar_enabled: Settings.gravatar['enabled'],
      help_page_text: nil,
      housekeeping_bitmaps_enabled: true,
      housekeeping_enabled: true,
      housekeeping_full_repack_period: 50,
      housekeeping_gc_period: 200,
      housekeeping_incremental_repack_period: 10,
      import_sources: Gitlab::ImportSources.values,
      koding_enabled: false,
      koding_url: nil,
      max_artifacts_size: Settings.artifacts['max_size'],
      max_attachment_size: Settings.gitlab['max_attachment_size'],
      plantuml_enabled: false,
      plantuml_url: nil,
      recaptcha_enabled: false,
      repository_checks_enabled: true,
      repository_storages: ['default'],
      require_two_factor_authentication: false,
      restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
      session_expire_delay: Settings.gitlab['session_expire_delay'],
      send_user_confirmation_email: false,
      shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
      shared_runners_text: nil,
      sidekiq_throttling_enabled: false,
      sign_in_text: nil,
      signin_enabled: Settings.gitlab['signin_enabled'],
      signup_enabled: Settings.gitlab['signup_enabled'],
212
      terminal_max_session_time: 0,
213
      two_factor_grace_period: 48,
214
      user_default_external: false
215 216 217 218 219 220 221
    }
  end

  def self.defaults
    defaults_ce
  end

222
  def self.create_from_defaults
223
    create(defaults)
224
  end
225

226 227 228 229 230 231 232 233
  def self.human_attribute_name(attr, _options = {})
    if attr == :default_artifacts_expire_in
      'Default artifacts expiration'
    else
      super
    end
  end

234 235 236
  def home_page_url_column_exist
    ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
  end
237

238 239 240 241
  def sidekiq_throttling_column_exists?
    ActiveRecord::Base.connection.column_exists?(:application_settings, :sidekiq_throttling_enabled)
  end

242
  def domain_whitelist_raw
Z
Z.J. van de Weg 已提交
243
    self.domain_whitelist&.join("\n")
244 245
  end

246
  def domain_blacklist_raw
Z
Z.J. van de Weg 已提交
247
    self.domain_blacklist&.join("\n")
248 249
  end

250 251 252 253 254
  def domain_whitelist_raw=(values)
    self.domain_whitelist = []
    self.domain_whitelist = values.split(DOMAIN_LIST_SEPARATOR)
    self.domain_whitelist.reject! { |d| d.empty? }
    self.domain_whitelist
255
  end
256

257 258
  def domain_blacklist_raw=(values)
    self.domain_blacklist = []
259
    self.domain_blacklist = values.split(DOMAIN_LIST_SEPARATOR)
260
    self.domain_blacklist.reject! { |d| d.empty? }
261
    self.domain_blacklist
262 263 264 265 266 267
  end

  def domain_blacklist_file=(file)
    self.domain_blacklist_raw = file.read
  end

268
  def repository_storages
269
    Array(read_attribute(:repository_storages))
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
  end

  # repository_storage is still required in the API. Remove in 9.0
  def repository_storage
    repository_storages.first
  end

  def repository_storage=(value)
    self.repository_storages = [value]
  end

  # Choose one of the available repository storage options. Currently all have
  # equal weighting.
  def pick_repository_storage
    repository_storages.sample
  end

287 288 289
  def runners_registration_token
    ensure_runners_registration_token!
  end
290 291 292 293

  def health_check_access_token
    ensure_health_check_access_token!
  end
294

295 296 297 298 299 300
  def sidekiq_throttling_enabled?
    return false unless sidekiq_throttling_column_exists?

    sidekiq_throttling_enabled
  end

301 302 303 304 305 306 307
  private

  def check_repository_storages
    invalid = repository_storages - Gitlab.config.repositories.storages.keys
    errors.add(:repository_storages, "can't include: #{invalid.join(", ")}") unless
      invalid.empty?
  end
308 309

  def check_default_artifacts_expire_in
310
    ChronicDuration.parse(default_artifacts_expire_in)
L
Lin Jen-Shin 已提交
311
  rescue ChronicDuration::DurationParseError
312
    errors.add(:default_artifacts_expire_in, "is not a correct duration")
313
  end
314
end