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/ci/interpolation/config.rb')
-rw-r--r--lib/gitlab/ci/interpolation/config.rb124
1 files changed, 0 insertions, 124 deletions
diff --git a/lib/gitlab/ci/interpolation/config.rb b/lib/gitlab/ci/interpolation/config.rb
deleted file mode 100644
index 32f58521139..00000000000
--- a/lib/gitlab/ci/interpolation/config.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Interpolation
- ##
- # Interpolation::Config represents a configuration artifact that we want to perform interpolation on.
- #
- class Config
- include Gitlab::Utils::StrongMemoize
- ##
- # Total number of hash nodes traversed. For example, loading a YAML below would result in a hash having 12 nodes
- # instead of 9, because hash values are being counted before we recursively traverse them.
- #
- # test:
- # spec:
- # env: $[[ inputs.env ]]
- #
- # $[[ inputs.key ]]:
- # name: $[[ inputs.key ]]
- # script: my-value
- #
- # According to our benchmarks performed when developing this code, the worst-case scenario of processing
- # a hash with 500_000 nodes takes around 1 second and consumes around 225 megabytes of memory.
- #
- # The typical scenario, using just a few interpolations takes 250ms and consumes around 20 megabytes of memory.
- #
- # Given the above the 500_000 nodes should be an upper limit, provided that the are additional safeguard
- # present in other parts of the code (example: maximum number of interpolation blocks found). Typical size of a
- # YAML configuration with 500k nodes might be around 10 megabytes, which is an order of magnitude higher than
- # the 1MB limit for loading YAML on GitLab.com
- #
- MAX_NODES = 500_000
- MAX_NODE_SIZE = 1024 * 1024 # 1MB
-
- TooManyNodesError = Class.new(StandardError)
- NodeTooLargeError = Class.new(StandardError)
-
- Visitor = Class.new do
- def initialize
- @visited = 0
- end
-
- def visit!
- @visited += 1
-
- raise Config::TooManyNodesError if @visited > Config::MAX_NODES
- end
- end
-
- attr_reader :errors
-
- def initialize(hash)
- @config = hash
- @errors = []
- end
-
- def to_h
- @config
- end
-
- ##
- # The replace! method will yield a block and replace a each of the hash config nodes with a return value of the
- # block.
- #
- # It returns `nil` if there were errors found during the process.
- #
- def replace!(&block)
- recursive_replace(@config, Visitor.new, &block)
- rescue TooManyNodesError
- @errors.push('config too large')
- nil
- rescue NodeTooLargeError
- @errors.push('config node too large')
- nil
- end
- strong_memoize_attr :replace!
-
- def self.fabricate(config)
- case config
- when Hash
- new(config)
- when Interpolation::Config
- config
- else
- raise ArgumentError, 'unknown interpolation config'
- end
- end
-
- private
-
- def recursive_replace(config, visitor, &block)
- visitor.visit!
-
- case config
- when Hash
- {}.tap do |new_hash|
- config.each_pair do |key, value|
- new_key = recursive_replace(key, visitor, &block)
- new_value = recursive_replace(value, visitor, &block)
-
- if new_key != key
- new_hash[new_key] = new_value
- else
- new_hash[key] = new_value
- end
- end
- end
- when Array
- config.map { |value| recursive_replace(value, visitor, &block) }
- when Symbol
- recursive_replace(config.to_s, visitor, &block)
- when String
- raise NodeTooLargeError if config.bytesize > MAX_NODE_SIZE
-
- yield config
- else
- config
- end
- end
- end
- end
- end
-end