Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb')
-rw-r--r--lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb124
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb b/lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb
new file mode 100644
index 00000000000..2b049ea2d2f
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require 'parser/ruby27'
+
+module Gitlab
+ module BackgroundMigration
+ # This migration fixes raw_metadata entries which have incorrectly been passed a Ruby Hash instead of JSON data.
+ class FixVulnerabilityOccurrencesWithHashesAsRawMetadata
+ CLUSTER_IMAGE_SCANNING_REPORT_TYPE = 7
+ GENERIC_REPORT_TYPE = 99
+
+ # Type error is used to handle unexpected types when parsing stringified hashes.
+ class TypeError < ::StandardError
+ attr_reader :message, :type
+
+ def initialize(message, type)
+ @message = message
+ @type = type
+ end
+ end
+
+ # Migration model namespace isolated from application code.
+ class Finding < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'vulnerability_occurrences'
+
+ scope :by_api_report_types, -> { where(report_type: [CLUSTER_IMAGE_SCANNING_REPORT_TYPE, GENERIC_REPORT_TYPE]) }
+ end
+
+ def perform(start_id, end_id)
+ Finding.by_api_report_types.where(id: start_id..end_id).each do |finding|
+ next if valid_json?(finding.raw_metadata)
+
+ metadata = hash_from_s(finding.raw_metadata)
+
+ finding.update(raw_metadata: metadata.to_json) if metadata
+ end
+ mark_job_as_succeeded(start_id, end_id)
+ end
+
+ def hash_from_s(str_hash)
+ ast = Parser::Ruby27.parse(str_hash)
+
+ unless ast.type == :hash
+ ::Gitlab::AppLogger.error(message: "expected raw_metadata to be a hash", type: ast.type)
+ return
+ end
+
+ parse_hash(ast)
+ rescue Parser::SyntaxError => e
+ ::Gitlab::AppLogger.error(message: "error parsing raw_metadata", error: e.message)
+ nil
+ rescue TypeError => e
+ ::Gitlab::AppLogger.error(message: "error parsing raw_metadata", error: e.message, type: e.type)
+ nil
+ end
+
+ private
+
+ def mark_job_as_succeeded(*arguments)
+ Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
+ 'FixVulnerabilityOccurrencesWithHashesAsRawMetadata',
+ arguments
+ )
+ end
+
+ def valid_json?(metadata)
+ Oj.load(metadata)
+ true
+ rescue Oj::ParseError, Encoding::UndefinedConversionError
+ false
+ end
+
+ def parse_hash(hash)
+ out = {}
+ hash.children.each do |node|
+ unless node.type == :pair
+ raise TypeError.new("expected child of hash to be a `pair`", node.type)
+ end
+
+ key, value = node.children
+
+ key = parse_key(key)
+ value = parse_value(value)
+
+ out[key] = value
+ end
+
+ out
+ end
+
+ def parse_key(key)
+ case key.type
+ when :sym, :str, :int
+ key.children.first
+ else
+ raise TypeError.new("expected key to be either symbol, string, or integer", key.type)
+ end
+ end
+
+ def parse_value(value)
+ case value.type
+ when :sym, :str, :int
+ value.children.first
+ # rubocop:disable Lint/BooleanSymbol
+ when :true
+ true
+ when :false
+ false
+ # rubocop:enable Lint/BooleanSymbol
+ when :nil
+ nil
+ when :array
+ value.children.map { |c| parse_value(c) }
+ when :hash
+ parse_hash(value)
+ else
+ raise TypeError.new("value of a pair was an unexpected type", value.type)
+ end
+ end
+ end
+ end
+end