Class: Gitlab::Ci::Config::Interpolation::Config

Inherits:
Object
  • Object
show all
Includes:
Utils::StrongMemoize
Defined in:
lib/gitlab/ci/config/interpolation/config.rb

Overview

Interpolation::Config represents a configuration artifact that we want to perform interpolation on.

Constant Summary collapse

MAX_NODES =

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

500_000
MAX_NODE_SIZE =

1MB

1024 * 1024
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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash) ⇒ Config

Returns a new instance of Config.



57
58
59
60
# File 'lib/gitlab/ci/config/interpolation/config.rb', line 57

def initialize(hash)
  @config = hash
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



55
56
57
# File 'lib/gitlab/ci/config/interpolation/config.rb', line 55

def errors
  @errors
end

Class Method Details

.fabricate(config) ⇒ Object



83
84
85
86
87
88
89
90
91
92
# File 'lib/gitlab/ci/config/interpolation/config.rb', line 83

def self.fabricate(config)
  case config
  when Hash
    new(config)
  when Interpolation::Config
    config
  else
    raise ArgumentError, 'unknown interpolation config'
  end
end

Instance Method Details

#replace!(&block) ⇒ Object

The replace! method will yield a block and replace each of the hash config nodes with the return value of the block.

It returns ‘nil` if there were errors found during the process.



72
73
74
75
76
77
78
79
80
# File 'lib/gitlab/ci/config/interpolation/config.rb', line 72

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

#to_hObject



62
63
64
# File 'lib/gitlab/ci/config/interpolation/config.rb', line 62

def to_h
  @config
end