summaryrefslogtreecommitdiff
path: root/app/models/concerns
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/concerns')
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage.rb19
-rw-r--r--app/models/concerns/atomic_internal_id.rb44
-rw-r--r--app/models/concerns/cacheable_attributes.rb2
-rw-r--r--app/models/concerns/can_move_repository_storage.rb21
-rw-r--r--app/models/concerns/enums/ci/pipeline.rb8
-rw-r--r--app/models/concerns/featurable.rb3
-rw-r--r--app/models/concerns/has_repository.rb9
-rw-r--r--app/models/concerns/nullify_if_blank.rb48
-rw-r--r--app/models/concerns/optimized_issuable_label_filter.rb4
-rw-r--r--app/models/concerns/packages/debian/architecture.rb6
-rw-r--r--app/models/concerns/packages/debian/component.rb31
-rw-r--r--app/models/concerns/packages/debian/component_file.rb101
-rw-r--r--app/models/concerns/packages/debian/distribution.rb10
-rw-r--r--app/models/concerns/protected_ref.rb16
-rw-r--r--app/models/concerns/repositories/can_housekeep_repository.rb4
-rw-r--r--app/models/concerns/repository_storage_movable.rb24
-rw-r--r--app/models/concerns/spammable.rb11
-rw-r--r--app/models/concerns/suppress_composite_primary_key_warning.rb19
-rw-r--r--app/models/concerns/token_authenticatable_strategies/encrypted.rb10
-rw-r--r--app/models/concerns/triggerable_hooks.rb3
20 files changed, 345 insertions, 48 deletions
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb
index f1c39dda49d..080ff07ec0c 100644
--- a/app/models/concerns/analytics/cycle_analytics/stage.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stage.rb
@@ -49,6 +49,14 @@ module Analytics
end
end
+ def start_event_identifier
+ backward_compatible_identifier(:start_event_identifier) || super
+ end
+
+ def end_event_identifier
+ backward_compatible_identifier(:end_event_identifier) || super
+ end
+
def start_event_label_based?
start_event_identifier && start_event.label_based?
end
@@ -128,6 +136,17 @@ module Analytics
.id_in(label_id)
.exists?
end
+
+ # Temporary, will be removed in 13.10
+ def backward_compatible_identifier(attribute_name)
+ removed_identifier = 6 # References IssueFirstMentionedInCommit removed on https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51975
+ replacement_identifier = :issue_first_mentioned_in_commit
+
+ # ActiveRecord returns nil if the column value is not part of the Enum definition
+ if self[attribute_name].nil? && read_attribute_before_type_cast(attribute_name) == removed_identifier
+ replacement_identifier
+ end
+ end
end
end
end
diff --git a/app/models/concerns/atomic_internal_id.rb b/app/models/concerns/atomic_internal_id.rb
index baa99fa5a7f..bbf9ecbcfe9 100644
--- a/app/models/concerns/atomic_internal_id.rb
+++ b/app/models/concerns/atomic_internal_id.rb
@@ -26,20 +26,31 @@
module AtomicInternalId
extend ActiveSupport::Concern
+ MissingValueError = Class.new(StandardError)
+
class_methods do
def has_internal_id( # rubocop:disable Naming/PredicateName
- column, scope:, init: :not_given, ensure_if: nil, track_if: nil,
- presence: true, backfill: false, hook_names: :create)
+ column, scope:, init: :not_given, ensure_if: nil, track_if: nil, presence: true, hook_names: :create)
raise "has_internal_id init must not be nil if given." if init.nil?
raise "has_internal_id needs to be defined on association." unless self.reflect_on_association(scope)
init = infer_init(scope) if init == :not_given
- before_validation :"track_#{scope}_#{column}!", on: hook_names, if: track_if
- before_validation :"ensure_#{scope}_#{column}!", on: hook_names, if: ensure_if
- validates column, presence: presence
+ callback_names = Array.wrap(hook_names).map { |hook_name| :"before_#{hook_name}" }
+ callback_names.each do |callback_name|
+ # rubocop:disable GitlabSecurity/PublicSend
+ public_send(callback_name, :"track_#{scope}_#{column}!", if: track_if)
+ public_send(callback_name, :"ensure_#{scope}_#{column}!", if: ensure_if)
+ # rubocop:enable GitlabSecurity/PublicSend
+ end
+ after_rollback :"clear_#{scope}_#{column}!", on: hook_names, if: ensure_if
+
+ if presence
+ before_create :"validate_#{column}_exists!"
+ before_update :"validate_#{column}_exists!"
+ end
define_singleton_internal_id_methods(scope, column, init)
- define_instance_internal_id_methods(scope, column, init, backfill)
+ define_instance_internal_id_methods(scope, column, init)
end
private
@@ -62,10 +73,8 @@ module AtomicInternalId
# - track_{scope}_{column}!
# - reset_{scope}_{column}
# - {column}=
- def define_instance_internal_id_methods(scope, column, init, backfill)
+ def define_instance_internal_id_methods(scope, column, init)
define_method("ensure_#{scope}_#{column}!") do
- return if backfill && self.class.where(column => nil).exists?
-
scope_value = internal_id_read_scope(scope)
value = read_attribute(column)
return value unless scope_value
@@ -79,6 +88,8 @@ module AtomicInternalId
internal_id_scope_usage,
init)
write_attribute(column, value)
+
+ @internal_id_set_manually = false
end
value
@@ -110,6 +121,7 @@ module AtomicInternalId
super(value).tap do |v|
# Indicate the iid was set from externally
@internal_id_needs_tracking = true
+ @internal_id_set_manually = true
end
end
@@ -128,6 +140,20 @@ module AtomicInternalId
read_attribute(column)
end
+
+ define_method("clear_#{scope}_#{column}!") do
+ return if @internal_id_set_manually
+
+ return unless public_send(:"#{column}_previously_changed?") # rubocop:disable GitlabSecurity/PublicSend
+
+ write_attribute(column, nil)
+ end
+
+ define_method("validate_#{column}_exists!") do
+ value = read_attribute(column)
+
+ raise MissingValueError, "#{column} was unexpectedly blank!" if value.blank?
+ end
end
# Defines class methods:
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
index de176ffde5c..ee56322cce7 100644
--- a/app/models/concerns/cacheable_attributes.rb
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -83,6 +83,6 @@ module CacheableAttributes
end
def cache!
- self.class.cache_backend.write(self.class.cache_key, self, expires_in: 1.minute)
+ self.class.cache_backend.write(self.class.cache_key, self, expires_in: Gitlab.config.gitlab['application_settings_cache_seconds'] || 60)
end
end
diff --git a/app/models/concerns/can_move_repository_storage.rb b/app/models/concerns/can_move_repository_storage.rb
index 52c3a4106e3..1132e4e79ac 100644
--- a/app/models/concerns/can_move_repository_storage.rb
+++ b/app/models/concerns/can_move_repository_storage.rb
@@ -16,10 +16,10 @@ module CanMoveRepositoryStorage
!skip_git_transfer_check && git_transfer_in_progress?
raise RepositoryReadOnlyError, _('Repository already read-only') if
- self.class.where(id: id).pick(:repository_read_only)
+ _safe_read_repository_read_only_column
raise ActiveRecord::RecordNotSaved, _('Database update failed') unless
- update_column(:repository_read_only, true)
+ _update_repository_read_only_column(true)
nil
end
@@ -30,7 +30,7 @@ module CanMoveRepositoryStorage
def set_repository_writable!
with_lock do
raise ActiveRecord::RecordNotSaved, _('Database update failed') unless
- update_column(:repository_read_only, false)
+ _update_repository_read_only_column(false)
nil
end
@@ -43,4 +43,19 @@ module CanMoveRepositoryStorage
def reference_counter(type:)
Gitlab::ReferenceCounter.new(type.identifier_for_container(self))
end
+
+ private
+
+ # Not all resources that can move repositories have the `repository_read_only`
+ # in their table, for example groups. We need these methods to override the
+ # behavior in those classes in order to access the column.
+ def _safe_read_repository_read_only_column
+ # This was added originally this way because of
+ # https://gitlab.com/gitlab-org/gitlab/-/commit/43f9b98302d3985312c9f8b66018e2835d8293d2
+ self.class.where(id: id).pick(:repository_read_only)
+ end
+
+ def _update_repository_read_only_column(value)
+ update_column(:repository_read_only, value)
+ end
end
diff --git a/app/models/concerns/enums/ci/pipeline.rb b/app/models/concerns/enums/ci/pipeline.rb
index e1f07fa162c..f8314d8b429 100644
--- a/app/models/concerns/enums/ci/pipeline.rb
+++ b/app/models/concerns/enums/ci/pipeline.rb
@@ -10,6 +10,9 @@ module Enums
unknown_failure: 0,
config_error: 1,
external_validation_failure: 2,
+ activity_limit_exceeded: 20,
+ size_limit_exceeded: 21,
+ job_activity_limit_exceeded: 22,
deployments_limit_exceeded: 23
}
end
@@ -71,11 +74,10 @@ module Enums
remote_source: 4,
external_project_source: 5,
bridge_source: 6,
- parameter_source: 7
+ parameter_source: 7,
+ compliance_source: 8
}
end
end
end
end
-
-Enums::Ci::Pipeline.prepend_if_ee('EE::Enums::Ci::Pipeline')
diff --git a/app/models/concerns/featurable.rb b/app/models/concerns/featurable.rb
index 20b72957ec2..ed9bce87da1 100644
--- a/app/models/concerns/featurable.rb
+++ b/app/models/concerns/featurable.rb
@@ -88,9 +88,6 @@ module Featurable
end
def feature_available?(feature, user)
- # This feature might not be behind a feature flag at all, so default to true
- return false unless ::Feature.enabled?(feature, user, default_enabled: true)
-
get_permission(user, feature)
end
diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb
index 9692941d8b2..b9ad78c14fd 100644
--- a/app/models/concerns/has_repository.rb
+++ b/app/models/concerns/has_repository.rb
@@ -15,15 +15,6 @@ module HasRepository
delegate :base_dir, :disk_path, to: :storage
- class_methods do
- def pick_repository_storage
- # We need to ensure application settings are fresh when we pick
- # a repository storage to use.
- Gitlab::CurrentSettings.expire_current_application_settings
- Gitlab::CurrentSettings.pick_repository_storage
- end
- end
-
def valid_repo?
repository.exists?
rescue
diff --git a/app/models/concerns/nullify_if_blank.rb b/app/models/concerns/nullify_if_blank.rb
new file mode 100644
index 00000000000..5a5cc51509b
--- /dev/null
+++ b/app/models/concerns/nullify_if_blank.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+# Helper that sets attributes to nil prior to validation if they
+# are blank (are false, empty or contain only whitespace), to avoid
+# unnecessarily persisting empty strings.
+#
+# Model usage:
+#
+# class User < ApplicationRecord
+# include NullifyIfBlank
+#
+# nullify_if_blank :name, :email
+# end
+#
+#
+# Test usage:
+#
+# RSpec.describe User do
+# it { is_expected.to nullify_if_blank(:name) }
+# it { is_expected.to nullify_if_blank(:email) }
+# end
+#
+module NullifyIfBlank
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def nullify_if_blank(*attributes)
+ self.attributes_to_nullify += attributes
+ end
+ end
+
+ included do
+ class_attribute :attributes_to_nullify,
+ instance_accessor: false,
+ instance_predicate: false,
+ default: Set.new
+
+ before_validation :nullify_blank_attributes
+ end
+
+ private
+
+ def nullify_blank_attributes
+ self.class.attributes_to_nullify.each do |attribute|
+ assign_attributes(attribute => nil) if read_attribute(attribute).blank?
+ end
+ end
+end
diff --git a/app/models/concerns/optimized_issuable_label_filter.rb b/app/models/concerns/optimized_issuable_label_filter.rb
index 82055822cfb..c7af841e450 100644
--- a/app/models/concerns/optimized_issuable_label_filter.rb
+++ b/app/models/concerns/optimized_issuable_label_filter.rb
@@ -13,7 +13,7 @@ module OptimizedIssuableLabelFilter
def by_label(items)
return items unless params.labels?
- return super if Feature.disabled?(:optimized_issuable_label_filter)
+ return super if Feature.disabled?(:optimized_issuable_label_filter, default_enabled: :yaml)
target_model = items.model
@@ -29,7 +29,7 @@ module OptimizedIssuableLabelFilter
# Taken from IssuableFinder
def count_by_state
return super if root_namespace.nil?
- return super if Feature.disabled?(:optimized_issuable_label_filter)
+ return super if Feature.disabled?(:optimized_issuable_label_filter, default_enabled: :yaml)
count_params = params.merge(state: nil, sort: nil, force_cte: true)
finder = self.class.new(current_user, count_params)
diff --git a/app/models/concerns/packages/debian/architecture.rb b/app/models/concerns/packages/debian/architecture.rb
index 4aa633e0357..760ebb49980 100644
--- a/app/models/concerns/packages/debian/architecture.rb
+++ b/app/models/concerns/packages/debian/architecture.rb
@@ -7,6 +7,12 @@ module Packages
included do
belongs_to :distribution, class_name: "Packages::Debian::#{container_type.capitalize}Distribution", inverse_of: :architectures
+ # files must be destroyed by ruby code in order to properly remove carrierwave uploads
+ has_many :files,
+ class_name: "Packages::Debian::#{container_type.capitalize}ComponentFile",
+ foreign_key: :architecture_id,
+ inverse_of: :architecture,
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
validates :distribution,
presence: true
diff --git a/app/models/concerns/packages/debian/component.rb b/app/models/concerns/packages/debian/component.rb
new file mode 100644
index 00000000000..7b342c7b684
--- /dev/null
+++ b/app/models/concerns/packages/debian/component.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Packages
+ module Debian
+ module Component
+ extend ActiveSupport::Concern
+
+ included do
+ belongs_to :distribution, class_name: "Packages::Debian::#{container_type.capitalize}Distribution", inverse_of: :components
+ # files must be destroyed by ruby code in order to properly remove carrierwave uploads
+ has_many :files,
+ class_name: "Packages::Debian::#{container_type.capitalize}ComponentFile",
+ foreign_key: :component_id,
+ inverse_of: :component,
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+
+ validates :distribution,
+ presence: true
+
+ validates :name,
+ presence: true,
+ length: { maximum: 255 },
+ uniqueness: { scope: %i[distribution_id] },
+ format: { with: Gitlab::Regex.debian_component_regex }
+
+ scope :with_distribution, ->(distribution) { where(distribution: distribution) }
+ scope :with_name, ->(name) { where(name: name) }
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/packages/debian/component_file.rb b/app/models/concerns/packages/debian/component_file.rb
new file mode 100644
index 00000000000..3cc2c291e96
--- /dev/null
+++ b/app/models/concerns/packages/debian/component_file.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Packages
+ module Debian
+ module ComponentFile
+ extend ActiveSupport::Concern
+
+ included do
+ include Sortable
+ include FileStoreMounter
+
+ def self.container_foreign_key
+ "#{container_type}_id".to_sym
+ end
+
+ def self.distribution_class
+ "::Packages::Debian::#{container_type.capitalize}Distribution".constantize
+ end
+
+ belongs_to :component, class_name: "Packages::Debian::#{container_type.capitalize}Component", inverse_of: :files
+ belongs_to :architecture, class_name: "Packages::Debian::#{container_type.capitalize}Architecture", inverse_of: :files, optional: true
+
+ enum file_type: { packages: 1, source: 2, di_packages: 3 }
+ enum compression_type: { gz: 1, bz2: 2, xz: 3 }
+
+ validates :component, presence: true
+ validates :file_type, presence: true
+ validates :architecture, presence: true, unless: :source?
+ validates :architecture, absence: true, if: :source?
+ validates :file, length: { minimum: 0, allow_nil: false }
+ validates :size, presence: true
+ validates :file_store, presence: true
+ validates :file_md5, presence: true
+ validates :file_sha256, presence: true
+
+ scope :with_container, ->(container) do
+ joins(component: :distribution)
+ .where("packages_debian_#{container_type}_distributions" => { container_foreign_key => container.id })
+ end
+
+ scope :with_codename_or_suite, ->(codename_or_suite) do
+ joins(component: :distribution)
+ .merge(distribution_class.with_codename_or_suite(codename_or_suite))
+ end
+
+ scope :with_component_name, ->(component_name) do
+ joins(:component)
+ .where("packages_debian_#{container_type}_components" => { name: component_name })
+ end
+
+ scope :with_file_type, ->(file_type) { where(file_type: file_type) }
+
+ scope :with_architecture_name, ->(architecture_name) do
+ left_outer_joins(:architecture)
+ .where("packages_debian_#{container_type}_architectures" => { name: architecture_name })
+ end
+
+ scope :with_compression_type, ->(compression_type) { where(compression_type: compression_type) }
+ scope :with_file_sha256, ->(file_sha256) { where(file_sha256: file_sha256) }
+
+ scope :preload_distribution, -> { includes(component: :distribution) }
+
+ mount_file_store_uploader Packages::Debian::ComponentFileUploader
+
+ before_validation :update_size_from_file
+
+ def file_name
+ case file_type
+ when 'di_packages'
+ 'Packages'
+ else
+ file_type.capitalize
+ end
+ end
+
+ def relative_path
+ case file_type
+ when 'packages'
+ "#{component.name}/binary-#{architecture.name}/#{file_name}#{extension}"
+ when 'source'
+ "#{component.name}/source/#{file_name}#{extension}"
+ when 'di_packages'
+ "#{component.name}/debian-installer/binary-#{architecture.name}/#{file_name}#{extension}"
+ end
+ end
+
+ private
+
+ def extension
+ return '' unless compression_type
+
+ ".#{compression_type}"
+ end
+
+ def update_size_from_file
+ self.size ||= file.size
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/packages/debian/distribution.rb b/app/models/concerns/packages/debian/distribution.rb
index 285d293c9ee..08fb9ccf3ea 100644
--- a/app/models/concerns/packages/debian/distribution.rb
+++ b/app/models/concerns/packages/debian/distribution.rb
@@ -18,6 +18,16 @@ module Packages
belongs_to container_type
belongs_to :creator, class_name: 'User'
+ # component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
+ has_many :components,
+ class_name: "Packages::Debian::#{container_type.capitalize}Component",
+ foreign_key: :distribution_id,
+ inverse_of: :distribution,
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :component_files,
+ through: :components,
+ source: :files,
+ class_name: "Packages::Debian::#{container_type.capitalize}ComponentFile"
has_many :architectures,
class_name: "Packages::Debian::#{container_type.capitalize}Architecture",
foreign_key: :distribution_id,
diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb
index 65195a8d5aa..cf23a27244c 100644
--- a/app/models/concerns/protected_ref.rb
+++ b/app/models/concerns/protected_ref.rb
@@ -40,20 +40,26 @@ module ProtectedRef
end
def protected_ref_accessible_to?(ref, user, project:, action:, protected_refs: nil)
- access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level|
+ all_matching_rules_allow?(ref, action: action, protected_refs: protected_refs) do |access_level|
access_level.check_access(user)
end
end
def developers_can?(action, ref, protected_refs: nil)
- access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level|
+ all_matching_rules_allow?(ref, action: action, protected_refs: protected_refs) do |access_level|
access_level.access_level == Gitlab::Access::DEVELOPER
end
end
- def access_levels_for_ref(ref, action:, protected_refs: nil)
- self.matching(ref, protected_refs: protected_refs)
- .flat_map(&:"#{action}_access_levels")
+ def all_matching_rules_allow?(ref, action:, protected_refs: nil, &block)
+ access_levels_groups =
+ self.matching(ref, protected_refs: protected_refs).map(&:"#{action}_access_levels")
+
+ return false if access_levels_groups.blank?
+
+ access_levels_groups.all? do |access_levels|
+ access_levels.any?(&block)
+ end
end
# Returns all protected refs that match the given ref name.
diff --git a/app/models/concerns/repositories/can_housekeep_repository.rb b/app/models/concerns/repositories/can_housekeep_repository.rb
index 2b79851a07c..946f82c5f36 100644
--- a/app/models/concerns/repositories/can_housekeep_repository.rb
+++ b/app/models/concerns/repositories/can_housekeep_repository.rb
@@ -16,6 +16,10 @@ module Repositories
Gitlab::Redis::SharedState.with { |redis| redis.del(pushes_since_gc_redis_shared_state_key) }
end
+ def git_garbage_collect_worker_klass
+ raise NotImplementedError
+ end
+
private
def pushes_since_gc_redis_shared_state_key
diff --git a/app/models/concerns/repository_storage_movable.rb b/app/models/concerns/repository_storage_movable.rb
index a45b4626628..8607f0d94f4 100644
--- a/app/models/concerns/repository_storage_movable.rb
+++ b/app/models/concerns/repository_storage_movable.rb
@@ -20,7 +20,7 @@ module RepositoryStorageMovable
validate :container_repository_writable, on: :create
default_value_for(:destination_storage_name, allows_nil: false) do
- pick_repository_storage
+ Repository.pick_storage_shard
end
state_machine initial: :initial do
@@ -68,6 +68,18 @@ module RepositoryStorageMovable
storage_move.update_repository_storage(storage_move.destination_storage_name)
end
+ after_transition started: :replicated do |storage_move|
+ # We have several scripts in place that replicate some statistics information
+ # to other databases. Some of them depend on the updated_at column
+ # to identify the models they need to extract.
+ #
+ # If we don't update the `updated_at` of the container after a repository storage move,
+ # the scripts won't know that they need to sync them.
+ #
+ # See https://gitlab.com/gitlab-data/analytics/-/issues/7868
+ storage_move.container.touch
+ end
+
before_transition started: :failed do |storage_move|
storage_move.container.set_repository_writable!
end
@@ -82,16 +94,6 @@ module RepositoryStorageMovable
end
end
- class_methods do
- private
-
- def pick_repository_storage
- container_klass = reflect_on_association(:container).class_name.constantize
-
- container_klass.pick_repository_storage
- end
- end
-
# Projects, snippets, and group wikis has different db structure. In projects,
# we need to update some columns in this step, but we don't with the other resources.
#
diff --git a/app/models/concerns/spammable.rb b/app/models/concerns/spammable.rb
index 9cd1a22b203..2daea388939 100644
--- a/app/models/concerns/spammable.rb
+++ b/app/models/concerns/spammable.rb
@@ -45,6 +45,17 @@ module Spammable
self.needs_recaptcha = true
end
+ ##
+ # Indicates if a recaptcha should be rendered before allowing this model to be saved.
+ #
+ def render_recaptcha?
+ return false unless Gitlab::Recaptcha.enabled?
+
+ return false if self.errors.count > 1 # captcha should not be rendered if are still other errors
+
+ self.needs_recaptcha?
+ end
+
def spam!
self.spam = true
end
diff --git a/app/models/concerns/suppress_composite_primary_key_warning.rb b/app/models/concerns/suppress_composite_primary_key_warning.rb
new file mode 100644
index 00000000000..32634e7bc72
--- /dev/null
+++ b/app/models/concerns/suppress_composite_primary_key_warning.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+# When extended, silences this warning below:
+# WARNING: Active Record does not support composite primary key.
+#
+# project_authorizations has composite primary key. Composite primary key is ignored.
+#
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/292909
+module SuppressCompositePrimaryKeyWarning
+ extend ActiveSupport::Concern
+
+ private
+
+ def suppress_composite_primary_key(pk)
+ silence_warnings do
+ super
+ end
+ end
+end
diff --git a/app/models/concerns/token_authenticatable_strategies/encrypted.rb b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
index 4728cb658dc..672402ee4d6 100644
--- a/app/models/concerns/token_authenticatable_strategies/encrypted.rb
+++ b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
@@ -85,10 +85,18 @@ module TokenAuthenticatableStrategies
end
def find_by_encrypted_token(token, unscoped)
- encrypted_value = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
+ nonce = Feature.enabled?(:dynamic_nonce_creation) ? find_hashed_iv(token) : Gitlab::CryptoHelper::AES256_GCM_IV_STATIC
+ encrypted_value = Gitlab::CryptoHelper.aes256_gcm_encrypt(token, nonce: nonce)
+
relation(unscoped).find_by(encrypted_field => encrypted_value)
end
+ def find_hashed_iv(token)
+ token_record = TokenWithIv.find_by_plaintext_token(token)
+
+ token_record&.iv || Gitlab::CryptoHelper::AES256_GCM_IV_STATIC
+ end
+
def insecure_strategy
@insecure_strategy ||= TokenAuthenticatableStrategies::Insecure
.new(klass, token_field, options)
diff --git a/app/models/concerns/triggerable_hooks.rb b/app/models/concerns/triggerable_hooks.rb
index 473b430bb04..db5df6c2c9f 100644
--- a/app/models/concerns/triggerable_hooks.rb
+++ b/app/models/concerns/triggerable_hooks.rb
@@ -16,7 +16,8 @@ module TriggerableHooks
deployment_hooks: :deployment_events,
feature_flag_hooks: :feature_flag_events,
release_hooks: :releases_events,
- member_hooks: :member_events
+ member_hooks: :member_events,
+ subgroup_hooks: :subgroup_events
}.freeze
extend ActiveSupport::Concern