secret_config 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -21
- data/bin/{secret_config → secret-config} +0 -0
- data/lib/secret_config/cli.rb +127 -91
- data/lib/secret_config/parser.rb +9 -8
- data/lib/secret_config/registry.rb +6 -5
- data/lib/secret_config/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcd736808cbbcc2366bd1e6f8ab87eedc17bbd45bae3492aa7f28b9d1c7be046
|
4
|
+
data.tar.gz: bcea91adfdfe4e3b0f57d78c4954b07e61234870d746aafddd35448ee524d298
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c12a1b4709b92c0db325f209ac36ca244bf8ac7acf518ff165ebdbbcb2a84a658c25cdee931c13e86ebba033e16998c7acd96e53e6da6021c086c350a1277c2
|
7
|
+
data.tar.gz: 87c131f25083a20a0850369704f36311d6ae6e25cc940ba76845a2fcc45cf758a00d513f8157c332defd402990eddd6fe65a3e22997b72e5693ccf147d21150a
|
data/README.md
CHANGED
@@ -5,6 +5,14 @@ Centralized Configuration and Secrets Management for Ruby and Rails applications
|
|
5
5
|
|
6
6
|
Securely store configuration information centrally, supporting multiple tenants of the same application.
|
7
7
|
|
8
|
+
## v0.9 Upgrade Notes
|
9
|
+
|
10
|
+
Note that the command line program name has changed from `secret_config` to `secret-config`.
|
11
|
+
Be careful that the arguments have also changed. The arguments are now consistent across operations.
|
12
|
+
The command line examples below have also been updated to reflect the changes.
|
13
|
+
|
14
|
+
Please run `secret-config --help` to see the new arguments and updated operations.
|
15
|
+
|
8
16
|
## Overview
|
9
17
|
|
10
18
|
Securely store centralized configuration information such as:
|
@@ -579,20 +587,26 @@ Available interpolations:
|
|
579
587
|
Secret Config has a command line interface for exporting, importing and copying between paths in the registry.
|
580
588
|
|
581
589
|
~~~
|
582
|
-
|
583
|
-
-e, --export
|
584
|
-
-i, --import
|
585
|
-
|
586
|
-
-
|
590
|
+
secret-config [options]
|
591
|
+
-e, --export SOURCE_PATH Export configuration. Use --file to specify the file name, otherwise stdout is used.
|
592
|
+
-i, --import TARGET_PATH Import configuration. Use --file to specify the file name, --path for the SOURCE_PATH, otherwise stdin is used.
|
593
|
+
--file FILE_NAME Import/Export/Diff to/from this file.
|
594
|
+
-p, --path PATH Import/Export/Diff to/from this path.
|
595
|
+
--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.
|
596
|
+
-s, --set KEY=VALUE Set one key to value. Example: --set mysql/database=localhost
|
597
|
+
-f, --fetch KEY Fetch the value for one setting. Example: --fetch mysql/database.
|
598
|
+
-d, --delete KEY Delete one specific key.
|
599
|
+
-r, --delete-tree PATH Recursively delete all keys under the specified path.
|
587
600
|
-c, --console Start interactive console.
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
601
|
+
--provider PROVIDER Provider to use. [ssm | file]. Default: ssm
|
602
|
+
--no-filter For --export only. Do not filter passwords and keys.
|
603
|
+
--interpolate For --export only. Evaluate string interpolation and __import__.
|
604
|
+
--prune For --import only. During import delete all existing keys for which there is no key in the import file. Only works with --import.
|
605
|
+
--force For --import only. Overwrite all values, not just the changed ones. Useful for changing the KMS key.
|
606
|
+
--key_id KEY_ID For --import only. Encrypt config settings with this AWS KMS key id. Default: AWS Default key.
|
607
|
+
--key_alias KEY_ALIAS For --import only. Encrypt config settings with this AWS KMS alias.
|
608
|
+
--random_size INTEGER For --import only. Size to use when generating random values when $(random) is encountered in the source. Default: 32
|
609
|
+
-v, --version Display Secret Config version.
|
596
610
|
-h, --help Prints this help.
|
597
611
|
~~~
|
598
612
|
|
@@ -624,18 +638,22 @@ secrets:
|
|
624
638
|
|
625
639
|
Import a yaml file, into a path in AWS SSM Parameter Store:
|
626
640
|
|
627
|
-
|
641
|
+
secret-config --import /production/my_application --path production.yml
|
628
642
|
|
629
643
|
Import a yaml file, into a path in AWS SSM Parameter Store, using a custom KMS key to encrypt the values:
|
630
644
|
|
631
|
-
|
645
|
+
secret-config --import /production/my_application --path production.yml --key_id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
646
|
+
|
647
|
+
Import a yaml file, into a path in AWS SSM Parameter Store, using a custom KMS key alias to encrypt the values:
|
648
|
+
|
649
|
+
secret-config --import /production/my_application --path production.yml --key_alias my_key_alias
|
632
650
|
|
633
651
|
#### Diff
|
634
652
|
|
635
653
|
Before importing a new config file into the AWS SSM Parameter store, a diff can be performed to determine
|
636
654
|
what the differences are that will be applied when the import is run with the `--prune` option.
|
637
655
|
|
638
|
-
|
656
|
+
secret-config --diff /production/my_application --path production.yml
|
639
657
|
|
640
658
|
Key:
|
641
659
|
|
@@ -650,15 +668,15 @@ Export the values from a specific path into a yaml or json file so that they are
|
|
650
668
|
|
651
669
|
Export from a path in AWS SSM Parameter Store to a yaml file, where passwords are filtered:
|
652
670
|
|
653
|
-
|
671
|
+
secret-config --export /production/my_application --file production.yml
|
654
672
|
|
655
673
|
Export from a path in AWS SSM Parameter Store to a yaml file, _without_ filtering out passwords:
|
656
674
|
|
657
|
-
|
675
|
+
secret-config --export /production/my_application --file production.yml --no-filter
|
658
676
|
|
659
677
|
Export from a path in AWS SSM Parameter Store to a json file, where passwords are filtered:
|
660
678
|
|
661
|
-
|
679
|
+
secret-config --export /production/my_application --file production.json
|
662
680
|
|
663
681
|
#### Copy values between paths in AWS SSM parameter store
|
664
682
|
|
@@ -666,9 +684,9 @@ It can be useful to keep a "master" copy of the values for an environment or sta
|
|
666
684
|
in AWS Parameter Store. Then for each stack or environment that is spun up, copy the "master" / "common" values
|
667
685
|
into the new path. Once copied the values specific to that path can be updated accordingly.
|
668
686
|
|
669
|
-
|
687
|
+
Import configuration from an existing path in AWS SSM Parameter Store into another:
|
670
688
|
|
671
|
-
|
689
|
+
secret-config --import /tenant73/my_application --path /production/my_application
|
672
690
|
|
673
691
|
#### Generating random passwords
|
674
692
|
|
File without changes
|
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
|
|
@@ -198,57 +217,55 @@ module SecretConfig
|
|
198
217
|
end
|
199
218
|
end
|
200
219
|
|
201
|
-
def run_export(
|
202
|
-
|
220
|
+
def run_export(source_path, file_name, filtered: true)
|
221
|
+
puts("Exporting #{provider}:#{source_path} to #{file_name}") if file_name.is_a?(String)
|
203
222
|
|
204
|
-
config = fetch_config(
|
223
|
+
config = fetch_config(source_path, filtered: filtered)
|
205
224
|
write_config_file(file_name, config)
|
206
|
-
|
207
|
-
puts("Exported #{path} from #{provider} to #{file_name}") if file_name.is_a?(String)
|
208
225
|
end
|
209
226
|
|
210
|
-
def run_import(
|
211
|
-
|
212
|
-
|
227
|
+
def run_import(target_path, file_name, prune, force)
|
228
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
229
|
+
puts "+++ #{file_name}#{Colors::CLEAR}"
|
213
230
|
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)
|
231
|
+
import_config(config, target_path, prune, force)
|
217
232
|
end
|
218
233
|
|
219
|
-
def run_import_path(
|
220
|
-
|
234
|
+
def run_import_path(target_path, source_path, prune, force)
|
235
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
236
|
+
puts "+++ #{provider}:#{source_path}#{Colors::CLEAR}"
|
221
237
|
|
222
238
|
config = fetch_config(source_path, filtered: false)
|
223
|
-
import_config(config,
|
239
|
+
import_config(config, target_path, prune, force)
|
224
240
|
|
225
|
-
puts("Imported #{
|
241
|
+
puts("Imported #{target_path} from #{source_path} on provider: #{provider}")
|
226
242
|
end
|
227
243
|
|
228
|
-
def run_diff(
|
229
|
-
|
244
|
+
def run_diff(target_path, file_name)
|
245
|
+
source_config = read_config_file(file_name)
|
246
|
+
source = Utils.flatten(source_config, target_path)
|
230
247
|
|
231
|
-
|
232
|
-
|
248
|
+
target_config = fetch_config(target_path, filtered: false)
|
249
|
+
target = Utils.flatten(target_config, target_path)
|
233
250
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
diff_config(
|
251
|
+
if file_name.is_a?(String)
|
252
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
253
|
+
puts "+++ #{file_name}#{Colors::CLEAR}"
|
254
|
+
end
|
255
|
+
diff_config(target, source)
|
239
256
|
end
|
240
257
|
|
241
|
-
def run_diff_path(
|
242
|
-
raise(ArgumentError, "Missing required option --path") unless path
|
243
|
-
|
258
|
+
def run_diff_path(target_path, source_path)
|
244
259
|
source_config = fetch_config(source_path, filtered: false)
|
245
260
|
source = Utils.flatten(source_config)
|
246
261
|
|
247
|
-
target_config = fetch_config(
|
262
|
+
target_config = fetch_config(target_path, filtered: false)
|
248
263
|
target = Utils.flatten(target_config)
|
249
264
|
|
250
|
-
puts
|
251
|
-
|
265
|
+
puts "#{Colors::TITLE}--- #{provider}:#{target_path}"
|
266
|
+
puts "+++ #{provider}:#{source_path}#{Colors::CLEAR}"
|
267
|
+
|
268
|
+
diff_config(target, source)
|
252
269
|
end
|
253
270
|
|
254
271
|
def run_console
|
@@ -256,14 +273,18 @@ module SecretConfig
|
|
256
273
|
end
|
257
274
|
|
258
275
|
def run_delete(key)
|
276
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}"
|
277
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
259
278
|
provider_instance.delete(key)
|
260
279
|
end
|
261
280
|
|
262
|
-
def
|
281
|
+
def run_delete_tree(path)
|
263
282
|
source_config = fetch_config(path)
|
264
|
-
|
283
|
+
puts "#{Colors::TITLE}--- #{provider}:#{path}#{Colors::CLEAR}"
|
284
|
+
|
285
|
+
source = Utils.flatten(source_config, path)
|
265
286
|
source.each_key do |key|
|
266
|
-
puts
|
287
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
267
288
|
provider_instance.delete(key)
|
268
289
|
end
|
269
290
|
end
|
@@ -277,8 +298,8 @@ module SecretConfig
|
|
277
298
|
provider_instance.set(key, value)
|
278
299
|
end
|
279
300
|
|
280
|
-
def current_values
|
281
|
-
|
301
|
+
def current_values(path)
|
302
|
+
Utils.flatten(fetch_config(path, filtered: false), path)
|
282
303
|
end
|
283
304
|
|
284
305
|
def read_config_file(file_name)
|
@@ -306,38 +327,53 @@ module SecretConfig
|
|
306
327
|
# Ignore filtered values
|
307
328
|
next
|
308
329
|
end
|
309
|
-
|
330
|
+
|
331
|
+
if current_values.key?(key)
|
332
|
+
puts "#{Colors::KEY}* #{key}#{Colors::CLEAR}"
|
333
|
+
else
|
334
|
+
puts "#{Colors::ADD}+ #{key}#{Colors::CLEAR}"
|
335
|
+
end
|
336
|
+
|
310
337
|
provider_instance.set(key, value)
|
311
338
|
end
|
312
339
|
end
|
313
340
|
|
314
341
|
def fetch_config(path, filtered: true)
|
315
|
-
registry = Registry.new(path: path, provider: provider_instance)
|
342
|
+
registry = Registry.new(path: path, provider: provider_instance, interpolate: interpolate)
|
316
343
|
config = filtered ? registry.configuration : registry.configuration(filters: nil)
|
317
344
|
sort_hash_by_key!(config)
|
318
345
|
end
|
319
346
|
|
320
347
|
# Diffs two configs and displays the results
|
321
|
-
def diff_config(
|
348
|
+
def diff_config(target, source)
|
322
349
|
(source.keys + target.keys).sort.uniq.each do |key|
|
323
350
|
if target.key?(key)
|
324
351
|
if source.key?(key)
|
325
352
|
value = source[key].to_s
|
326
353
|
# Ignore filtered values
|
327
|
-
|
354
|
+
if (value != target[key].to_s) && (value != FILTERED)
|
355
|
+
puts "#{Colors::KEY}#{key}:"
|
356
|
+
puts "#{Colors::REMOVE}#{prefix_lines("- ", target[key])}"
|
357
|
+
puts "#{Colors::ADD}#{prefix_lines("+ ", source[key])}#{Colors::CLEAR}\n\n"
|
358
|
+
end
|
328
359
|
else
|
329
|
-
puts "
|
360
|
+
puts "#{Colors::KEY}#{key}:"
|
361
|
+
puts "#{Colors::REMOVE}#{prefix_lines("- ", target[key])}\n\n"
|
330
362
|
end
|
331
363
|
elsif source.key?(key)
|
332
|
-
puts "
|
364
|
+
puts "#{Colors::KEY}#{key}:"
|
365
|
+
puts "#{Colors::ADD}#{prefix_lines("+ ", source[key])}#{Colors::CLEAR}\n\n"
|
333
366
|
end
|
334
367
|
end
|
335
368
|
end
|
336
369
|
|
337
|
-
def
|
338
|
-
|
370
|
+
def prefix_lines(prefix, value)
|
371
|
+
value.to_s.lines.collect { |line| "#{prefix}#{line}" }.join("")
|
372
|
+
end
|
339
373
|
|
340
|
-
|
374
|
+
def import_config(config, path, prune, force)
|
375
|
+
current = current_values(path)
|
376
|
+
delete_keys = prune ? current.keys - Utils.flatten(config, path).keys : []
|
341
377
|
|
342
378
|
unless delete_keys.empty?
|
343
379
|
puts "Going to delete the following keys:"
|
@@ -345,10 +381,10 @@ module SecretConfig
|
|
345
381
|
sleep(5)
|
346
382
|
end
|
347
383
|
|
348
|
-
set_config(config, path, force ? {} :
|
384
|
+
set_config(config, path, force ? {} : current)
|
349
385
|
|
350
386
|
delete_keys.each do |key|
|
351
|
-
puts "
|
387
|
+
puts "#{Colors::REMOVE}- #{key}#{Colors::CLEAR}"
|
352
388
|
provider_instance.delete(key)
|
353
389
|
end
|
354
390
|
end
|
data/lib/secret_config/parser.rb
CHANGED
@@ -2,26 +2,26 @@ module SecretConfig
|
|
2
2
|
class Parser
|
3
3
|
attr_reader :tree, :path, :registry, :interpolator
|
4
4
|
|
5
|
-
def initialize(path, registry)
|
5
|
+
def initialize(path, registry, interpolate: true)
|
6
6
|
@path = path
|
7
7
|
@registry = registry
|
8
8
|
@fetch_list = {}
|
9
9
|
@import_list = {}
|
10
10
|
@tree = {}
|
11
|
-
@interpolator = SettingInterpolator.new
|
11
|
+
@interpolator = interpolate ? SettingInterpolator.new : nil
|
12
12
|
end
|
13
13
|
|
14
14
|
# Returns a flat path of keys and values from the provider without looking in the local path.
|
15
15
|
# Keys are returned with path names relative to the supplied path.
|
16
16
|
def parse(key, value)
|
17
17
|
relative_key = relative_key?(key) ? key : key.sub("#{path}/", "")
|
18
|
-
|
18
|
+
value = interpolator.parse(value) if interpolator && value.is_a?(String) && value.include?("%{")
|
19
|
+
tree[relative_key] = value
|
19
20
|
end
|
20
21
|
|
21
22
|
# Returns a flat Hash of the rendered paths.
|
22
23
|
def render
|
23
|
-
|
24
|
-
apply_imports
|
24
|
+
apply_imports if interpolator
|
25
25
|
tree
|
26
26
|
end
|
27
27
|
|
@@ -38,10 +38,11 @@ module SecretConfig
|
|
38
38
|
# - Imports cannot reference other imports at this time.
|
39
39
|
def apply_imports
|
40
40
|
tree.keys.each do |key|
|
41
|
-
next unless key =~ /\/__import__\Z/
|
41
|
+
next unless (key =~ /\/__import__\Z/) || (key == "__import__")
|
42
42
|
|
43
43
|
import_key = tree.delete(key)
|
44
44
|
key, _ = ::File.split(key)
|
45
|
+
key = nil if key == "."
|
45
46
|
|
46
47
|
# binding.irb
|
47
48
|
|
@@ -53,13 +54,13 @@ module SecretConfig
|
|
53
54
|
match = current_key.match(/\A#{import_key}\/(.*)/)
|
54
55
|
next unless match
|
55
56
|
|
56
|
-
imported_key = ::File.join(key, match[1])
|
57
|
+
imported_key = key.nil? ? match[1] : ::File.join(key, match[1])
|
57
58
|
tree[imported_key] = tree[current_key] unless tree.key?(imported_key)
|
58
59
|
end
|
59
60
|
else
|
60
61
|
relative_paths = registry.send(:fetch_path, import_key)
|
61
62
|
relative_paths.each_pair do |relative_key, value|
|
62
|
-
imported_key = ::File.join(key, relative_key)
|
63
|
+
imported_key = key.nil? ? relative_key : ::File.join(key, relative_key)
|
63
64
|
tree[imported_key] = value unless tree.key?(imported_key)
|
64
65
|
end
|
65
66
|
end
|
@@ -4,18 +4,19 @@ require "concurrent-ruby"
|
|
4
4
|
module SecretConfig
|
5
5
|
# Centralized configuration with values stored in AWS System Manager Parameter Store
|
6
6
|
class Registry
|
7
|
-
attr_reader :provider
|
7
|
+
attr_reader :provider, :interpolate
|
8
8
|
attr_accessor :path
|
9
9
|
|
10
|
-
def initialize(path: nil, provider: nil, provider_args: nil)
|
10
|
+
def initialize(path: nil, provider: nil, provider_args: nil, interpolate: true)
|
11
11
|
@path = default_path(path)
|
12
12
|
raise(UndefinedRootError, "Root must start with /") unless @path.start_with?("/")
|
13
13
|
|
14
14
|
resolved_provider = default_provider(provider)
|
15
15
|
provider_args = nil if resolved_provider != provider
|
16
16
|
|
17
|
-
@provider
|
18
|
-
@cache
|
17
|
+
@provider = create_provider(resolved_provider, provider_args)
|
18
|
+
@cache = Concurrent::Map.new
|
19
|
+
@interpolate = interpolate
|
19
20
|
refresh!
|
20
21
|
end
|
21
22
|
|
@@ -115,7 +116,7 @@ module SecretConfig
|
|
115
116
|
# Returns a flat path of keys and values from the provider without looking in the local path.
|
116
117
|
# Keys are returned with path names relative to the supplied path.
|
117
118
|
def fetch_path(path)
|
118
|
-
parser = Parser.new(path, self)
|
119
|
+
parser = Parser.new(path, self, interpolate: interpolate)
|
119
120
|
provider.each(path) { |key, value| parser.parse(key, value) }
|
120
121
|
parser.render
|
121
122
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secret_config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -28,14 +28,14 @@ description:
|
|
28
28
|
email:
|
29
29
|
- reidmo@gmail.com
|
30
30
|
executables:
|
31
|
-
-
|
31
|
+
- secret-config
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
35
|
- LICENSE
|
36
36
|
- README.md
|
37
37
|
- Rakefile
|
38
|
-
- bin/
|
38
|
+
- bin/secret-config
|
39
39
|
- lib/secret_config.rb
|
40
40
|
- lib/secret_config/cli.rb
|
41
41
|
- lib/secret_config/config.rb
|