chamber 2.2.1 → 2.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 +4 -4
- data/lib/chamber/commands/heroku/compare.rb +2 -2
- data/lib/chamber/commands/securable.rb +17 -9
- data/lib/chamber/commands/secure.rb +1 -3
- data/lib/chamber/file.rb +13 -2
- data/lib/chamber/file_set.rb +1 -1
- data/lib/chamber/filters/boolean_conversion_filter.rb +0 -2
- data/lib/chamber/filters/decryption_filter.rb +14 -16
- data/lib/chamber/filters/insecure_filter.rb +29 -0
- data/lib/chamber/filters/translate_secure_keys_filter.rb +54 -0
- data/lib/chamber/settings.rb +89 -21
- data/lib/chamber/version.rb +1 -1
- data/spec/lib/chamber/commands/secure_spec.rb +14 -10
- data/spec/lib/chamber/commands/show_spec.rb +1 -1
- data/spec/lib/chamber/file_spec.rb +57 -1
- data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +2 -0
- data/spec/lib/chamber/filters/decryption_filter_spec.rb +4 -4
- data/spec/lib/chamber/filters/insecure_filter_spec.rb +54 -0
- data/spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb +29 -0
- data/spec/lib/chamber/settings_spec.rb +112 -33
- metadata +17 -14
- data/lib/chamber/system_environment.rb +0 -55
- data/spec/lib/chamber/system_environment_spec.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e00049d9950a63a991be3de4cec30e8afd9f3ed9
|
4
|
+
data.tar.gz: ef49dca6ba236376806c878ebe462170e7317259
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efcee15432655ae9ac0ccf3ec639b7520506159cb237868abb8a365c56108727ec6e964140584f09b29dc65da3de302a7157d6d56dab23d92d3bd964bacb0a3d
|
7
|
+
data.tar.gz: 34148d8932aad7777144b425999ea93eee32f0615450eb50f207754b5a29b7125b4b22c27898d8b1e5970782bc972e9b99cf2ba6bc606414a72f476e581f2f52
|
@@ -17,8 +17,8 @@ class Compare < Chamber::Commands::Base
|
|
17
17
|
secured_settings.to_s(pair_separator: "\n",
|
18
18
|
value_surrounder: '')
|
19
19
|
else
|
20
|
-
|
21
|
-
|
20
|
+
current_settings.to_s(pair_separator: "\n",
|
21
|
+
value_surrounder: '')
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -12,7 +12,7 @@ module Securable
|
|
12
12
|
merge(files: ignored_settings_filepaths).
|
13
13
|
reject { |k, v| k == 'basepath' }
|
14
14
|
self.ignored_settings_instance = Chamber::Instance.new(ignored_settings_options)
|
15
|
-
self.
|
15
|
+
self.current_settings_instance = Chamber::Instance.new(options)
|
16
16
|
self.only_sensitive = options[:only_sensitive]
|
17
17
|
end
|
18
18
|
|
@@ -20,28 +20,36 @@ module Securable
|
|
20
20
|
|
21
21
|
attr_accessor :only_sensitive,
|
22
22
|
:ignored_settings_instance,
|
23
|
-
:
|
23
|
+
:current_settings_instance
|
24
24
|
|
25
25
|
def securable_environment_variables
|
26
26
|
if only_sensitive
|
27
|
-
|
27
|
+
securable_settings.to_environment
|
28
28
|
else
|
29
|
-
|
29
|
+
current_settings.to_environment
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
33
|
+
def insecure_environment_variables
|
34
|
+
securable_settings.insecure.to_environment
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
|
37
|
+
def securable_settings
|
38
|
+
ignored_settings.merge(current_settings.securable)
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_settings
|
42
|
+
current_settings_instance.settings
|
43
|
+
end
|
44
|
+
|
45
|
+
def ignored_settings
|
46
|
+
ignored_settings_instance.settings
|
39
47
|
end
|
40
48
|
|
41
49
|
def ignored_settings_filepaths
|
42
50
|
shell_escaped_chamber_filenames = chamber.filenames.map { |filename| Shellwords.escape(filename) }
|
43
51
|
|
44
|
-
`git ls-files --other --ignored --exclude-from=.gitignore | sed -e "s|^|#{Shellwords.escape(rootpath)}/|" | grep --colour=never -E '#{shell_escaped_chamber_filenames.join('|')}'`.split("\n")
|
52
|
+
`git ls-files --other --ignored --exclude-from=.gitignore | sed -e "s|^|#{Shellwords.escape(rootpath.to_s)}/|" | grep --colour=never -E '#{shell_escaped_chamber_filenames.join('|')}'`.split("\n")
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
@@ -11,9 +11,7 @@ class Secure < Chamber::Commands::Base
|
|
11
11
|
|
12
12
|
def call
|
13
13
|
disable_warnings do
|
14
|
-
|
15
|
-
next if value.match %r{\A[A-Za-z0-9\+\/]{342}==\z}
|
16
|
-
|
14
|
+
insecure_environment_variables.each do |key, value|
|
17
15
|
if dry_run
|
18
16
|
shell.say_status 'encrypt', key, :blue
|
19
17
|
else
|
data/lib/chamber/file.rb
CHANGED
@@ -71,9 +71,20 @@ class File < Pathname
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def secure
|
74
|
-
|
74
|
+
insecure_settings = to_settings.insecure.to_flattened_name_hash
|
75
|
+
secure_settings = to_settings.insecure.secure.to_flattened_name_hash
|
76
|
+
file_contents = self.read
|
75
77
|
|
76
|
-
|
78
|
+
insecure_settings.each_pair do |name_pieces, value|
|
79
|
+
secure_value = secure_settings[name_pieces]
|
80
|
+
|
81
|
+
file_contents.
|
82
|
+
sub!(
|
83
|
+
/^(\s*)_secure_#{name_pieces.last}(\s*):(\s*)['"]?#{value}['"]?$/,
|
84
|
+
"\\1_secure_#{name_pieces.last}\\2:\\3#{secure_value}")
|
85
|
+
end
|
86
|
+
|
87
|
+
self.write(file_contents)
|
77
88
|
end
|
78
89
|
|
79
90
|
protected
|
data/lib/chamber/file_set.rb
CHANGED
@@ -29,24 +29,22 @@ class DecryptionFilter
|
|
29
29
|
raw_data.each_pair do |key, value|
|
30
30
|
if value.respond_to? :each_pair
|
31
31
|
value = execute(value)
|
32
|
-
elsif value.respond_to?
|
33
|
-
if
|
34
|
-
|
35
|
-
value = if value.match(BASE64_STRING_PATTERN)
|
36
|
-
if decryption_key.nil?
|
37
|
-
value
|
38
|
-
else
|
39
|
-
decoded_string = Base64.strict_decode64(value)
|
40
|
-
decryption_key.private_decrypt(decoded_string)
|
41
|
-
end
|
42
|
-
else
|
43
|
-
warn "WARNING: It appears that you would like to keep your information for #{key} secure, however the value for that setting does not appear to be encrypted. Make sure you run 'chamber settings secure' before committing."
|
44
|
-
|
32
|
+
elsif key.match(SECURE_KEY_TOKEN) && value.respond_to?(:match)
|
33
|
+
value = if value.match(BASE64_STRING_PATTERN)
|
34
|
+
if decryption_key.nil?
|
45
35
|
value
|
36
|
+
else
|
37
|
+
decoded_string = Base64.strict_decode64(value)
|
38
|
+
decryption_key.private_decrypt(decoded_string)
|
46
39
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
40
|
+
else
|
41
|
+
warn 'WARNING: It appears that you would like to keep your ' \
|
42
|
+
"information for #{key} secure, however the value for that " \
|
43
|
+
'setting does not appear to be encrypted. Make sure you run ' \
|
44
|
+
"'chamber secure' before committing."
|
45
|
+
|
46
|
+
value
|
47
|
+
end
|
50
48
|
end
|
51
49
|
|
52
50
|
settings[key] = value
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
require 'chamber/filters/secure_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
class InsecureFilter < SecureFilter
|
7
|
+
BASE64 = %r{\A[A-Za-z0-9\+\/]{342}==\z}
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def execute(raw_data = data)
|
12
|
+
securable_settings = super
|
13
|
+
settings = Hashie::Mash.new
|
14
|
+
|
15
|
+
securable_settings.each_pair do |key, value|
|
16
|
+
value = if value.respond_to? :each_pair
|
17
|
+
execute(value)
|
18
|
+
elsif value.respond_to? :match
|
19
|
+
value unless value.match(BASE64)
|
20
|
+
end
|
21
|
+
|
22
|
+
settings[key] = value unless value.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
settings
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
require 'chamber/errors/undecryptable_value_error'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
class TranslateSecureKeysFilter
|
7
|
+
SECURE_KEY_TOKEN = %r{\A_secure_}
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
self.data = options.fetch(:data).dup
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.execute(options = {})
|
14
|
+
self.new(options).send(:execute)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
attr_accessor :data
|
20
|
+
|
21
|
+
def execute(raw_data = data)
|
22
|
+
settings = Hashie::Mash.new
|
23
|
+
|
24
|
+
raw_data.each_pair do |key, value|
|
25
|
+
if value.respond_to? :each_pair
|
26
|
+
value = execute(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
key = key.to_s
|
30
|
+
|
31
|
+
if key.match(SECURE_KEY_TOKEN)
|
32
|
+
key = key.sub(SECURE_KEY_TOKEN, '')
|
33
|
+
end
|
34
|
+
|
35
|
+
settings[key] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
settings
|
39
|
+
end
|
40
|
+
|
41
|
+
def decryption_key=(keyish)
|
42
|
+
return @decryption_key = nil if keyish.nil?
|
43
|
+
|
44
|
+
key_content = if ::File.readable?(::File.expand_path(keyish))
|
45
|
+
::File.read(::File.expand_path(keyish))
|
46
|
+
else
|
47
|
+
keyish
|
48
|
+
end
|
49
|
+
|
50
|
+
@decryption_key = OpenSSL::PKey::RSA.new(key_content)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/chamber/settings.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'hashie/mash'
|
2
|
-
require 'chamber/system_environment'
|
3
2
|
require 'chamber/namespace_set'
|
4
3
|
require 'chamber/filters/namespace_filter'
|
5
4
|
require 'chamber/filters/encryption_filter'
|
@@ -7,6 +6,8 @@ require 'chamber/filters/decryption_filter'
|
|
7
6
|
require 'chamber/filters/environment_filter'
|
8
7
|
require 'chamber/filters/boolean_conversion_filter'
|
9
8
|
require 'chamber/filters/secure_filter'
|
9
|
+
require 'chamber/filters/translate_secure_keys_filter'
|
10
|
+
require 'chamber/filters/insecure_filter'
|
10
11
|
|
11
12
|
###
|
12
13
|
# Internal: Represents the base settings storage needed for Chamber.
|
@@ -26,6 +27,7 @@ class Settings
|
|
26
27
|
]
|
27
28
|
self.post_filters = options[:post_filters] || [
|
28
29
|
Filters::DecryptionFilter,
|
30
|
+
Filters::TranslateSecureKeysFilter,
|
29
31
|
Filters::EnvironmentFilter,
|
30
32
|
Filters::BooleanConversionFilter,
|
31
33
|
]
|
@@ -53,7 +55,9 @@ class Settings
|
|
53
55
|
# Returns a Hash sorted alphabetically by the names of the keys
|
54
56
|
#
|
55
57
|
def to_environment
|
56
|
-
|
58
|
+
to_concatenated_name_hash('_').each_with_object({}) do |pair, env_hash|
|
59
|
+
env_hash[pair[0].upcase] = pair[1].to_s
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
63
|
###
|
@@ -69,17 +73,85 @@ class Settings
|
|
69
73
|
# # => 'MY_KEY="my value" MY_OTHER_KEY="my other value"'
|
70
74
|
#
|
71
75
|
def to_s(options = {})
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
hierarchical_separator = options[:hierarchical_separator] || '_'
|
77
|
+
pair_separator = options[:pair_separator] || ' '
|
78
|
+
value_surrounder = options[:value_surrounder] || '"'
|
79
|
+
name_value_separator = options[:name_value_separator] || '='
|
80
|
+
|
81
|
+
concatenated_name_hash = to_concatenated_name_hash(hierarchical_separator)
|
75
82
|
|
76
|
-
pairs =
|
77
|
-
%Q{#{
|
83
|
+
pairs = concatenated_name_hash.to_a.map do |key, value|
|
84
|
+
%Q{#{key.upcase}#{name_value_separator}#{value_surrounder}#{value}#{value_surrounder}}
|
78
85
|
end
|
79
86
|
|
80
87
|
pairs.join(pair_separator)
|
81
88
|
end
|
82
89
|
|
90
|
+
###
|
91
|
+
# Internal: Returns the Settings data as a Hash for easy manipulation.
|
92
|
+
# Changes made to the hash will *not* be reflected in the original Settings
|
93
|
+
# object.
|
94
|
+
#
|
95
|
+
# Returns a Hash
|
96
|
+
#
|
97
|
+
def to_hash
|
98
|
+
data.to_hash
|
99
|
+
end
|
100
|
+
|
101
|
+
###
|
102
|
+
# Internal: Returns a hash which contains the flattened name hierarchy of the
|
103
|
+
# setting as the keys and the values of each setting as the value.
|
104
|
+
#
|
105
|
+
# Examples:
|
106
|
+
# Settings.new(settings: {
|
107
|
+
# my_setting: 'value',
|
108
|
+
# there: 'was not that easy?',
|
109
|
+
# level_1: {
|
110
|
+
# level_2: {
|
111
|
+
# some_setting: 'hello',
|
112
|
+
# another: 'goodbye',
|
113
|
+
# },
|
114
|
+
# body: 'gracias',
|
115
|
+
# },
|
116
|
+
# }).to_flattened_name_hash
|
117
|
+
# # => {
|
118
|
+
# ['my_setting'] => 'value',
|
119
|
+
# ['there'] => 'was not that easy?',
|
120
|
+
# ['level_1', 'level_2', 'some_setting'] => 'hello',
|
121
|
+
# ['level_1', 'level_2', 'another'] => 'goodbye',
|
122
|
+
# ['level_1', 'body'] => 'gracias',
|
123
|
+
# }
|
124
|
+
#
|
125
|
+
# Returns a Hash
|
126
|
+
#
|
127
|
+
def to_flattened_name_hash(hash = data, parent_keys = [])
|
128
|
+
flattened_name_hash = {}
|
129
|
+
|
130
|
+
hash.each_pair do |key, value|
|
131
|
+
flattened_name_components = parent_keys.dup.push(key)
|
132
|
+
|
133
|
+
if value.respond_to?(:each_pair)
|
134
|
+
flattened_name_hash.merge! to_flattened_name_hash(value, flattened_name_components)
|
135
|
+
else
|
136
|
+
flattened_name_hash[flattened_name_components] = value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
flattened_name_hash
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_concatenated_name_hash(hierarchical_separator = '_')
|
144
|
+
concatenated_name_hash = {}
|
145
|
+
|
146
|
+
to_flattened_name_hash.each_pair do |flattened_name, value|
|
147
|
+
concatenated_name = flattened_name.join(hierarchical_separator)
|
148
|
+
|
149
|
+
concatenated_name_hash[concatenated_name] = value
|
150
|
+
end
|
151
|
+
|
152
|
+
concatenated_name_hash.sort
|
153
|
+
end
|
154
|
+
|
83
155
|
###
|
84
156
|
# Internal: Merges a Settings object with another Settings object or
|
85
157
|
# a hash-like object.
|
@@ -115,17 +187,6 @@ class Settings
|
|
115
187
|
settings: raw_data.merge(other_settings.raw_data))
|
116
188
|
end
|
117
189
|
|
118
|
-
###
|
119
|
-
# Internal: Returns the Settings data as a Hash for easy manipulation.
|
120
|
-
# Changes made to the hash will *not* be reflected in the original Settings
|
121
|
-
# object.
|
122
|
-
#
|
123
|
-
# Returns a Hash
|
124
|
-
#
|
125
|
-
def to_hash
|
126
|
-
data.to_hash
|
127
|
-
end
|
128
|
-
|
129
190
|
###
|
130
191
|
# Internal: Determines whether a Settings is equal to another hash-like
|
131
192
|
# object.
|
@@ -147,7 +208,7 @@ class Settings
|
|
147
208
|
self.namespaces == other.namespaces
|
148
209
|
end
|
149
210
|
|
150
|
-
def
|
211
|
+
def securable
|
151
212
|
Settings.new( metadata.merge(
|
152
213
|
settings: raw_data,
|
153
214
|
pre_filters: [Filters::SecureFilter]))
|
@@ -155,9 +216,16 @@ class Settings
|
|
155
216
|
|
156
217
|
def secure
|
157
218
|
Settings.new( metadata.merge(
|
158
|
-
settings:
|
219
|
+
settings: raw_data,
|
159
220
|
pre_filters: [Filters::EncryptionFilter],
|
160
|
-
post_filters: [] ))
|
221
|
+
post_filters: [Filters::TranslateSecureKeysFilter] ))
|
222
|
+
end
|
223
|
+
|
224
|
+
def insecure
|
225
|
+
Settings.new( metadata.merge(
|
226
|
+
settings: raw_data,
|
227
|
+
pre_filters: [Filters::InsecureFilter],
|
228
|
+
post_filters: [Filters::TranslateSecureKeysFilter] ))
|
161
229
|
end
|
162
230
|
|
163
231
|
protected
|
data/lib/chamber/version.rb
CHANGED
@@ -5,27 +5,31 @@ require 'fileutils'
|
|
5
5
|
module Chamber
|
6
6
|
module Commands
|
7
7
|
describe Secure do
|
8
|
-
let(:rootpath)
|
9
|
-
let(:
|
10
|
-
let(:
|
8
|
+
let(:rootpath) { Pathname.new(::File.expand_path('./spec/fixtures')) }
|
9
|
+
let(:settings_directory) { rootpath + 'settings' }
|
10
|
+
let(:settings_filename) { settings_directory + 'unencrypted.yml' }
|
11
|
+
let(:options) { { basepath: rootpath,
|
11
12
|
rootpath: rootpath,
|
12
13
|
encryption_key: rootpath + '../spec_key',
|
13
14
|
shell: double.as_null_object } }
|
14
15
|
|
16
|
+
before(:each) do
|
17
|
+
::FileUtils.mkdir_p settings_directory unless ::File.exist? settings_directory
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:each) do
|
21
|
+
::FileUtils.rm_rf(settings_directory) if ::File.exist? settings_directory
|
22
|
+
end
|
23
|
+
|
15
24
|
it 'can return values formatted as environment variables' do
|
16
|
-
|
17
|
-
::File.open(settings_filename, 'w') do |file|
|
18
|
-
file.write <<-HEREDOC
|
25
|
+
settings_filename.write <<-HEREDOC
|
19
26
|
test:
|
20
27
|
_secure_my_unencrpyted_setting: hello
|
21
28
|
HEREDOC
|
22
|
-
end
|
23
29
|
|
24
30
|
Secure.call(options)
|
25
31
|
|
26
|
-
expect(
|
27
|
-
|
28
|
-
::File.delete(settings_filename)
|
32
|
+
expect(settings_filename.read).to match %r{_secure_my_unencrpyted_setting: [A-Za-z0-9\+\/]{342}==}
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -12,8 +12,8 @@ describe Show do
|
|
12
12
|
it 'can return values formatted as environment variables' do
|
13
13
|
expect(Show.call(options.merge(as_env: true))).to eql(
|
14
14
|
<<-HEREDOC.chomp
|
15
|
-
ANOTHER_LEVEL_LEVEL_THREE_AN_ARRAY="["item 1", "item 2", "item 3"]"
|
16
15
|
ANOTHER_LEVEL_LEVEL_THREE_A_SCALAR="hello"
|
16
|
+
ANOTHER_LEVEL_LEVEL_THREE_AN_ARRAY="["item 1", "item 2", "item 3"]"
|
17
17
|
ANOTHER_LEVEL_SETTING_ONE="1"
|
18
18
|
ANOTHER_LEVEL_SETTING_TWO="2"
|
19
19
|
MY_BOOLEAN="false"
|
@@ -103,7 +103,9 @@ describe File do
|
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'can securely encrypt the settings contained in a file' do
|
106
|
-
tempfile = create_tempfile_with_content
|
106
|
+
tempfile = create_tempfile_with_content <<-HEREDOC
|
107
|
+
_secure_setting: hello
|
108
|
+
HEREDOC
|
107
109
|
settings_file = File.new path: tempfile.path,
|
108
110
|
encryption_key: './spec/spec_key.pub'
|
109
111
|
|
@@ -113,5 +115,59 @@ describe File do
|
|
113
115
|
|
114
116
|
expect(settings_file.to_settings.send(:raw_data)['_secure_setting']).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
115
117
|
end
|
118
|
+
|
119
|
+
it 'does not encrypt the settings contained in a file which are already secure' do
|
120
|
+
tempfile = create_tempfile_with_content <<-HEREDOC
|
121
|
+
_secure_setting: hello
|
122
|
+
_secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
|
123
|
+
HEREDOC
|
124
|
+
|
125
|
+
settings_file = File.new path: tempfile.path,
|
126
|
+
encryption_key: './spec/spec_key.pub'
|
127
|
+
|
128
|
+
settings_file.secure
|
129
|
+
|
130
|
+
settings_file = File.new path: tempfile.path
|
131
|
+
|
132
|
+
expect(settings_file.to_settings.send(:raw_data)['_secure_setting']).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
133
|
+
expect(settings_file.to_settings.send(:raw_data)['_secure_other_setting']).to eql "g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw=="
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'does not rewrite the entire file but only the encrypted settings' do
|
137
|
+
tempfile = create_tempfile_with_content <<-HEREDOC
|
138
|
+
default:
|
139
|
+
stuff: &default
|
140
|
+
_secure_setting: hello
|
141
|
+
_secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
|
142
|
+
|
143
|
+
other:
|
144
|
+
stuff:
|
145
|
+
<<: *default
|
146
|
+
_secure_another_setting: "Thanks for all the fish"
|
147
|
+
regular_setting: <%= 1 + 1 %>
|
148
|
+
HEREDOC
|
149
|
+
|
150
|
+
settings_file = File.new path: tempfile.path,
|
151
|
+
encryption_key: './spec/spec_key.pub'
|
152
|
+
|
153
|
+
settings_file.secure
|
154
|
+
|
155
|
+
file_contents = ::File.read(tempfile.path)
|
156
|
+
secure_setting_encoded = file_contents[/ _secure_setting: ([A-Za-z0-9\+\/]{342}==)$/, 1]
|
157
|
+
secure_another_setting_encoded = file_contents[/ _secure_another_setting: ([A-Za-z0-9\+\/]{342}==)$/, 1]
|
158
|
+
|
159
|
+
expect(::File.read(tempfile.path)).to eql <<-HEREDOC
|
160
|
+
default:
|
161
|
+
stuff: &default
|
162
|
+
_secure_setting: #{secure_setting_encoded}
|
163
|
+
_secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
|
164
|
+
|
165
|
+
other:
|
166
|
+
stuff:
|
167
|
+
<<: *default
|
168
|
+
_secure_another_setting: #{secure_another_setting_encoded}
|
169
|
+
regular_setting: <%= 1 + 1 %>
|
170
|
+
HEREDOC
|
171
|
+
end
|
116
172
|
end
|
117
173
|
end
|
@@ -21,6 +21,7 @@ describe BooleanConversionFilter do
|
|
21
21
|
non_boolean: Time.utc(2012, 8, 1),
|
22
22
|
nilly: nil, },
|
23
23
|
false_boolean: 'false',
|
24
|
+
nilly: nil,
|
24
25
|
non_boolean: [1, 2, 3] })
|
25
26
|
|
26
27
|
expect(filtered_data).to eql( true_boolean: true,
|
@@ -37,6 +38,7 @@ describe BooleanConversionFilter do
|
|
37
38
|
non_boolean: Time.utc(2012, 8, 1),
|
38
39
|
nilly: nil, },
|
39
40
|
false_boolean: false,
|
41
|
+
nilly: nil,
|
40
42
|
non_boolean: [1, 2, 3] )
|
41
43
|
end
|
42
44
|
end
|
@@ -9,7 +9,7 @@ describe DecryptionFilter do
|
|
9
9
|
_secure_my_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
10
10
|
decryption_key: './spec/spec_key' )
|
11
11
|
|
12
|
-
expect(filtered_settings.
|
12
|
+
expect(filtered_settings._secure_my_secure_setting).to eql 'hello'
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'will not attempt to decrypt values which are not marked as "secure"' do
|
@@ -33,7 +33,7 @@ describe DecryptionFilter do
|
|
33
33
|
_secure_my_secure_setting: 'cJbFe0NI5\wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
34
34
|
decryption_key: './spec/spec_key' )
|
35
35
|
|
36
|
-
expect(filtered_settings.
|
36
|
+
expect(filtered_settings._secure_my_secure_setting).to eql 'cJbFe0NI5\wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'will not attempt to decrypt values if it guesses that they are not encrpyted' do
|
@@ -41,14 +41,14 @@ describe DecryptionFilter do
|
|
41
41
|
_secure_my_secure_setting: 'hello' },
|
42
42
|
decryption_key: './spec/spec_key' )
|
43
43
|
|
44
|
-
expect(filtered_settings.
|
44
|
+
expect(filtered_settings._secure_my_secure_setting).to eql 'hello'
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'simply returns the encrypted string if there is no decryption key' do
|
48
48
|
filtered_settings = DecryptionFilter.execute( data: {
|
49
49
|
_secure_my_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' })
|
50
50
|
|
51
|
-
expect(filtered_settings.
|
51
|
+
expect(filtered_settings._secure_my_secure_setting).to eql 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/insecure_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe InsecureFilter do
|
7
|
+
it 'will return values which are marked as "secure" if they are unencrypted' do
|
8
|
+
filtered_settings = InsecureFilter.execute( data: {
|
9
|
+
_secure_my_secure_setting: 'hello' })
|
10
|
+
|
11
|
+
expect(filtered_settings._secure_my_secure_setting).to match 'hello'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'will not return values which are not marked as "secure"' do
|
15
|
+
filtered_settings = InsecureFilter.execute( data: {
|
16
|
+
my_secure_setting: 'hello' })
|
17
|
+
|
18
|
+
expect(filtered_settings.my_secure_setting).to be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'will properly return values even if they are mixed and deeply nested' do
|
22
|
+
filtered_settings = InsecureFilter.execute( data: {
|
23
|
+
_secure_setting: 'hello',
|
24
|
+
secure_setting: 'goodbye',
|
25
|
+
secure_group: {
|
26
|
+
_secure_nested_setting: 'movie',
|
27
|
+
insecure_nested_setting: 'dinner' }})
|
28
|
+
|
29
|
+
expect(filtered_settings._secure_setting).to eql 'hello'
|
30
|
+
expect(filtered_settings.secure_setting).to be_nil
|
31
|
+
expect(filtered_settings.secure_group._secure_nested_setting).to eql 'movie'
|
32
|
+
expect(filtered_settings.secure_group.insecure_nested_setting).to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'will not return values which are encrypted' do
|
36
|
+
filtered_settings = InsecureFilter.execute( data: {
|
37
|
+
_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
38
|
+
secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
39
|
+
_secure_other_setting: 'hello',
|
40
|
+
secure_group: {
|
41
|
+
_secure_nested_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
42
|
+
_secure_other_nested_setting: 'goodbye',
|
43
|
+
insecure_nested_setting: 'dinner' }})
|
44
|
+
|
45
|
+
expect(filtered_settings._secure_setting?).to eql false
|
46
|
+
expect(filtered_settings.secure_setting?).to eql false
|
47
|
+
expect(filtered_settings._secure_other_setting).to eql 'hello'
|
48
|
+
expect(filtered_settings.secure_group._secure_nested_setting?).to eql false
|
49
|
+
expect(filtered_settings.secure_group._secure_other_nested_setting).to eql 'goodbye'
|
50
|
+
expect(filtered_settings.secure_group.insecure_nested_setting?).to eql false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/translate_secure_keys_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe TranslateSecureKeysFilter do
|
7
|
+
it 'will translate keys if they start with "_secure_"' do
|
8
|
+
filtered_settings = TranslateSecureKeysFilter.execute( data: {
|
9
|
+
_secure_my_secure_setting: 'hello' })
|
10
|
+
|
11
|
+
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'will not translate keys if they do not start with "_secure_"' do
|
15
|
+
filtered_settings = TranslateSecureKeysFilter.execute( data: {
|
16
|
+
my_secure_setting: 'hello' })
|
17
|
+
|
18
|
+
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'will not translate the key if it starts with "secure"' do
|
22
|
+
filtered_settings = TranslateSecureKeysFilter.execute( data: {
|
23
|
+
secure_setting: 'hello' })
|
24
|
+
|
25
|
+
expect(filtered_settings.secure_setting).to eql 'hello'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -31,25 +31,33 @@ describe Settings do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'knows how to convert itself into an environment hash' do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
settings = Settings.new(settings: {
|
35
|
+
my_setting: 'value',
|
36
|
+
level_1: {
|
37
|
+
level_2: {
|
38
|
+
some_setting: 'hello',
|
39
|
+
another: 'goodbye',
|
40
|
+
},
|
41
|
+
body: 'gracias',
|
42
|
+
},
|
43
|
+
there: 'was not that easy?',
|
44
|
+
})
|
45
|
+
|
46
|
+
expect(settings.to_environment).to eql(
|
47
|
+
'MY_SETTING' => 'value',
|
48
|
+
'LEVEL_1_LEVEL_2_SOME_SETTING' => 'hello',
|
49
|
+
'LEVEL_1_LEVEL_2_ANOTHER' => 'goodbye',
|
50
|
+
'LEVEL_1_BODY' => 'gracias',
|
51
|
+
'THERE' => 'was not that easy?',
|
52
|
+
)
|
42
53
|
end
|
43
54
|
|
44
55
|
it 'sorts environment variables by name when converted to an environment hash so that they are easier to parse for humans' do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
'B' => 'value',)
|
51
|
-
|
52
|
-
settings = Settings.new(settings: { setting: 'value' })
|
56
|
+
settings = Settings.new(settings: { 'C' => 'value',
|
57
|
+
'D' => 'value',
|
58
|
+
'A' => 'value',
|
59
|
+
'E' => 'value',
|
60
|
+
'B' => 'value' })
|
53
61
|
|
54
62
|
expect(settings.to_environment.to_a).to eql([['A', 'value'],
|
55
63
|
['B', 'value'],
|
@@ -59,16 +67,46 @@ describe Settings do
|
|
59
67
|
end
|
60
68
|
|
61
69
|
it 'can convert itself into a string' do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
settings = Settings.new(settings: {
|
71
|
+
my_setting: 'value',
|
72
|
+
level_1: {
|
73
|
+
level_2: {
|
74
|
+
some_setting: 'hello',
|
75
|
+
another: 'goodbye',
|
76
|
+
},
|
77
|
+
body: 'gracias',
|
78
|
+
},
|
79
|
+
there: 'was not that easy?',
|
80
|
+
})
|
81
|
+
|
82
|
+
expect(settings.to_s).to eql %Q{LEVEL_1_BODY="gracias" LEVEL_1_LEVEL_2_ANOTHER="goodbye" LEVEL_1_LEVEL_2_SOME_SETTING="hello" MY_SETTING="value" THERE="was not that easy?"}
|
83
|
+
end
|
70
84
|
|
71
|
-
|
85
|
+
it 'can convert itself into a string with custom options' do
|
86
|
+
settings = Settings.new(settings: {
|
87
|
+
my_setting: 'value',
|
88
|
+
level_1: {
|
89
|
+
level_2: {
|
90
|
+
some_setting: 'hello',
|
91
|
+
another: 'goodbye',
|
92
|
+
},
|
93
|
+
body: 'gracias',
|
94
|
+
},
|
95
|
+
there: 'was not that easy?',
|
96
|
+
})
|
97
|
+
|
98
|
+
settings_string = settings.to_s hierarchical_separator: '/',
|
99
|
+
pair_separator: "\n",
|
100
|
+
value_surrounder: "'",
|
101
|
+
name_value_separator: ': '
|
102
|
+
|
103
|
+
expect(settings_string).to eql <<-HEREDOC.chomp
|
104
|
+
LEVEL_1/BODY: 'gracias'
|
105
|
+
LEVEL_1/LEVEL_2/ANOTHER: 'goodbye'
|
106
|
+
LEVEL_1/LEVEL_2/SOME_SETTING: 'hello'
|
107
|
+
MY_SETTING: 'value'
|
108
|
+
THERE: 'was not that easy?'
|
109
|
+
HEREDOC
|
72
110
|
end
|
73
111
|
|
74
112
|
it 'can merge itself with a hash' do
|
@@ -113,6 +151,30 @@ describe Settings do
|
|
113
151
|
expect(settings.to_hash).not_to be_a Hashie::Mash
|
114
152
|
end
|
115
153
|
|
154
|
+
it 'can convert itself into a hash with flattened names' do
|
155
|
+
settings = Settings.new(settings: {
|
156
|
+
my_setting: 'value',
|
157
|
+
level_1: {
|
158
|
+
level_2: {
|
159
|
+
some_setting: 'hello',
|
160
|
+
another: 'goodbye',
|
161
|
+
},
|
162
|
+
body: 'gracias',
|
163
|
+
},
|
164
|
+
there: 'was not that easy?',
|
165
|
+
})
|
166
|
+
|
167
|
+
expect(settings.to_flattened_name_hash).to eql(
|
168
|
+
['my_setting'] => 'value',
|
169
|
+
['level_1', 'level_2', 'some_setting'] => 'hello',
|
170
|
+
['level_1', 'level_2', 'another'] => 'goodbye',
|
171
|
+
['level_1', 'body'] => 'gracias',
|
172
|
+
['there'] => 'was not that easy?',
|
173
|
+
)
|
174
|
+
expect(settings.to_flattened_name_hash).to be_a Hash
|
175
|
+
expect(settings.to_flattened_name_hash).not_to be_a Hashie::Mash
|
176
|
+
end
|
177
|
+
|
116
178
|
it 'does not allow manipulation of the internal setting hash when converted to a Hash' do
|
117
179
|
settings = Settings.new(settings: {setting: 'value'})
|
118
180
|
|
@@ -186,7 +248,7 @@ describe Settings do
|
|
186
248
|
|
187
249
|
secure_settings = settings.secure
|
188
250
|
|
189
|
-
expect(secure_settings.
|
251
|
+
expect(secure_settings.my_encrypted_setting).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
190
252
|
end
|
191
253
|
|
192
254
|
it 'can check if it is equal to other items which can be converted into hashes' do
|
@@ -195,17 +257,34 @@ describe Settings do
|
|
195
257
|
expect(settings).to eq('setting' => 'value')
|
196
258
|
end
|
197
259
|
|
198
|
-
it 'can filter
|
199
|
-
settings = Settings.new(settings:
|
200
|
-
_secure_my_encrypted_setting:
|
201
|
-
|
260
|
+
it 'can filter securable settings' do
|
261
|
+
settings = Settings.new(settings: {
|
262
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
263
|
+
_secure_my_unencrypted_setting: 'nifty',
|
264
|
+
my_insecure_setting: 'goodbye',
|
265
|
+
},
|
266
|
+
decryption_key: './spec/spec_key')
|
267
|
+
|
268
|
+
secured_settings = settings.securable
|
269
|
+
|
270
|
+
expect(secured_settings.my_encrypted_setting).to eql 'hello'
|
271
|
+
expect(secured_settings.my_unencrypted_setting).to eql 'nifty'
|
272
|
+
expect(secured_settings.my_insecure_setting?).to eql false
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'can filter unencrypted settings' do
|
276
|
+
settings = Settings.new(settings: {
|
277
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
278
|
+
_secure_my_unencrypted_setting: 'nifty',
|
279
|
+
my_insecure_setting: 'goodbye',
|
202
280
|
},
|
203
281
|
decryption_key: './spec/spec_key')
|
204
282
|
|
205
|
-
secured_settings = settings.
|
283
|
+
secured_settings = settings.insecure
|
206
284
|
|
207
|
-
expect(secured_settings.my_encrypted_setting).to
|
208
|
-
expect(secured_settings.
|
285
|
+
expect(secured_settings.my_encrypted_setting?).to eql false
|
286
|
+
expect(secured_settings.my_unencrypted_setting).to eql 'nifty'
|
287
|
+
expect(secured_settings.my_insecure_setting?).to eql false
|
209
288
|
end
|
210
289
|
end
|
211
290
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chamber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- stevenhallen
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-
|
14
|
+
date: 2014-06-29 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: thor
|
@@ -19,56 +19,56 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: 0.19.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 0.19.1
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: hashie
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
34
|
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 2.0.5
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
43
|
+
version: 2.0.5
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: rspec
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
48
|
- - "~>"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 3.0
|
50
|
+
version: '3.0'
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 3.0
|
57
|
+
version: '3.0'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rspectacular
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
62
|
- - "~>"
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 0.
|
64
|
+
version: '0.46'
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
69
|
- - "~>"
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: 0.
|
71
|
+
version: '0.46'
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: codeclimate-test-reporter
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,14 +127,15 @@ files:
|
|
127
127
|
- lib/chamber/filters/decryption_filter.rb
|
128
128
|
- lib/chamber/filters/encryption_filter.rb
|
129
129
|
- lib/chamber/filters/environment_filter.rb
|
130
|
+
- lib/chamber/filters/insecure_filter.rb
|
130
131
|
- lib/chamber/filters/namespace_filter.rb
|
131
132
|
- lib/chamber/filters/secure_filter.rb
|
133
|
+
- lib/chamber/filters/translate_secure_keys_filter.rb
|
132
134
|
- lib/chamber/instance.rb
|
133
135
|
- lib/chamber/namespace_set.rb
|
134
136
|
- lib/chamber/rails.rb
|
135
137
|
- lib/chamber/rails/railtie.rb
|
136
138
|
- lib/chamber/settings.rb
|
137
|
-
- lib/chamber/system_environment.rb
|
138
139
|
- lib/chamber/version.rb
|
139
140
|
- spec/fixtures/settings.yml
|
140
141
|
- spec/lib/chamber/commands/files_spec.rb
|
@@ -151,11 +152,12 @@ files:
|
|
151
152
|
- spec/lib/chamber/filters/decryption_filter_spec.rb
|
152
153
|
- spec/lib/chamber/filters/encryption_filter_spec.rb
|
153
154
|
- spec/lib/chamber/filters/environment_filter_spec.rb
|
155
|
+
- spec/lib/chamber/filters/insecure_filter_spec.rb
|
154
156
|
- spec/lib/chamber/filters/namespace_filter_spec.rb
|
155
157
|
- spec/lib/chamber/filters/secure_filter_spec.rb
|
158
|
+
- spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb
|
156
159
|
- spec/lib/chamber/namespace_set_spec.rb
|
157
160
|
- spec/lib/chamber/settings_spec.rb
|
158
|
-
- spec/lib/chamber/system_environment_spec.rb
|
159
161
|
- spec/lib/chamber_spec.rb
|
160
162
|
- spec/rails-2-test/config.ru
|
161
163
|
- spec/rails-2-test/config/application.rb
|
@@ -190,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
192
|
version: '0'
|
191
193
|
requirements: []
|
192
194
|
rubyforge_project: chamber
|
193
|
-
rubygems_version: 2.
|
195
|
+
rubygems_version: 2.3.0
|
194
196
|
signing_key:
|
195
197
|
specification_version: 4
|
196
198
|
summary: A surprisingly configurable convention-based approach to managing your application's
|
@@ -211,11 +213,12 @@ test_files:
|
|
211
213
|
- spec/lib/chamber/filters/decryption_filter_spec.rb
|
212
214
|
- spec/lib/chamber/filters/encryption_filter_spec.rb
|
213
215
|
- spec/lib/chamber/filters/environment_filter_spec.rb
|
216
|
+
- spec/lib/chamber/filters/insecure_filter_spec.rb
|
214
217
|
- spec/lib/chamber/filters/namespace_filter_spec.rb
|
215
218
|
- spec/lib/chamber/filters/secure_filter_spec.rb
|
219
|
+
- spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb
|
216
220
|
- spec/lib/chamber/namespace_set_spec.rb
|
217
221
|
- spec/lib/chamber/settings_spec.rb
|
218
|
-
- spec/lib/chamber/system_environment_spec.rb
|
219
222
|
- spec/lib/chamber_spec.rb
|
220
223
|
- spec/rails-2-test/config/application.rb
|
221
224
|
- spec/rails-2-test/config.ru
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'chamber/environmentable'
|
2
|
-
|
3
|
-
###
|
4
|
-
# Internal: Gives access to the existing environment for importing/exporting
|
5
|
-
# values.
|
6
|
-
#
|
7
|
-
module Chamber
|
8
|
-
module SystemEnvironment
|
9
|
-
extend Environmentable
|
10
|
-
|
11
|
-
###
|
12
|
-
# Internal: Allows the environment variable-compatible variables to be
|
13
|
-
# extracted from a passed in hash.
|
14
|
-
#
|
15
|
-
# Examples:
|
16
|
-
#
|
17
|
-
# ###
|
18
|
-
# # Extracts the environment variables based on the hash keys
|
19
|
-
# #
|
20
|
-
# SystemEnvironment.extract_from(
|
21
|
-
# level_one_1: {
|
22
|
-
# level_two_1: 'value 1',
|
23
|
-
# level_two_2: {
|
24
|
-
# level_three_1: 'value 2' } } )
|
25
|
-
#
|
26
|
-
# # => {
|
27
|
-
# 'LEVEL_ONE_1_LEVEL_TWO_1' => 'env value 1',
|
28
|
-
# 'LEVEL_ONE_1_LEVEL_TWO_2_LEVEL_THREE_1' => 'env value 2',
|
29
|
-
# }
|
30
|
-
#
|
31
|
-
# ###
|
32
|
-
# # Can extract environment variables if said variables are prefixed
|
33
|
-
# #
|
34
|
-
# SystemEnvironment.extract_from({
|
35
|
-
# level_two_1: 'value 1',
|
36
|
-
# level_two_2: 'value 2'
|
37
|
-
# },
|
38
|
-
# ['prefix'])
|
39
|
-
#
|
40
|
-
# # => {
|
41
|
-
# 'PREFIX_LEVEL_TWO_1' => 'value 1',
|
42
|
-
# 'PREFIX_LEVEL_TWO_2' => 'value 2',
|
43
|
-
# }
|
44
|
-
#
|
45
|
-
def self.extract_from(settings, parent_keys = [])
|
46
|
-
with_environment(settings, parent_keys,
|
47
|
-
->(key, value, environment_keys) do
|
48
|
-
extract_from(value, environment_keys)
|
49
|
-
end,
|
50
|
-
->(key, value, environment_key) do
|
51
|
-
{ environment_key => value.to_s }
|
52
|
-
end)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'rspectacular'
|
2
|
-
require 'chamber/system_environment'
|
3
|
-
|
4
|
-
module Chamber
|
5
|
-
describe SystemEnvironment do
|
6
|
-
it 'can extract environment variables based on a hash that is passed in' do
|
7
|
-
source_hash = {
|
8
|
-
level_one_1: {
|
9
|
-
level_two_1: 'value 1',
|
10
|
-
level_two_2: {
|
11
|
-
level_three_1: 'value 2',
|
12
|
-
level_three_2: 'value 3',
|
13
|
-
},
|
14
|
-
level_two_3: 'value 4',
|
15
|
-
level_one_2: 'value 5' }
|
16
|
-
}
|
17
|
-
|
18
|
-
expect(SystemEnvironment.extract_from(source_hash)).to eql({
|
19
|
-
'LEVEL_ONE_1_LEVEL_TWO_1' => 'value 1',
|
20
|
-
'LEVEL_ONE_1_LEVEL_TWO_2_LEVEL_THREE_1' => 'value 2',
|
21
|
-
'LEVEL_ONE_1_LEVEL_TWO_2_LEVEL_THREE_2' => 'value 3',
|
22
|
-
'LEVEL_ONE_1_LEVEL_TWO_3' => 'value 4',
|
23
|
-
'LEVEL_ONE_1_LEVEL_ONE_2' => 'value 5',
|
24
|
-
})
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'converts all items to strings so that they are usable as an environment variable' do
|
28
|
-
source_hash = {
|
29
|
-
value_one: Time.utc(2013, 10, 8, 18, 0, 1),
|
30
|
-
value_two: 3,
|
31
|
-
}
|
32
|
-
|
33
|
-
expect(SystemEnvironment.extract_from(source_hash)).to eql({
|
34
|
-
'VALUE_ONE' => '2013-10-08 18:00:01 UTC',
|
35
|
-
'VALUE_TWO' => '3',
|
36
|
-
})
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'allows extracted environment variables to be prefixed for compatibility' do
|
40
|
-
source_hash = {
|
41
|
-
value_one: 'value',
|
42
|
-
}
|
43
|
-
|
44
|
-
environment_hash = SystemEnvironment.extract_from(source_hash, [:prefix])
|
45
|
-
|
46
|
-
expect(environment_hash).to eql({
|
47
|
-
'PREFIX_VALUE_ONE' => 'value',
|
48
|
-
})
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|