secret_config 0.8.0 → 0.9.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 +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
|