prefab-cloud-ruby 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bfaef7482dfdd1946bd0b0dee2cd0f366f5661e275bb8b906fb207d9b241d14
4
- data.tar.gz: ed36c67d8039d2250fab5c6b1ff08da23cde51f696c256daaa943639205f2d0e
3
+ metadata.gz: 55134a75669f459bbb12d50cfa6e221937a5c00f53ca365e609f0cb436b24aff
4
+ data.tar.gz: f3507032152e1dfe7b48156e5b8795d3bfd9262e077fab18923fef7cbeb78e34
5
5
  SHA512:
6
- metadata.gz: 209f9cc828ec0eccd3b34162d9513c53695bf36838b60601103fd699748fad78af28cb622c1d057ea63162abd143f4db176395726a52517426885483789c7a3c
7
- data.tar.gz: 3d368dc2aab1e941607e437d889dd51c8d5aaf9e65208d81552f930cfa34db0eff02fba1b7f2e7a3a08ab87a23e11fad67a0634861e586649fbc466a4f2d3629
6
+ metadata.gz: 839db6777d5e6c3a76d34b7812787e8241779b2ede48d4ffddbf5e96bb493494e8d30e980582a5d06518e8f64f789287417ac5e6abc66c7789e17082992c83fb
7
+ data.tar.gz: fd26b0d5ceb02a17724ede1a3329bda2a1ca7ee1c8d49e0776c61498bfe7e1b41ca81158e395192c4c73c35970824e5eb2d319b241a9489e0e215febe9ea2bb6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 1.3.0 - 2023-11-13
6
+ - Less logging when wifi is off and we load from cache (#157)
7
+ - Alpha: Add Provided & Secret Support (#152)
8
+ - Alpha: x_datafile (#156)
9
+ - Add single line action-controller output under rails.controller (#158)
10
+
11
+ ## 1.2.1 - 2023-11-01
12
+ - Update protobuf definitions (#154)
13
+
14
+
3
15
  ## 1.2.0 - 2023-10-30
4
16
  - Add `Prefab.get('key')` style usage after a `Prefab.init()` call (#151)
5
17
  - Add `add_context_keys` and `with_context_keys` method for LoggerClient (#145)
data/Gemfile CHANGED
@@ -7,6 +7,8 @@ gem 'google-protobuf', platforms: :ruby
7
7
  gem 'ld-eventsource'
8
8
  gem 'uuid'
9
9
 
10
+ gem 'activesupport', '>= 4'
11
+
10
12
  group :development do
11
13
  gem 'benchmark-ips'
12
14
  gem 'bundler'
data/Gemfile.lock CHANGED
@@ -1,17 +1,32 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
+ activesupport (7.1.2)
5
+ base64
6
+ bigdecimal
7
+ concurrent-ruby (~> 1.0, >= 1.0.2)
8
+ connection_pool (>= 2.2.5)
9
+ drb
10
+ i18n (>= 1.6, < 2)
11
+ minitest (>= 5.1)
12
+ mutex_m
13
+ tzinfo (~> 2.0)
4
14
  addressable (2.8.0)
5
15
  public_suffix (>= 2.0.2, < 5.0)
6
16
  ansi (1.5.0)
17
+ base64 (0.2.0)
7
18
  benchmark-ips (2.10.0)
19
+ bigdecimal (3.1.4)
8
20
  builder (3.2.4)
9
21
  concurrent-ruby (1.1.10)
22
+ connection_pool (2.4.1)
10
23
  descendants_tracker (0.0.4)
11
24
  thread_safe (~> 0.3, >= 0.3.1)
12
25
  docile (1.3.5)
13
26
  domain_name (0.5.20190701)
14
27
  unf (>= 0.0.5, < 1.0.0)
28
+ drb (2.2.0)
29
+ ruby2_keywords
15
30
  faraday (1.3.0)
16
31
  faraday-net_http (~> 1.0)
17
32
  multipart-post (>= 1.2, < 3)
@@ -43,6 +58,8 @@ GEM
43
58
  http-cookie (1.0.4)
44
59
  domain_name (~> 0.5)
45
60
  http-form_data (2.3.0)
61
+ i18n (1.14.1)
62
+ concurrent-ruby (~> 1.0)
46
63
  juwelier (2.4.9)
47
64
  builder
48
65
  bundler
@@ -78,6 +95,7 @@ GEM
78
95
  multi_json (1.15.0)
79
96
  multi_xml (0.6.0)
80
97
  multipart-post (2.1.1)
98
+ mutex_m (0.2.0)
81
99
  nokogiri (1.15.2)
82
100
  mini_portile2 (~> 2.8.2)
83
101
  racc (~> 1.4)
@@ -104,6 +122,8 @@ GEM
104
122
  systemu (2.6.5)
105
123
  thread_safe (0.3.6)
106
124
  timecop (0.9.4)
125
+ tzinfo (2.0.6)
126
+ concurrent-ruby (~> 1.0)
107
127
  unf (0.1.4)
108
128
  unf_ext
109
129
  unf_ext (0.0.8)
@@ -114,6 +134,7 @@ PLATFORMS
114
134
  ruby
115
135
 
116
136
  DEPENDENCIES
137
+ activesupport (>= 4)
117
138
  benchmark-ips
118
139
  bundler
119
140
  concurrent-ruby (~> 1.0, >= 1.0.5)
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017 Jeff Dwyer
1
+ Copyright (c) 2023 Prefab, Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.3.0
data/lib/prefab/client.rb CHANGED
@@ -22,6 +22,8 @@ module Prefab
22
22
 
23
23
  if @options.local_only?
24
24
  LOG.debug 'Prefab Running in Local Mode'
25
+ elsif @options.datafile?
26
+ LOG.debug 'Prefab Running in DataFile Mode'
25
27
  else
26
28
  @api_key = @options.api_key
27
29
  raise Prefab::Errors::InvalidApiKeyError, @api_key if @api_key.nil? || @api_key.empty? || api_key.count('-') < 1
@@ -96,6 +98,8 @@ module Prefab
96
98
  ActiveJob::Base.logger = log if defined?(ActiveJob)
97
99
  ActiveRecord::Base.logger = log
98
100
  ActiveStorage.logger = log if defined?(ActiveStorage)
101
+
102
+ LogSubscribers::ActionControllerSubscriber.attach_to :action_controller unless @options.disable_action_controller_logging
99
103
  end
100
104
 
101
105
  def on_update(&block)
@@ -31,6 +31,8 @@ module Prefab
31
31
 
32
32
  if @options.local_only?
33
33
  finish_init!(:local_only, nil)
34
+ elsif @options.datafile?
35
+ load_json_file(@options.datafile)
34
36
  else
35
37
  load_checkpoint
36
38
  start_checkpointing_thread
@@ -141,8 +143,16 @@ module Prefab
141
143
  LOG.info "Checkpoint #{source} failed to load. Response #{resp.status}"
142
144
  false
143
145
  end
146
+ rescue Faraday::ConnectionFailed => e
147
+ if @initialization_lock.write_locked?
148
+ LOG.warn "Connection Fail loading #{source} checkpoint."
149
+ else
150
+ LOG.debug "Connection Fail loading #{source} checkpoint."
151
+ end
152
+ false
144
153
  rescue StandardError => e
145
154
  LOG.warn "Unexpected #{source} problem loading checkpoint #{e} #{conn}"
155
+ LOG.debug e.backtrace
146
156
  false
147
157
  end
148
158
 
@@ -156,7 +166,7 @@ module Prefab
156
166
  [
157
167
  context.type,
158
168
  context.values.keys.map do |k|
159
- [k, Prefab::ConfigValueUnwrapper.new(context.values[k]).unwrap]
169
+ [k, Prefab::ConfigValueUnwrapper.new(context.values[k], @config_resolver).unwrap]
160
170
  end.to_h
161
171
  ]
162
172
  end.to_h
@@ -210,12 +220,21 @@ module Prefab
210
220
  if hours_old > STALE_CACHE_WARN_HOURS
211
221
  LOG.info "Stale Cache Load: #{hours_old} hours old"
212
222
  end
223
+ true
213
224
  end
214
225
  rescue => e
215
226
  LOG.debug "Failed to read cached configs at #{cache_path}. #{e}"
216
227
  false
217
228
  end
218
229
 
230
+ def load_json_file(file)
231
+ File.open(file) do |f|
232
+ f.flock(File::LOCK_SH)
233
+ configs = PrefabProto::Configs.decode_json(f.read)
234
+ load_configs(configs, :datafile)
235
+ end
236
+ end
237
+
219
238
  # A thread that checks for a checkpoint
220
239
  def start_checkpointing_thread
221
240
  Thread.new do
@@ -54,6 +54,7 @@ module Prefab
54
54
  private
55
55
 
56
56
  def load_classpath_config
57
+ return {} if @prefab_options.datafile?
57
58
  classpath_dir = @prefab_options.prefab_config_classpath_dir
58
59
  rtn = load_glob(File.join(classpath_dir, '.prefab.default.config.yaml'))
59
60
  @prefab_options.prefab_envs.each do |env|
@@ -63,6 +64,7 @@ module Prefab
63
64
  end
64
65
 
65
66
  def load_local_overrides
67
+ return {} if @prefab_options.datafile?
66
68
  override_dir = @prefab_options.prefab_config_override_dir
67
69
  rtn = load_glob(File.join(override_dir, '.prefab.default.config.yaml'))
68
70
  @prefab_options.prefab_envs.each do |env|
@@ -3,37 +3,115 @@
3
3
  module Prefab
4
4
  class ConfigValueUnwrapper
5
5
  LOG = Prefab::InternalLogger.new(ConfigValueUnwrapper)
6
- attr_reader :value, :weighted_value_index
6
+ CONFIDENTIAL_PREFIX = "*****"
7
+ attr_reader :weighted_value_index
7
8
 
8
- def initialize(value, weighted_value_index = nil)
9
- @value = value
9
+ def initialize(config_value, resolver, weighted_value_index = nil)
10
+ @config_value = config_value
11
+ @resolver = resolver
10
12
  @weighted_value_index = weighted_value_index
11
13
  end
12
14
 
13
- def unwrap
14
- case value.type
15
- when :int, :string, :double, :bool, :log_level
16
- value.public_send(value.type)
17
- when :string_list
18
- value.string_list.values
15
+ def reportable_wrapped_value
16
+ if @config_value.confidential
17
+ # Unique hash for differentiation
18
+ Prefab::ConfigValueWrapper.wrap("#{CONFIDENTIAL_PREFIX}#{Digest::MD5.hexdigest(unwrap)[0,5]}")
19
19
  else
20
- LOG.error "Unknown type: #{config_value.type}"
21
- raise "Unknown type: #{config_value.type}"
20
+ @config_value
21
+ end
22
+ end
23
+
24
+ def reportable_value
25
+ Prefab::ConfigValueUnwrapper.new(reportable_wrapped_value, @resolver, @weighted_value_index).unwrap
26
+ end
27
+
28
+ def raw_config_value
29
+ @config_value
30
+ end
31
+
32
+ # this will return the actual value of confidential, use reportable_value unless you need it
33
+ def unwrap
34
+ raw = case @config_value.type
35
+ when :int, :string, :double, :bool, :log_level
36
+ @config_value.public_send(@config_value.type)
37
+ when :string_list
38
+ @config_value.string_list.values
39
+ else
40
+ LOG.error "Unknown type: #{@config_value.type}"
41
+ raise "Unknown type: #{@config_value.type}"
42
+ end
43
+ if @config_value.has_decrypt_with?
44
+ decryption_key = @resolver.get(@config_value.decrypt_with)&.unwrapped_value
45
+ if decryption_key.nil?
46
+ LOG.warn "No value for decryption key #{@config_value.decrypt_with} found."
47
+ return ""
48
+ else
49
+ unencrypted = Prefab::Encryption.new(decryption_key).decrypt(raw)
50
+ return unencrypted
51
+ end
22
52
  end
53
+
54
+ raw
55
+
23
56
  end
24
57
 
25
- def self.deepest_value(config_value, config_key, context)
58
+ def self.deepest_value(config_value, config, context, resolver)
26
59
  if config_value&.type == :weighted_values
27
60
  value, index = Prefab::WeightedValueResolver.new(
28
61
  config_value.weighted_values.weighted_values,
29
- config_key,
62
+ config.key,
30
63
  context.get(config_value.weighted_values.hash_by_property_name)
31
64
  ).resolve
32
65
 
33
- new(deepest_value(value.value, config_key, context).value, index)
66
+ new(deepest_value(value.value, config, context, resolver).raw_config_value, resolver, index)
67
+
68
+ elsif config_value&.type == :provided
69
+ if :ENV_VAR == config_value.provided.source
70
+ raw = ENV[config_value.provided.lookup]
71
+ if raw.nil?
72
+ LOG.warn "ENV Variable #{config_value.provided.lookup} not found. Using empty string."
73
+ new(Prefab::ConfigValueWrapper.wrap(""), resolver)
74
+ else
75
+ coerced = coerce_into_type(raw, config, config_value.provided.lookup)
76
+ new(Prefab::ConfigValueWrapper.wrap(coerced, confidential: config_value.confidential), resolver)
77
+ end
78
+ else
79
+ raise "Unknown Provided Source #{config_value.provided.source}"
80
+ end
81
+ else
82
+ new(config_value, resolver)
83
+ end
84
+ end
85
+
86
+ # Don't allow env vars to resolve to a value_type other than the config's value_type
87
+ def self.coerce_into_type(value_string, config, env_var_name)
88
+ case config.value_type
89
+ when :INT then Integer(value_string)
90
+ when :DOUBLE then Float(value_string)
91
+ when :STRING then String(value_string)
92
+ when :STRING_LIST then
93
+ maybe_string_list = YAML.load(value_string)
94
+ case maybe_string_list
95
+ when Array
96
+ maybe_string_list
97
+ else
98
+ raise raise Prefab::Errors::EnvVarParseError.new(value_string, config, env_var_name)
99
+ end
100
+ when :BOOL then
101
+ maybe_bool = YAML.load(value_string)
102
+ case maybe_bool
103
+ when TrueClass,FalseClass
104
+ maybe_bool
105
+ else
106
+ raise Prefab::Errors::EnvVarParseError.new(value_string, config, env_var_name)
107
+ end
108
+ when :NOT_SET_VALUE_TYPE
109
+ YAML.load(value_string)
34
110
  else
35
- new(config_value)
111
+ raise Prefab::Errors::EnvVarParseError.new(value_string, config, env_var_name)
36
112
  end
113
+ rescue ArgumentError
114
+ raise Prefab::Errors::EnvVarParseError.new(value_string, config, env_var_name)
37
115
  end
38
116
  end
39
117
  end
@@ -1,17 +1,17 @@
1
1
  module Prefab
2
2
  class ConfigValueWrapper
3
- def self.wrap(value)
3
+ def self.wrap(value, confidential: nil)
4
4
  case value
5
5
  when Integer
6
- PrefabProto::ConfigValue.new(int: value)
6
+ PrefabProto::ConfigValue.new(int: value, confidential: confidential)
7
7
  when Float
8
- PrefabProto::ConfigValue.new(double: value)
8
+ PrefabProto::ConfigValue.new(double: value, confidential: confidential)
9
9
  when TrueClass, FalseClass
10
- PrefabProto::ConfigValue.new(bool: value)
10
+ PrefabProto::ConfigValue.new(bool: value, confidential: confidential)
11
11
  when Array
12
- PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: value.map(&:to_s)))
12
+ PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: value.map(&:to_s)), confidential: confidential)
13
13
  else
14
- PrefabProto::ConfigValue.new(string: value.to_s)
14
+ PrefabProto::ConfigValue.new(string: value.to_s, confidential: confidential)
15
15
  end
16
16
  end
17
17
  end
@@ -22,7 +22,7 @@ module Prefab
22
22
  def evaluate(properties)
23
23
  rtn = evaluate_for_env(@project_env_id, properties) ||
24
24
  evaluate_for_env(0, properties)
25
- LOG.debug "Eval Key #{@config.key} Result #{rtn&.value} with #{properties.to_h}" unless @config.config_type == :LOG_LEVEL
25
+ LOG.debug "Eval Key #{@config.key} Result #{rtn&.reportable_value} with #{properties.to_h}" unless @config.config_type == :LOG_LEVEL
26
26
  rtn
27
27
  end
28
28
 
@@ -93,7 +93,8 @@ module Prefab
93
93
  value: conditional_value.value,
94
94
  value_index: value_index,
95
95
  config_row_index: index,
96
- context: properties
96
+ context: properties,
97
+ resolver: @resolver
97
98
  )
98
99
  end
99
100
  end
@@ -111,7 +112,7 @@ module Prefab
111
112
 
112
113
  def matches?(criterion, value, properties)
113
114
  criterion_value_or_values = Prefab::ConfigValueUnwrapper.deepest_value(criterion.value_to_match, @config.key,
114
- properties).unwrap
115
+ properties, @resolver).unwrap
115
116
 
116
117
  case criterion_value_or_values
117
118
  when Google::Protobuf::RepeatedField
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class Encryption
5
+ CIPHER_TYPE = "aes-256-gcm" # 32/12
6
+ SEPARATOR = "--"
7
+
8
+ # Hexadecimal format ensures that generated keys are representable with
9
+ # plain text
10
+ #
11
+ # To convert back to the original string with the desired length:
12
+ # [ value ].pack("H*")
13
+ def self.generate_new_hex_key
14
+ generate_random_key.unpack("H*")[0]
15
+ end
16
+
17
+ def initialize(key_string_hex)
18
+ @key = [key_string_hex].pack("H*")
19
+ end
20
+
21
+ def encrypt(clear_text)
22
+ cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
23
+ cipher.encrypt
24
+ iv = cipher.random_iv
25
+
26
+ # load them into the cipher
27
+ cipher.key = @key
28
+ cipher.iv = iv
29
+ cipher.auth_data = ""
30
+
31
+ # encrypt the message
32
+ encrypted = cipher.update(clear_text)
33
+ encrypted << cipher.final
34
+ tag = cipher.auth_tag
35
+
36
+ # pack and join
37
+ [encrypted, iv, tag].map { |p| p.unpack("H*")[0] }.join(SEPARATOR)
38
+ end
39
+
40
+ def decrypt(encrypted_string)
41
+ unpacked_parts = encrypted_string.split(SEPARATOR).map { |p| [p].pack("H*") }
42
+
43
+ cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
44
+ cipher.decrypt
45
+ cipher.key = @key
46
+ cipher.iv = unpacked_parts[1]
47
+ cipher.auth_tag = unpacked_parts[2]
48
+
49
+ # and decrypt it
50
+ decrypted = cipher.update(unpacked_parts[0])
51
+ decrypted << cipher.final
52
+ decrypted
53
+ end
54
+
55
+ private
56
+
57
+ def self.generate_random_key
58
+ SecureRandom.random_bytes(key_length)
59
+ end
60
+
61
+ def self.key_length
62
+ OpenSSL::Cipher.new(CIPHER_TYPE).key_len
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ module Errors
5
+ class EnvVarParseError < Prefab::Error
6
+ def initialize(env_var, config, env_var_name)
7
+ super("Evaluating #{config.key} couldn't coerce #{env_var_name} of #{env_var} to #{config.value_type}")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -5,18 +5,23 @@ module Prefab
5
5
  class Evaluation
6
6
  attr_reader :value
7
7
 
8
- def initialize(config:, value:, value_index:, config_row_index:, context:)
8
+ def initialize(config:, value:, value_index:, config_row_index:, context:, resolver:)
9
9
  @config = config
10
10
  @value = value
11
11
  @value_index = value_index
12
12
  @config_row_index = config_row_index
13
13
  @context = context
14
+ @resolver = resolver
14
15
  end
15
16
 
16
17
  def unwrapped_value
17
18
  deepest_value.unwrap
18
19
  end
19
20
 
21
+ def reportable_value
22
+ deepest_value.reportable_value
23
+ end
24
+
20
25
  def report_and_return(evaluation_summary_aggregator)
21
26
  report(evaluation_summary_aggregator)
22
27
 
@@ -27,7 +32,6 @@ module Prefab
27
32
 
28
33
  def report(evaluation_summary_aggregator)
29
34
  return if @config.config_type == :LOG_LEVEL
30
-
31
35
  evaluation_summary_aggregator&.record(
32
36
  config_key: @config.key,
33
37
  config_type: @config.config_type,
@@ -35,14 +39,14 @@ module Prefab
35
39
  config_id: @config.id,
36
40
  config_row_index: @config_row_index,
37
41
  conditional_value_index: @value_index,
38
- selected_value: deepest_value.value,
42
+ selected_value: deepest_value.reportable_wrapped_value,
39
43
  weighted_value_index: deepest_value.weighted_value_index,
40
44
  selected_index: nil # TODO
41
45
  })
42
46
  end
43
47
 
44
48
  def deepest_value
45
- @deepest_value ||= Prefab::ConfigValueUnwrapper.deepest_value(@value, @config.key, @context)
49
+ @deepest_value ||= Prefab::ConfigValueUnwrapper.deepest_value(@value, @config, @context, @resolver)
46
50
  end
47
51
  end
48
52
  end
@@ -1,33 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prefab
4
- class InternalLogger < ::Logger
4
+ class InternalLogger < StaticLogger
5
+ INTERNAL_PREFIX = 'cloud.prefab.client'
6
+
5
7
  def initialize(path)
6
8
  if path.is_a?(Class)
7
- @path = path.name.split('::').last.downcase
9
+ path_string = path.name.split('::').last.downcase
8
10
  else
9
- @path = path
11
+ path_string = path
10
12
  end
11
- end
12
-
13
- def debug msg
14
- Prefab::LoggerClient.instance.log_internal ::Logger::DEBUG, msg, @path
15
- end
16
-
17
- def info msg
18
- Prefab::LoggerClient.instance.log_internal ::Logger::INFO, msg, @path
19
- end
20
-
21
- def warn msg
22
- Prefab::LoggerClient.instance.log_internal ::Logger::WARN, msg, @path
23
- end
24
-
25
- def error msg
26
- Prefab::LoggerClient.instance.log_internal ::Logger::ERROR, msg, @path
27
- end
28
-
29
- def fatal msg
30
- Prefab::LoggerClient.instance.log_internal ::Logger::FATAL, msg, @path
13
+ super("#{INTERNAL_PREFIX}.#{path_string}")
31
14
  end
32
15
  end
33
16
  end
@@ -7,6 +7,10 @@ module Prefab
7
7
  if value.instance_of?(Hash)
8
8
  if value['feature_flag']
9
9
  config[key] = feature_flag_config(file, key, value)
10
+ elsif value['type'] == 'provided'
11
+ config[key] = provided_config(file, key, value)
12
+ elsif value['decrypt_with'] || value['confidential']
13
+ config[key] = complex_string(file, key, value)
10
14
  else
11
15
  value.each do |nest_key, nest_value|
12
16
  nested_key = "#{key}.#{nest_key}"
@@ -23,8 +27,8 @@ module Prefab
23
27
  key: key,
24
28
  rows: [
25
29
  PrefabProto::ConfigRow.new(values: [
26
- PrefabProto::ConditionalValue.new(value: value_from(key, value))
27
- ])
30
+ PrefabProto::ConditionalValue.new(value: value_from(key, value))
31
+ ])
28
32
  ]
29
33
  )
30
34
  }
@@ -79,6 +83,58 @@ module Prefab
79
83
  }
80
84
  end
81
85
 
86
+ def provided_config(file, key, value_hash)
87
+ value = PrefabProto::ConfigValue.new(provided: PrefabProto::Provided.new(
88
+ source: :ENV_VAR,
89
+ lookup: value_hash["lookup"],
90
+ ),
91
+ confidential: value_hash["confidential"],
92
+ )
93
+
94
+ row = PrefabProto::ConfigRow.new(
95
+ values: [
96
+ PrefabProto::ConditionalValue.new(
97
+ value: value
98
+ )
99
+ ]
100
+ )
101
+
102
+ {
103
+ source: file,
104
+ match: value.provided.lookup,
105
+ config: PrefabProto::Config.new(
106
+ config_type: :CONFIG,
107
+ key: key,
108
+ rows: [row]
109
+ )
110
+ }
111
+ end
112
+
113
+ def complex_string(file, key, value_hash)
114
+ value = PrefabProto::ConfigValue.new(
115
+ string: value_hash["value"],
116
+ confidential: value_hash["confidential"],
117
+ decrypt_with: value_hash["decrypt_with"],
118
+ )
119
+
120
+ row = PrefabProto::ConfigRow.new(
121
+ values: [
122
+ PrefabProto::ConditionalValue.new(
123
+ value: value
124
+ )
125
+ ]
126
+ )
127
+
128
+ {
129
+ source: file,
130
+ config: PrefabProto::Config.new(
131
+ config_type: :CONFIG,
132
+ key: key,
133
+ rows: [row]
134
+ )
135
+ }
136
+ end
137
+
82
138
  def parse_criterion(criterion)
83
139
  PrefabProto::Criterion.new(operator: criterion['operator'],
84
140
  property_name: criterion['property'],