97 lines
3.3 KiB
Ruby
97 lines
3.3 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"
|
|
|
|
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)
|
|
|
|
logger.info(message: 'RecalculateVulnerabilitiesOccurrencesUuid Migration: recalculation is done for:',
|
|
finding_ids: mappings.keys.pluck(:id))
|
|
|
|
mark_job_as_succeeded(start_id, end_id)
|
|
rescue StandardError => error
|
|
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
|
|
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
|
|
|
|
def logger
|
|
@logger ||= Gitlab::BackgroundMigration::Logger.build
|
|
end
|
|
|
|
def mark_job_as_succeeded(*arguments)
|
|
Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
|
|
'RecalculateVulnerabilitiesOccurrencesUuid',
|
|
arguments
|
|
)
|
|
end
|
|
end
|