secret_config 0.7.0 → 0.10.1
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 +154 -97
- 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 +1 -1
- 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
|
-
|
13
|
-
|
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,
|
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,9 +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
|
66
|
+
@force = false
|
67
|
+
@interpolate = false
|
49
68
|
|
50
69
|
if argv.empty?
|
51
70
|
puts parser
|
@@ -57,27 +76,32 @@ module SecretConfig
|
|
57
76
|
def run!
|
58
77
|
if show_version
|
59
78
|
puts "Secret Config v#{VERSION}"
|
60
|
-
puts "Region: #{region}"
|
61
79
|
elsif console
|
62
80
|
run_console
|
63
81
|
elsif export
|
64
|
-
|
82
|
+
raise(ArgumentError, "--path option is not valid for --export") if path
|
83
|
+
|
84
|
+
run_export(export, file_name || STDOUT, filtered: !no_filter)
|
65
85
|
elsif import
|
66
|
-
|
67
|
-
|
68
|
-
|
86
|
+
if path
|
87
|
+
run_import_path(import, path, prune, force)
|
88
|
+
else
|
89
|
+
run_import(import, file_name || STDIN, prune, force)
|
90
|
+
end
|
69
91
|
elsif diff
|
70
|
-
|
71
|
-
|
72
|
-
|
92
|
+
if path
|
93
|
+
run_diff_path(diff, path)
|
94
|
+
else
|
95
|
+
run_diff(diff, file_name || STDIN)
|
96
|
+
end
|
73
97
|
elsif set_key
|
74
98
|
run_set(set_key, set_value)
|
75
99
|
elsif fetch_key
|
76
100
|
run_fetch(fetch_key)
|
77
101
|
elsif delete_key
|
78
102
|
run_delete(delete_key)
|
79
|
-
elsif
|
80
|
-
|
103
|
+
elsif delete_tree
|
104
|
+
run_delete_tree(delete_tree)
|
81
105
|
else
|
82
106
|
puts parser
|
83
107
|
end
|
@@ -90,27 +114,27 @@ module SecretConfig
|
|
90
114
|
|
91
115
|
For more information, see: https://rocketjob.github.io/secret_config/
|
92
116
|
|
93
|
-
|
117
|
+
secret-config [options]
|
94
118
|
BANNER
|
95
119
|
|
96
|
-
opts.on "-e", "--export
|
97
|
-
@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
|
98
122
|
end
|
99
123
|
|
100
|
-
opts.on "-i", "--import
|
101
|
-
@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
|
102
126
|
end
|
103
127
|
|
104
|
-
opts.on "
|
105
|
-
@
|
128
|
+
opts.on "-f", "--file FILE_NAME", "Import/Export/Diff to/from this file." do |file_name|
|
129
|
+
@file_name = file_name
|
106
130
|
end
|
107
131
|
|
108
|
-
opts.on "--
|
109
|
-
@
|
132
|
+
opts.on "-p", "--path PATH", "Import/Export/Diff to/from this path." do |path|
|
133
|
+
@path = path
|
110
134
|
end
|
111
135
|
|
112
|
-
opts.on "--diff
|
113
|
-
@
|
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
|
114
138
|
end
|
115
139
|
|
116
140
|
opts.on "-s", "--set KEY=VALUE", "Set one key to value. Example: --set mysql/database=localhost" do |param|
|
@@ -120,55 +144,55 @@ module SecretConfig
|
|
120
144
|
end
|
121
145
|
end
|
122
146
|
|
123
|
-
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|
|
124
148
|
@fetch_key = key
|
125
149
|
end
|
126
150
|
|
127
|
-
opts.on "-d", "--delete KEY", "Delete one specific key.
|
151
|
+
opts.on "-d", "--delete KEY", "Delete one specific key." do |key|
|
128
152
|
@delete_key = key
|
129
153
|
end
|
130
154
|
|
131
|
-
opts.on "-r", "--delete-
|
132
|
-
@
|
155
|
+
opts.on "-r", "--delete-tree PATH", "Recursively delete all keys under the specified path." do |path|
|
156
|
+
@delete_tree = path
|
133
157
|
end
|
134
158
|
|
135
159
|
opts.on "-c", "--console", "Start interactive console." do
|
136
160
|
@console = true
|
137
161
|
end
|
138
162
|
|
139
|
-
opts.on "-p", "--path PATH", "Path in central configuration to use." do |path|
|
140
|
-
@path = path
|
141
|
-
end
|
142
|
-
|
143
163
|
opts.on "--provider PROVIDER", "Provider to use. [ssm | file]. Default: ssm" do |provider|
|
144
164
|
@provider = provider.to_sym
|
145
165
|
end
|
146
166
|
|
147
|
-
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
|
148
168
|
@no_filter = true
|
149
169
|
end
|
150
170
|
|
151
|
-
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
|
152
176
|
@prune = true
|
153
177
|
end
|
154
178
|
|
155
|
-
opts.on "--
|
156
|
-
@
|
179
|
+
opts.on "--force", "For --import only. Overwrite all values, not just the changed ones. Useful for changing the KMS key." do
|
180
|
+
@force = true
|
157
181
|
end
|
158
182
|
|
159
|
-
opts.on "--
|
160
|
-
@
|
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|
|
184
|
+
@key_id = key_id
|
161
185
|
end
|
162
186
|
|
163
|
-
opts.on "--
|
164
|
-
@
|
187
|
+
opts.on "--key_alias KEY_ALIAS", "For --import only. Encrypt config settings with this AWS KMS alias." do |key_alias|
|
188
|
+
@key_alias = key_alias
|
165
189
|
end
|
166
190
|
|
167
|
-
opts.on "--random_size INTEGER", Integer, "Size to use when generating random values
|
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|
|
168
192
|
@random_size = random_size
|
169
193
|
end
|
170
194
|
|
171
|
-
opts.on "-v", "--version", "Display
|
195
|
+
opts.on "-v", "--version", "Display Secret Config version." do
|
172
196
|
@show_version = true
|
173
197
|
end
|
174
198
|
|
@@ -182,67 +206,72 @@ module SecretConfig
|
|
182
206
|
private
|
183
207
|
|
184
208
|
def provider_instance
|
185
|
-
@provider_instance ||=
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
209
|
+
@provider_instance ||=
|
210
|
+
begin
|
211
|
+
case provider
|
212
|
+
when :ssm
|
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
|
220
|
+
else
|
221
|
+
raise ArgumentError, "Invalid provider: #{provider}"
|
222
|
+
end
|
191
223
|
end
|
192
|
-
end
|
193
224
|
end
|
194
225
|
|
195
|
-
def run_export(
|
196
|
-
|
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)
|
197
228
|
|
198
|
-
config = fetch_config(
|
229
|
+
config = fetch_config(source_path, filtered: filtered)
|
199
230
|
write_config_file(file_name, config)
|
200
|
-
|
201
|
-
puts("Exported #{path} from #{provider} to #{file_name}") if file_name.is_a?(String)
|
202
231
|
end
|
203
232
|
|
204
|
-
def run_import(
|
205
|
-
|
206
|
-
|
233
|
+
def run_import(target_path, file_name, prune, force)
|
234
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
235
|
+
puts "+++ #{file_name}#{Colors::CLEAR}"
|
207
236
|
config = read_config_file(file_name)
|
208
|
-
import_config(config,
|
209
|
-
|
210
|
-
puts("Imported #{file_name} to #{path} on provider: #{provider}") if file_name.is_a?(String)
|
237
|
+
import_config(config, target_path, prune, force)
|
211
238
|
end
|
212
239
|
|
213
|
-
def run_import_path(
|
214
|
-
|
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}"
|
215
243
|
|
216
244
|
config = fetch_config(source_path, filtered: false)
|
217
|
-
import_config(config,
|
245
|
+
import_config(config, target_path, prune, force)
|
218
246
|
|
219
|
-
puts("Imported #{
|
247
|
+
puts("Imported #{target_path} from #{source_path} on provider: #{provider}")
|
220
248
|
end
|
221
249
|
|
222
|
-
def run_diff(
|
223
|
-
|
224
|
-
|
225
|
-
file_config = read_config_file(file_name)
|
226
|
-
file = Utils.flatten(file_config, path)
|
250
|
+
def run_diff(target_path, file_name)
|
251
|
+
source_config = read_config_file(file_name)
|
252
|
+
source = Utils.flatten(source_config, target_path)
|
227
253
|
|
228
|
-
|
229
|
-
|
254
|
+
target_config = fetch_config(target_path, filtered: false)
|
255
|
+
target = Utils.flatten(target_config, target_path)
|
230
256
|
|
231
|
-
|
232
|
-
|
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)
|
233
262
|
end
|
234
263
|
|
235
|
-
def run_diff_path(
|
236
|
-
raise(ArgumentError, "Missing required option --path") unless path
|
237
|
-
|
264
|
+
def run_diff_path(target_path, source_path)
|
238
265
|
source_config = fetch_config(source_path, filtered: false)
|
239
|
-
source = Utils.flatten(source_config
|
266
|
+
source = Utils.flatten(source_config)
|
267
|
+
|
268
|
+
target_config = fetch_config(target_path, filtered: false)
|
269
|
+
target = Utils.flatten(target_config)
|
240
270
|
|
241
|
-
|
242
|
-
|
271
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
272
|
+
puts "+++ #{provider}:#{source_path}#{Colors::CLEAR}"
|
243
273
|
|
244
|
-
|
245
|
-
diff_config(source, target)
|
274
|
+
diff_config(target, source)
|
246
275
|
end
|
247
276
|
|
248
277
|
def run_console
|
@@ -250,9 +279,22 @@ module SecretConfig
|
|
250
279
|
end
|
251
280
|
|
252
281
|
def run_delete(key)
|
282
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}"
|
283
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
253
284
|
provider_instance.delete(key)
|
254
285
|
end
|
255
286
|
|
287
|
+
def run_delete_tree(path)
|
288
|
+
source_config = fetch_config(path)
|
289
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}#{Colors::CLEAR}"
|
290
|
+
|
291
|
+
source = Utils.flatten(source_config, path)
|
292
|
+
source.each_key do |key|
|
293
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
294
|
+
provider_instance.delete(key)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
256
298
|
def run_fetch(key)
|
257
299
|
value = provider_instance.fetch(key)
|
258
300
|
puts value if value
|
@@ -262,8 +304,8 @@ module SecretConfig
|
|
262
304
|
provider_instance.set(key, value)
|
263
305
|
end
|
264
306
|
|
265
|
-
def current_values
|
266
|
-
|
307
|
+
def current_values(path)
|
308
|
+
Utils.flatten(fetch_config(path, filtered: false), path)
|
267
309
|
end
|
268
310
|
|
269
311
|
def read_config_file(file_name)
|
@@ -291,38 +333,53 @@ module SecretConfig
|
|
291
333
|
# Ignore filtered values
|
292
334
|
next
|
293
335
|
end
|
294
|
-
|
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
|
+
|
295
343
|
provider_instance.set(key, value)
|
296
344
|
end
|
297
345
|
end
|
298
346
|
|
299
347
|
def fetch_config(path, filtered: true)
|
300
|
-
registry = Registry.new(path: path, provider: provider_instance)
|
348
|
+
registry = Registry.new(path: path, provider: provider_instance, interpolate: interpolate)
|
301
349
|
config = filtered ? registry.configuration : registry.configuration(filters: nil)
|
302
350
|
sort_hash_by_key!(config)
|
303
351
|
end
|
304
352
|
|
305
353
|
# Diffs two configs and displays the results
|
306
|
-
def diff_config(
|
354
|
+
def diff_config(target, source)
|
307
355
|
(source.keys + target.keys).sort.uniq.each do |key|
|
308
356
|
if target.key?(key)
|
309
357
|
if source.key?(key)
|
310
358
|
value = source[key].to_s
|
311
359
|
# Ignore filtered values
|
312
|
-
|
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
|
313
365
|
else
|
314
|
-
puts "
|
366
|
+
puts "#{Colors::KEY}#{key}:"
|
367
|
+
puts "#{Colors::REMOVE}#{prefix_lines("- ", target[key])}\n\n"
|
315
368
|
end
|
316
369
|
elsif source.key?(key)
|
317
|
-
puts "
|
370
|
+
puts "#{Colors::KEY}#{key}:"
|
371
|
+
puts "#{Colors::ADD}#{prefix_lines("+ ", source[key])}#{Colors::CLEAR}\n\n"
|
318
372
|
end
|
319
373
|
end
|
320
374
|
end
|
321
375
|
|
322
|
-
def
|
323
|
-
|
376
|
+
def prefix_lines(prefix, value)
|
377
|
+
value.to_s.lines.collect { |line| "#{prefix}#{line}" }.join("")
|
378
|
+
end
|
324
379
|
|
325
|
-
|
380
|
+
def import_config(config, path, prune, force)
|
381
|
+
current = current_values(path)
|
382
|
+
delete_keys = prune ? current.keys - Utils.flatten(config, path).keys : []
|
326
383
|
|
327
384
|
unless delete_keys.empty?
|
328
385
|
puts "Going to delete the following keys:"
|
@@ -330,10 +387,10 @@ module SecretConfig
|
|
330
387
|
sleep(5)
|
331
388
|
end
|
332
389
|
|
333
|
-
set_config(config, path,
|
390
|
+
set_config(config, path, force ? {} : current)
|
334
391
|
|
335
392
|
delete_keys.each do |key|
|
336
|
-
puts "
|
393
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
337
394
|
provider_instance.delete(key)
|
338
395
|
end
|
339
396
|
end
|