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 =

Loading the 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, 500_000 nodes should be an upper limit given that there are additional safeguards present in other parts of the code. 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.



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

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

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



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

def errors
  @errors
end

Class Method Details

.fabricate(config) ⇒ Object



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

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.



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

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



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

def to_h
  @config
end