diff options
Diffstat (limited to 'lib/gitlab/config/loader/multi_doc_yaml.rb')
-rw-r--r-- | lib/gitlab/config/loader/multi_doc_yaml.rb | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/lib/gitlab/config/loader/multi_doc_yaml.rb b/lib/gitlab/config/loader/multi_doc_yaml.rb new file mode 100644 index 00000000000..346adc79896 --- /dev/null +++ b/lib/gitlab/config/loader/multi_doc_yaml.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Gitlab + module Config + module Loader + class MultiDocYaml + TooManyDocumentsError = Class.new(Loader::FormatError) + DataTooLargeError = Class.new(Loader::FormatError) + NotHashError = Class.new(Loader::FormatError) + + MULTI_DOC_DIVIDER = /^---$/.freeze + + def initialize(config, max_documents:, additional_permitted_classes: []) + @max_documents = max_documents + @safe_config = load_config(config, additional_permitted_classes) + end + + def load! + raise TooManyDocumentsError, 'The parsed YAML has too many documents' if too_many_documents? + raise DataTooLargeError, 'The parsed YAML is too big' if too_big? + raise NotHashError, 'Invalid configuration format' unless all_hashes? + + safe_config.map(&:deep_symbolize_keys) + end + + private + + attr_reader :safe_config, :max_documents + + def load_config(config, additional_permitted_classes) + config.split(MULTI_DOC_DIVIDER).filter_map do |document| + YAML.safe_load(document, + permitted_classes: [Symbol, *additional_permitted_classes], + permitted_symbols: [], + aliases: true + ) + end + rescue Psych::Exception => e + raise Loader::FormatError, e.message + end + + def all_hashes? + safe_config.all?(Hash) + end + + def too_many_documents? + safe_config.count > max_documents + end + + def too_big? + !deep_sizes.all?(&:valid?) + end + + def deep_sizes + safe_config.map do |config| + Gitlab::Utils::DeepSize.new(config, + max_size: Gitlab::CurrentSettings.current_application_settings.max_yaml_size_bytes, + max_depth: Gitlab::CurrentSettings.current_application_settings.max_yaml_depth) + end + end + end + end + end +end |