80 lines
2.7 KiB
Ruby
80 lines
2.7 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
# rubocop: disable Style/Documentation
|
||
|
class Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid
|
||
|
# rubocop: disable Gitlab/NamespacedClass
|
||
|
class VulnerabilitiesIdentifier < ActiveRecord::Base
|
||
|
self.table_name = "vulnerability_identifiers"
|
||
|
has_many :primary_findings, class_name: 'VulnerabilitiesFinding', inverse_of: :primary_identifier, foreign_key: 'primary_identifier_id'
|
||
|
end
|
||
|
|
||
|
class VulnerabilitiesFinding < ActiveRecord::Base
|
||
|
self.table_name = "vulnerability_occurrences"
|
||
|
belongs_to :primary_identifier, class_name: 'VulnerabilitiesIdentifier', inverse_of: :primary_findings, foreign_key: 'primary_identifier_id'
|
||
|
REPORT_TYPES = {
|
||
|
sast: 0,
|
||
|
dependency_scanning: 1,
|
||
|
container_scanning: 2,
|
||
|
dast: 3,
|
||
|
secret_detection: 4,
|
||
|
coverage_fuzzing: 5,
|
||
|
api_fuzzing: 6
|
||
|
}.with_indifferent_access.freeze
|
||
|
enum report_type: REPORT_TYPES
|
||
|
end
|
||
|
|
||
|
class CalculateFindingUUID
|
||
|
FINDING_NAMESPACES_IDS = {
|
||
|
development: "a143e9e2-41b3-47bc-9a19-081d089229f4",
|
||
|
test: "a143e9e2-41b3-47bc-9a19-081d089229f4",
|
||
|
staging: "a6930898-a1b2-4365-ab18-12aa474d9b26",
|
||
|
production: "58dc0f06-936c-43b3-93bb-71693f1b6570"
|
||
|
}.freeze
|
||
|
|
||
|
NAMESPACE_REGEX = /(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})/.freeze
|
||
|
PACK_PATTERN = "NnnnnN".freeze
|
||
|
|
||
|
def self.call(value)
|
||
|
Digest::UUID.uuid_v5(namespace_id, value)
|
||
|
end
|
||
|
|
||
|
def self.namespace_id
|
||
|
namespace_uuid = FINDING_NAMESPACES_IDS.fetch(Rails.env.to_sym)
|
||
|
# Digest::UUID is broken when using an UUID in namespace_id
|
||
|
# https://github.com/rails/rails/issues/37681#issue-520718028
|
||
|
namespace_uuid.scan(NAMESPACE_REGEX).flatten.map { |s| s.to_i(16) }.pack(PACK_PATTERN)
|
||
|
end
|
||
|
end
|
||
|
# rubocop: enable Gitlab/NamespacedClass
|
||
|
|
||
|
def perform(start_id, end_id)
|
||
|
findings = VulnerabilitiesFinding
|
||
|
.joins(:primary_identifier)
|
||
|
.select(:id, :report_type, :fingerprint, :location_fingerprint, :project_id)
|
||
|
.where(id: start_id..end_id)
|
||
|
|
||
|
mappings = findings.each_with_object({}) do |finding, hash|
|
||
|
hash[finding] = { uuid: calculate_uuid_v5_for_finding(finding) }
|
||
|
end
|
||
|
|
||
|
::Gitlab::Database::BulkUpdate.execute(%i[uuid], mappings)
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def calculate_uuid_v5_for_finding(vulnerability_finding)
|
||
|
return unless vulnerability_finding
|
||
|
|
||
|
uuid_v5_name_components = {
|
||
|
report_type: vulnerability_finding.report_type,
|
||
|
primary_identifier_fingerprint: vulnerability_finding.fingerprint,
|
||
|
location_fingerprint: vulnerability_finding.location_fingerprint,
|
||
|
project_id: vulnerability_finding.project_id
|
||
|
}
|
||
|
|
||
|
name = uuid_v5_name_components.values.join('-')
|
||
|
|
||
|
CalculateFindingUUID.call(name)
|
||
|
end
|
||
|
end
|