secret_config 0.7.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -756
- data/Rakefile +7 -7
- data/bin/{secret_config → secret-config} +1 -1
- data/lib/secret_config.rb +31 -2
- data/lib/secret_config/cli.rb +134 -92
- data/lib/secret_config/config.rb +44 -0
- data/lib/secret_config/parser.rb +76 -0
- data/lib/secret_config/providers/file.rb +17 -4
- data/lib/secret_config/providers/ssm.rb +9 -2
- data/lib/secret_config/registry.rb +46 -33
- data/lib/secret_config/setting_interpolator.rb +14 -27
- data/lib/secret_config/string_interpolator.rb +10 -9
- data/lib/secret_config/utils.rb +2 -2
- data/lib/secret_config/version.rb +1 -1
- data/test/config/application.yml +35 -5
- data/test/parser_test.rb +82 -0
- data/test/providers/file_test.rb +5 -5
- data/test/providers/ssm_test.rb +37 -12
- data/test/registry_test.rb +56 -26
- data/test/secret_config_test.rb +35 -4
- data/test/setting_interpolator_test.rb +43 -43
- data/test/test_helper.rb +6 -6
- data/test/utils_test.rb +4 -4
- metadata +9 -5
data/Rakefile
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
require
|
2
|
-
require_relative
|
1
|
+
require "rake/testtask"
|
2
|
+
require_relative "lib/secret_config/version"
|
3
3
|
|
4
4
|
task :gem do
|
5
|
-
system
|
5
|
+
system "gem build secret_config.gemspec"
|
6
6
|
end
|
7
7
|
|
8
|
-
task :
|
8
|
+
task publish: :gem do
|
9
9
|
system "git tag -a v#{SecretConfig::VERSION} -m 'Tagging #{SecretConfig::VERSION}'"
|
10
|
-
system
|
10
|
+
system "git push --tags"
|
11
11
|
system "gem push secret_config-#{SecretConfig::VERSION}.gem"
|
12
12
|
system "rm secret_config-#{SecretConfig::VERSION}.gem"
|
13
13
|
end
|
14
14
|
|
15
15
|
Rake::TestTask.new(:test) do |t|
|
16
|
-
t.pattern =
|
16
|
+
t.pattern = "test/**/*_test.rb"
|
17
17
|
t.verbose = true
|
18
18
|
t.warning = true
|
19
19
|
end
|
20
20
|
|
21
|
-
task :
|
21
|
+
task default: :test
|
data/lib/secret_config.rb
CHANGED
@@ -18,6 +18,8 @@ module SecretConfig
|
|
18
18
|
end
|
19
19
|
|
20
20
|
autoload :CLI, "secret_config/cli"
|
21
|
+
autoload :Config, "secret_config/config"
|
22
|
+
autoload :Parser, "secret_config/parser"
|
21
23
|
autoload :SettingInterpolator, "secret_config/setting_interpolator"
|
22
24
|
autoload :StringInterpolator, "secret_config/string_interpolator"
|
23
25
|
autoload :Utils, "secret_config/utils"
|
@@ -30,7 +32,6 @@ module SecretConfig
|
|
30
32
|
def_delegator :registry, :[]
|
31
33
|
def_delegator :registry, :[]=
|
32
34
|
def_delegator :registry, :key?
|
33
|
-
def_delegator :registry, :fetch
|
34
35
|
def_delegator :registry, :set
|
35
36
|
def_delegator :registry, :delete
|
36
37
|
def_delegator :registry, :refresh!
|
@@ -42,6 +43,34 @@ module SecretConfig
|
|
42
43
|
@registry = SecretConfig::Registry.new(path: path, provider: provider, provider_args: args)
|
43
44
|
end
|
44
45
|
|
46
|
+
# Fetch configuration in a block by supplying the root path once.
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
# SecretConfig.configure("suppliers/kafka_service") do |config|
|
50
|
+
# Kafka::Client.new(
|
51
|
+
# seed_brokers: config.fetch("brokers", separator: ","),
|
52
|
+
# delivery_interval: config.fetch("delivery_interval", type: :integer, default: 0),
|
53
|
+
# delivery_threshold: config.fetch("delivery_threshold", type: :integer, default: 0),
|
54
|
+
# max_queue_size: config.fetch("max_queue_size", type: :integer, default: 10_000),
|
55
|
+
# max_retries: config.fetch("max_retries", type: :integer, default: -1),
|
56
|
+
# retry_backoffs: config.fetch("retry_backoff", type: :integer, default: 0),
|
57
|
+
# )
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# If `SecretConfig.configure` was not used it would have looked like:
|
61
|
+
# Kafka::Client.new(
|
62
|
+
# seed_brokers: SecretConfig.fetch("suppliers/kafka_service/brokers", separator: ","),
|
63
|
+
# delivery_interval: SecretConfig.fetch("suppliers/kafka_service/delivery_interval", type: :integer, default: 0),
|
64
|
+
# delivery_threshold: SecretConfig.fetch("suppliers/kafka_service/delivery_threshold", type: :integer, default: 0),
|
65
|
+
# max_queue_size: SecretConfig.fetch("suppliers/kafka_service/max_queue_size", type: :integer, default: 10_000),
|
66
|
+
# max_retries: SecretConfig.fetch("suppliers/kafka_service/max_retries", type: :integer, default: -1),
|
67
|
+
# retry_backoffs: SecretConfig.fetch("suppliers/kafka_service/retry_backoff", type: :integer, default: 0),
|
68
|
+
# )
|
69
|
+
def self.configure(path)
|
70
|
+
config = Config.new(path, registry)
|
71
|
+
yield(config)
|
72
|
+
end
|
73
|
+
|
45
74
|
# Returns the global registry.
|
46
75
|
# Unless `.use` was called above, it will default to a file provider.
|
47
76
|
def self.registry
|
@@ -68,5 +97,5 @@ module SecretConfig
|
|
68
97
|
end
|
69
98
|
|
70
99
|
@check_env_var = true
|
71
|
-
@filters = [/password/i, /key\Z/i, /passphrase/i]
|
100
|
+
@filters = [/password/i, /key\Z/i, /passphrase/i, /secret/i, /pwd\Z/i]
|
72
101
|
end
|
data/lib/secret_config/cli.rb
CHANGED
@@ -8,11 +8,29 @@ require "irb"
|
|
8
8
|
|
9
9
|
module SecretConfig
|
10
10
|
class CLI
|
11
|
-
|
12
|
-
|
11
|
+
module Colors
|
12
|
+
CLEAR = "\e[0m".freeze
|
13
|
+
BOLD = "\e[1m".freeze
|
14
|
+
BLACK = "\e[30m".freeze
|
15
|
+
RED = "\e[31m".freeze
|
16
|
+
GREEN = "\e[32m".freeze
|
17
|
+
YELLOW = "\e[33m".freeze
|
18
|
+
BLUE = "\e[34m".freeze
|
19
|
+
MAGENTA = "\e[35m".freeze
|
20
|
+
CYAN = "\e[36m".freeze
|
21
|
+
WHITE = "\e[37m".freeze
|
22
|
+
|
23
|
+
TITLE = "\e[1m".freeze
|
24
|
+
KEY = "\e[36m".freeze
|
25
|
+
REMOVE = "\e[31m".freeze
|
26
|
+
ADD = "\e[32m".freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :path, :provider, :file_name,
|
30
|
+
:export, :no_filter, :interpolate,
|
13
31
|
:import, :key_id, :key_alias, :random_size, :prune, :force,
|
14
32
|
:diff_path, :import_path,
|
15
|
-
:fetch_key, :delete_key, :set_key, :set_value, :
|
33
|
+
:fetch_key, :delete_key, :set_key, :set_value, :delete_tree,
|
16
34
|
:copy_path, :diff,
|
17
35
|
:console,
|
18
36
|
:show_version
|
@@ -29,7 +47,6 @@ module SecretConfig
|
|
29
47
|
@path = nil
|
30
48
|
@key_id = nil
|
31
49
|
@key_alias = nil
|
32
|
-
@region = ENV["AWS_REGION"]
|
33
50
|
@provider = :ssm
|
34
51
|
@random_size = 32
|
35
52
|
@no_filter = false
|
@@ -43,10 +60,11 @@ module SecretConfig
|
|
43
60
|
@set_value = nil
|
44
61
|
@fetch_key = nil
|
45
62
|
@delete_key = nil
|
46
|
-
@
|
63
|
+
@delete_tree = nil
|
47
64
|
@diff_path = nil
|
48
65
|
@import_path = nil
|
49
66
|
@force = false
|
67
|
+
@interpolate = false
|
50
68
|
|
51
69
|
if argv.empty?
|
52
70
|
puts parser
|
@@ -58,27 +76,32 @@ module SecretConfig
|
|
58
76
|
def run!
|
59
77
|
if show_version
|
60
78
|
puts "Secret Config v#{VERSION}"
|
61
|
-
puts "Region: #{region}"
|
62
79
|
elsif console
|
63
80
|
run_console
|
64
81
|
elsif export
|
65
|
-
|
82
|
+
raise(ArgumentError, "--path option is not valid for --export") if path
|
83
|
+
|
84
|
+
run_export(export, file_name || STDOUT, filtered: !no_filter)
|
66
85
|
elsif import
|
67
|
-
|
68
|
-
|
69
|
-
|
86
|
+
if path
|
87
|
+
run_import_path(import, path, prune, force)
|
88
|
+
else
|
89
|
+
run_import(import, file_name || STDIN, prune, force)
|
90
|
+
end
|
70
91
|
elsif diff
|
71
|
-
|
72
|
-
|
73
|
-
|
92
|
+
if path
|
93
|
+
run_diff_path(diff, path)
|
94
|
+
else
|
95
|
+
run_diff(diff, file_name || STDIN)
|
96
|
+
end
|
74
97
|
elsif set_key
|
75
98
|
run_set(set_key, set_value)
|
76
99
|
elsif fetch_key
|
77
100
|
run_fetch(fetch_key)
|
78
101
|
elsif delete_key
|
79
102
|
run_delete(delete_key)
|
80
|
-
elsif
|
81
|
-
|
103
|
+
elsif delete_tree
|
104
|
+
run_delete_tree(delete_tree)
|
82
105
|
else
|
83
106
|
puts parser
|
84
107
|
end
|
@@ -91,27 +114,27 @@ module SecretConfig
|
|
91
114
|
|
92
115
|
For more information, see: https://rocketjob.github.io/secret_config/
|
93
116
|
|
94
|
-
|
117
|
+
secret-config [options]
|
95
118
|
BANNER
|
96
119
|
|
97
|
-
opts.on "-e", "--export
|
98
|
-
@export =
|
120
|
+
opts.on "-e", "--export SOURCE_PATH", "Export configuration. Use --file to specify the file name, otherwise stdout is used." do |path|
|
121
|
+
@export = path
|
99
122
|
end
|
100
123
|
|
101
|
-
opts.on "-i", "--import
|
102
|
-
@import =
|
124
|
+
opts.on "-i", "--import TARGET_PATH", "Import configuration. Use --file to specify the file name, --path for the SOURCE_PATH, otherwise stdin is used." do |path|
|
125
|
+
@import = path
|
103
126
|
end
|
104
127
|
|
105
|
-
opts.on "
|
106
|
-
@
|
128
|
+
opts.on "-f", "--file FILE_NAME", "Import/Export/Diff to/from this file." do |file_name|
|
129
|
+
@file_name = file_name
|
107
130
|
end
|
108
131
|
|
109
|
-
opts.on "--
|
110
|
-
@
|
132
|
+
opts.on "-p", "--path PATH", "Import/Export/Diff to/from this path." do |path|
|
133
|
+
@path = path
|
111
134
|
end
|
112
135
|
|
113
|
-
opts.on "--diff
|
114
|
-
@
|
136
|
+
opts.on "--diff TARGET_PATH", "Compare configuration to this path. Use --file to specify the source file name, --path for the SOURCE_PATH, otherwise stdin is used." do |file_name|
|
137
|
+
@diff = file_name
|
115
138
|
end
|
116
139
|
|
117
140
|
opts.on "-s", "--set KEY=VALUE", "Set one key to value. Example: --set mysql/database=localhost" do |param|
|
@@ -121,59 +144,55 @@ module SecretConfig
|
|
121
144
|
end
|
122
145
|
end
|
123
146
|
|
124
|
-
opts.on "-f", "--fetch KEY", "Fetch the value for one setting. Example: --
|
147
|
+
opts.on "-f", "--fetch KEY", "Fetch the value for one setting. Example: --fetch mysql/database." do |key|
|
125
148
|
@fetch_key = key
|
126
149
|
end
|
127
150
|
|
128
|
-
opts.on "-d", "--delete KEY", "Delete one specific key.
|
151
|
+
opts.on "-d", "--delete KEY", "Delete one specific key." do |key|
|
129
152
|
@delete_key = key
|
130
153
|
end
|
131
154
|
|
132
|
-
opts.on "-r", "--delete-
|
133
|
-
@
|
155
|
+
opts.on "-r", "--delete-tree PATH", "Recursively delete all keys under the specified path." do |path|
|
156
|
+
@delete_tree = path
|
134
157
|
end
|
135
158
|
|
136
159
|
opts.on "-c", "--console", "Start interactive console." do
|
137
160
|
@console = true
|
138
161
|
end
|
139
162
|
|
140
|
-
opts.on "-p", "--path PATH", "Path in central configuration to use." do |path|
|
141
|
-
@path = path
|
142
|
-
end
|
143
|
-
|
144
163
|
opts.on "--provider PROVIDER", "Provider to use. [ssm | file]. Default: ssm" do |provider|
|
145
164
|
@provider = provider.to_sym
|
146
165
|
end
|
147
166
|
|
148
|
-
opts.on "--no-filter", "Do not filter passwords and keys." do
|
167
|
+
opts.on "--no-filter", "For --export only. Do not filter passwords and keys." do
|
149
168
|
@no_filter = true
|
150
169
|
end
|
151
170
|
|
152
|
-
opts.on "--
|
171
|
+
opts.on "--interpolate", "For --export only. Evaluate string interpolation and __import__." do
|
172
|
+
@interpolate = true
|
173
|
+
end
|
174
|
+
|
175
|
+
opts.on "--prune", "For --import only. During import delete all existing keys for which there is no key in the import file. Only works with --import." do
|
153
176
|
@prune = true
|
154
177
|
end
|
155
178
|
|
156
|
-
opts.on "--force", "
|
179
|
+
opts.on "--force", "For --import only. Overwrite all values, not just the changed ones. Useful for changing the KMS key." do
|
157
180
|
@force = true
|
158
181
|
end
|
159
182
|
|
160
|
-
opts.on "--key_id KEY_ID", "Encrypt config settings with this AWS KMS key id. Default: AWS Default key." do |key_id|
|
183
|
+
opts.on "--key_id KEY_ID", "For --import only. Encrypt config settings with this AWS KMS key id. Default: AWS Default key." do |key_id|
|
161
184
|
@key_id = key_id
|
162
185
|
end
|
163
186
|
|
164
|
-
opts.on "--key_alias KEY_ALIAS", "Encrypt config settings with this AWS KMS alias." do |key_alias|
|
187
|
+
opts.on "--key_alias KEY_ALIAS", "For --import only. Encrypt config settings with this AWS KMS alias." do |key_alias|
|
165
188
|
@key_alias = key_alias
|
166
189
|
end
|
167
190
|
|
168
|
-
opts.on "--
|
169
|
-
@region = region
|
170
|
-
end
|
171
|
-
|
172
|
-
opts.on "--random_size INTEGER", Integer, "Size to use when generating random values. Whenever #{RANDOM} is encountered during an import. Default: 32" do |random_size|
|
191
|
+
opts.on "--random_size INTEGER", Integer, "For --import only. Size to use when generating random values when $(random) is encountered in the source. Default: 32" do |random_size|
|
173
192
|
@random_size = random_size
|
174
193
|
end
|
175
194
|
|
176
|
-
opts.on "-v", "--version", "Display
|
195
|
+
opts.on "-v", "--version", "Display Secret Config version." do
|
177
196
|
@show_version = true
|
178
197
|
end
|
179
198
|
|
@@ -191,64 +210,68 @@ module SecretConfig
|
|
191
210
|
begin
|
192
211
|
case provider
|
193
212
|
when :ssm
|
194
|
-
|
213
|
+
if key_alias
|
214
|
+
Providers::Ssm.new(key_alias: key_alias)
|
215
|
+
elsif key_id
|
216
|
+
Providers::Ssm.new(key_id: key_id)
|
217
|
+
else
|
218
|
+
Providers::Ssm.new
|
219
|
+
end
|
195
220
|
else
|
196
221
|
raise ArgumentError, "Invalid provider: #{provider}"
|
197
222
|
end
|
198
223
|
end
|
199
224
|
end
|
200
225
|
|
201
|
-
def run_export(
|
202
|
-
|
226
|
+
def run_export(source_path, file_name, filtered: true)
|
227
|
+
puts("Exporting #{provider}:#{source_path} to #{file_name}") if file_name.is_a?(String)
|
203
228
|
|
204
|
-
config = fetch_config(
|
229
|
+
config = fetch_config(source_path, filtered: filtered)
|
205
230
|
write_config_file(file_name, config)
|
206
|
-
|
207
|
-
puts("Exported #{path} from #{provider} to #{file_name}") if file_name.is_a?(String)
|
208
231
|
end
|
209
232
|
|
210
|
-
def run_import(
|
211
|
-
|
212
|
-
|
233
|
+
def run_import(target_path, file_name, prune, force)
|
234
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
235
|
+
puts "+++ #{file_name}#{Colors::CLEAR}"
|
213
236
|
config = read_config_file(file_name)
|
214
|
-
import_config(config,
|
215
|
-
|
216
|
-
puts("Imported #{file_name} to #{path} on provider: #{provider}") if file_name.is_a?(String)
|
237
|
+
import_config(config, target_path, prune, force)
|
217
238
|
end
|
218
239
|
|
219
|
-
def run_import_path(
|
220
|
-
|
240
|
+
def run_import_path(target_path, source_path, prune, force)
|
241
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
242
|
+
puts "+++ #{provider}:#{source_path}#{Colors::CLEAR}"
|
221
243
|
|
222
244
|
config = fetch_config(source_path, filtered: false)
|
223
|
-
import_config(config,
|
245
|
+
import_config(config, target_path, prune, force)
|
224
246
|
|
225
|
-
puts("Imported #{
|
247
|
+
puts("Imported #{target_path} from #{source_path} on provider: #{provider}")
|
226
248
|
end
|
227
249
|
|
228
|
-
def run_diff(
|
229
|
-
|
250
|
+
def run_diff(target_path, file_name)
|
251
|
+
source_config = read_config_file(file_name)
|
252
|
+
source = Utils.flatten(source_config, target_path)
|
230
253
|
|
231
|
-
|
232
|
-
|
254
|
+
target_config = fetch_config(target_path, filtered: false)
|
255
|
+
target = Utils.flatten(target_config, target_path)
|
233
256
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
diff_config(
|
257
|
+
if file_name.is_a?(String)
|
258
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
259
|
+
puts "+++ #{file_name}#{Colors::CLEAR}"
|
260
|
+
end
|
261
|
+
diff_config(target, source)
|
239
262
|
end
|
240
263
|
|
241
|
-
def run_diff_path(
|
242
|
-
raise(ArgumentError, "Missing required option --path") unless path
|
243
|
-
|
264
|
+
def run_diff_path(target_path, source_path)
|
244
265
|
source_config = fetch_config(source_path, filtered: false)
|
245
266
|
source = Utils.flatten(source_config)
|
246
267
|
|
247
|
-
target_config = fetch_config(
|
268
|
+
target_config = fetch_config(target_path, filtered: false)
|
248
269
|
target = Utils.flatten(target_config)
|
249
270
|
|
250
|
-
puts
|
251
|
-
|
271
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
272
|
+
puts "+++ #{provider}:#{source_path}#{Colors::CLEAR}"
|
273
|
+
|
274
|
+
diff_config(target, source)
|
252
275
|
end
|
253
276
|
|
254
277
|
def run_console
|
@@ -256,14 +279,18 @@ module SecretConfig
|
|
256
279
|
end
|
257
280
|
|
258
281
|
def run_delete(key)
|
282
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}"
|
283
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
259
284
|
provider_instance.delete(key)
|
260
285
|
end
|
261
286
|
|
262
|
-
def
|
287
|
+
def run_delete_tree(path)
|
263
288
|
source_config = fetch_config(path)
|
264
|
-
|
289
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}#{Colors::CLEAR}"
|
290
|
+
|
291
|
+
source = Utils.flatten(source_config, path)
|
265
292
|
source.each_key do |key|
|
266
|
-
puts
|
293
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
267
294
|
provider_instance.delete(key)
|
268
295
|
end
|
269
296
|
end
|
@@ -277,8 +304,8 @@ module SecretConfig
|
|
277
304
|
provider_instance.set(key, value)
|
278
305
|
end
|
279
306
|
|
280
|
-
def current_values
|
281
|
-
|
307
|
+
def current_values(path)
|
308
|
+
Utils.flatten(fetch_config(path, filtered: false), path)
|
282
309
|
end
|
283
310
|
|
284
311
|
def read_config_file(file_name)
|
@@ -306,38 +333,53 @@ module SecretConfig
|
|
306
333
|
# Ignore filtered values
|
307
334
|
next
|
308
335
|
end
|
309
|
-
|
336
|
+
|
337
|
+
if current_values.key?(key)
|
338
|
+
puts "#{Colors::KEY}* #{key}#{Colors::CLEAR}"
|
339
|
+
else
|
340
|
+
puts "#{Colors::ADD}+ #{key}#{Colors::CLEAR}"
|
341
|
+
end
|
342
|
+
|
310
343
|
provider_instance.set(key, value)
|
311
344
|
end
|
312
345
|
end
|
313
346
|
|
314
347
|
def fetch_config(path, filtered: true)
|
315
|
-
registry = Registry.new(path: path, provider: provider_instance)
|
348
|
+
registry = Registry.new(path: path, provider: provider_instance, interpolate: interpolate)
|
316
349
|
config = filtered ? registry.configuration : registry.configuration(filters: nil)
|
317
350
|
sort_hash_by_key!(config)
|
318
351
|
end
|
319
352
|
|
320
353
|
# Diffs two configs and displays the results
|
321
|
-
def diff_config(
|
354
|
+
def diff_config(target, source)
|
322
355
|
(source.keys + target.keys).sort.uniq.each do |key|
|
323
356
|
if target.key?(key)
|
324
357
|
if source.key?(key)
|
325
358
|
value = source[key].to_s
|
326
359
|
# Ignore filtered values
|
327
|
-
|
360
|
+
if (value != target[key].to_s) && (value != FILTERED)
|
361
|
+
puts "#{Colors::KEY}#{key}:"
|
362
|
+
puts "#{Colors::REMOVE}#{prefix_lines("- ", target[key])}"
|
363
|
+
puts "#{Colors::ADD}#{prefix_lines("+ ", source[key])}#{Colors::CLEAR}\n\n"
|
364
|
+
end
|
328
365
|
else
|
329
|
-
puts "
|
366
|
+
puts "#{Colors::KEY}#{key}:"
|
367
|
+
puts "#{Colors::REMOVE}#{prefix_lines("- ", target[key])}\n\n"
|
330
368
|
end
|
331
369
|
elsif source.key?(key)
|
332
|
-
puts "
|
370
|
+
puts "#{Colors::KEY}#{key}:"
|
371
|
+
puts "#{Colors::ADD}#{prefix_lines("+ ", source[key])}#{Colors::CLEAR}\n\n"
|
333
372
|
end
|
334
373
|
end
|
335
374
|
end
|
336
375
|
|
337
|
-
def
|
338
|
-
|
376
|
+
def prefix_lines(prefix, value)
|
377
|
+
value.to_s.lines.collect { |line| "#{prefix}#{line}" }.join("")
|
378
|
+
end
|
339
379
|
|
340
|
-
|
380
|
+
def import_config(config, path, prune, force)
|
381
|
+
current = current_values(path)
|
382
|
+
delete_keys = prune ? current.keys - Utils.flatten(config, path).keys : []
|
341
383
|
|
342
384
|
unless delete_keys.empty?
|
343
385
|
puts "Going to delete the following keys:"
|
@@ -345,10 +387,10 @@ module SecretConfig
|
|
345
387
|
sleep(5)
|
346
388
|
end
|
347
389
|
|
348
|
-
set_config(config, path, force ? {} :
|
390
|
+
set_config(config, path, force ? {} : current)
|
349
391
|
|
350
392
|
delete_keys.each do |key|
|
351
|
-
puts "
|
393
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
352
394
|
provider_instance.delete(key)
|
353
395
|
end
|
354
396
|
end
|