chamber 2.4.0 → 2.7.1
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 +16 -930
- data/Rakefile +6 -0
- data/lib/chamber.rb +11 -7
- data/lib/chamber/binary/heroku.rb +45 -25
- data/lib/chamber/binary/runner.rb +82 -44
- data/lib/chamber/binary/travis.rb +14 -8
- data/lib/chamber/commands/base.rb +1 -2
- data/lib/chamber/commands/comparable.rb +0 -1
- data/lib/chamber/commands/compare.rb +1 -1
- data/lib/chamber/commands/files.rb +0 -1
- data/lib/chamber/commands/heroku.rb +2 -3
- data/lib/chamber/commands/heroku/push.rb +1 -1
- data/lib/chamber/commands/initialize.rb +69 -12
- data/lib/chamber/commands/securable.rb +9 -4
- data/lib/chamber/commands/secure.rb +1 -1
- data/lib/chamber/commands/show.rb +20 -4
- data/lib/chamber/commands/travis.rb +0 -1
- data/lib/chamber/configuration.rb +5 -5
- data/lib/chamber/context_resolver.rb +12 -12
- data/lib/chamber/decryption_key.rb +51 -0
- data/lib/chamber/environmentable.rb +4 -1
- data/lib/chamber/errors/decryption_failure.rb +6 -0
- data/lib/chamber/file.rb +7 -8
- data/lib/chamber/file_set.rb +23 -22
- data/lib/chamber/filters/boolean_conversion_filter.rb +1 -2
- data/lib/chamber/filters/decryption_filter.rb +42 -25
- data/lib/chamber/filters/encryption_filter.rb +7 -5
- data/lib/chamber/filters/environment_filter.rb +7 -7
- data/lib/chamber/filters/failed_decryption_filter.rb +41 -0
- data/lib/chamber/filters/namespace_filter.rb +1 -1
- data/lib/chamber/filters/secure_filter.rb +3 -5
- data/lib/chamber/filters/translate_secure_keys_filter.rb +5 -24
- data/lib/chamber/namespace_set.rb +6 -6
- data/lib/chamber/rails.rb +1 -3
- data/lib/chamber/rails/railtie.rb +6 -3
- data/lib/chamber/settings.rb +34 -32
- data/lib/chamber/version.rb +1 -1
- data/spec/fixtures/settings.yml +1 -0
- data/spec/lib/chamber/commands/files_spec.rb +4 -2
- data/spec/lib/chamber/commands/secure_spec.rb +8 -5
- data/spec/lib/chamber/commands/show_spec.rb +18 -3
- data/spec/lib/chamber/context_resolver_spec.rb +38 -18
- data/spec/lib/chamber/file_set_spec.rb +73 -52
- data/spec/lib/chamber/file_spec.rb +37 -23
- data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +35 -33
- data/spec/lib/chamber/filters/decryption_filter_spec.rb +142 -21
- data/spec/lib/chamber/filters/encryption_filter_spec.rb +51 -19
- data/spec/lib/chamber/filters/environment_filter_spec.rb +12 -6
- data/spec/lib/chamber/filters/failed_decryption_filter_spec.rb +53 -0
- data/spec/lib/chamber/filters/insecure_filter_spec.rb +38 -18
- data/spec/lib/chamber/filters/namespace_filter_spec.rb +38 -38
- data/spec/lib/chamber/filters/secure_filter_spec.rb +10 -10
- data/spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb +9 -6
- data/spec/lib/chamber/namespace_set_spec.rb +7 -5
- data/spec/lib/chamber/settings_spec.rb +168 -79
- data/spec/lib/chamber_spec.rb +72 -71
- metadata +22 -21
- data/lib/chamber/errors/undecryptable_value_error.rb +0 -6
- data/templates/settings.yml +0 -14
@@ -5,26 +5,26 @@ module Chamber
|
|
5
5
|
module Filters
|
6
6
|
describe InsecureFilter do
|
7
7
|
it 'will return values which are marked as "secure" if they are unencrypted' do
|
8
|
-
filtered_settings = InsecureFilter.execute(
|
9
|
-
|
8
|
+
filtered_settings = InsecureFilter.execute(data: {
|
9
|
+
_secure_my_secure_setting: 'hello' })
|
10
10
|
|
11
11
|
expect(filtered_settings._secure_my_secure_setting).to match 'hello'
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'will not return values which are not marked as "secure"' do
|
15
|
-
filtered_settings = InsecureFilter.execute(
|
16
|
-
|
15
|
+
filtered_settings = InsecureFilter.execute(data: {
|
16
|
+
my_secure_setting: 'hello' })
|
17
17
|
|
18
18
|
expect(filtered_settings.my_secure_setting).to be_nil
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'will properly return values even if they are mixed and deeply nested' do
|
22
|
-
filtered_settings = InsecureFilter.execute(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
28
|
|
29
29
|
expect(filtered_settings._secure_setting).to eql 'hello'
|
30
30
|
expect(filtered_settings.secure_setting).to be_nil
|
@@ -33,14 +33,34 @@ describe InsecureFilter do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'will not return values which are encrypted' do
|
36
|
-
filtered_settings = InsecureFilter.execute(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
filtered_settings = InsecureFilter.execute(
|
37
|
+
data: {
|
38
|
+
_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpss' \
|
39
|
+
'pg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzC' \
|
40
|
+
'MJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YG' \
|
41
|
+
'DJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6ag' \
|
42
|
+
'y1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMn' \
|
43
|
+
'gJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfN' \
|
44
|
+
'xMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
45
|
+
secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpss' \
|
46
|
+
'pg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzC' \
|
47
|
+
'MJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YG' \
|
48
|
+
'DJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6ag' \
|
49
|
+
'y1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMn' \
|
50
|
+
'gJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfN' \
|
51
|
+
'xMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
52
|
+
_secure_other_setting: 'hello',
|
53
|
+
secure_group: {
|
54
|
+
_secure_nested_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTh' \
|
55
|
+
'aV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4' \
|
56
|
+
'akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGy' \
|
57
|
+
'dkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9' \
|
58
|
+
'ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8' \
|
59
|
+
'QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZ' \
|
60
|
+
'gfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMn' \
|
61
|
+
'z84XzmUp2Y0H1jPgGkBKQJKArfQ==',
|
62
|
+
_secure_other_nested_setting: 'goodbye',
|
63
|
+
insecure_nested_setting: 'dinner' } })
|
44
64
|
|
45
65
|
expect(filtered_settings._secure_setting?).to eql false
|
46
66
|
expect(filtered_settings.secure_setting?).to eql false
|
@@ -6,67 +6,67 @@ module Chamber
|
|
6
6
|
module Filters
|
7
7
|
describe NamespaceFilter do
|
8
8
|
it 'can filter settings data based on the settings namespaces' do
|
9
|
-
filtered_settings = NamespaceFilter.execute(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
'other_namespace_value' ])
|
9
|
+
filtered_settings = NamespaceFilter.execute(
|
10
|
+
data: {
|
11
|
+
namespace_value: {
|
12
|
+
namespace_setting: 'value 1' },
|
13
|
+
other_namespace_value: {
|
14
|
+
other_namespace_setting: 'value 2' } },
|
15
|
+
namespaces: %w{namespace_value other_namespace_value})
|
17
16
|
|
18
17
|
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
19
18
|
expect(filtered_settings.other_namespace_setting).to eql 'value 2'
|
20
19
|
end
|
21
20
|
|
22
21
|
it 'ignores data which is not part of a namespace' do
|
23
|
-
filtered_settings = NamespaceFilter.execute(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
filtered_settings = NamespaceFilter.execute(
|
23
|
+
data: {
|
24
|
+
namespace_value: {
|
25
|
+
namespace_setting: 'value 1' },
|
26
|
+
non_namespaced_value: {
|
27
|
+
non_namespaced_setting: 'value 2' } },
|
28
|
+
namespaces: [
|
29
|
+
'namespace_value'])
|
30
30
|
|
31
31
|
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
32
32
|
expect(filtered_settings.non_namespaced_setting).to be_nil
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'ignores namespaces which do not exist in the data' do
|
36
|
-
filtered_settings = NamespaceFilter.execute(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
'other_namespace_value' ])
|
36
|
+
filtered_settings = NamespaceFilter.execute(
|
37
|
+
data: {
|
38
|
+
namespace_value: {
|
39
|
+
namespace_setting: 'value 1' } },
|
40
|
+
namespaces: %w{namespace_value other_namespace_value})
|
42
41
|
|
43
42
|
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
44
43
|
end
|
45
44
|
|
46
45
|
it 'does not filter data if it does not include any namespaces' do
|
47
|
-
filtered_settings = NamespaceFilter.execute(
|
48
|
-
|
49
|
-
|
46
|
+
filtered_settings = NamespaceFilter.execute(
|
47
|
+
data: {
|
48
|
+
non_namespaced_setting: 'value 1' },
|
49
|
+
namespaces: [])
|
50
50
|
|
51
51
|
expect(filtered_settings.non_namespaced_setting).to eql 'value 1'
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'can filter if it is given NamespaceSets' do
|
55
|
-
filtered_settings = NamespaceFilter.execute(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
55
|
+
filtered_settings = NamespaceFilter.execute(
|
56
|
+
data: {
|
57
|
+
namespace_value: {
|
58
|
+
namespace_setting: 'value 1',
|
59
|
+
another_namespace_setting: 'value 2' },
|
60
|
+
other_namespace_value: {
|
61
|
+
namespace_setting_1: 'value 1',
|
62
|
+
another_namespace_setting_2: 'value 2' },
|
63
|
+
non_namespaced_value: 'value 3' },
|
64
|
+
namespaces: NamespaceSet.new(%w{namespace_value other_namespace_value}))
|
65
65
|
|
66
|
-
expect(filtered_settings.to_hash).to eql(
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
expect(filtered_settings.to_hash).to eql('namespace_setting' => 'value 1',
|
67
|
+
'another_namespace_setting' => 'value 2',
|
68
|
+
'namespace_setting_1' => 'value 1',
|
69
|
+
'another_namespace_setting_2' => 'value 2')
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
@@ -5,26 +5,26 @@ module Chamber
|
|
5
5
|
module Filters
|
6
6
|
describe SecureFilter do
|
7
7
|
it 'will return values which are marked as "secure"' do
|
8
|
-
filtered_settings = SecureFilter.execute(
|
9
|
-
|
8
|
+
filtered_settings = SecureFilter.execute(data: {
|
9
|
+
_secure_my_secure_setting: 'hello' })
|
10
10
|
|
11
11
|
expect(filtered_settings._secure_my_secure_setting).to match 'hello'
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'will not return values which are not marked as "secure"' do
|
15
|
-
filtered_settings = SecureFilter.execute(
|
16
|
-
|
15
|
+
filtered_settings = SecureFilter.execute(data: {
|
16
|
+
my_secure_setting: 'hello' })
|
17
17
|
|
18
18
|
expect(filtered_settings.my_secure_setting).to be_nil
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'will properly return values even if they are mixed and deeply nested' do
|
22
|
-
filtered_settings = SecureFilter.execute(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
filtered_settings = SecureFilter.execute(data: {
|
23
|
+
_secure_setting: 'hello',
|
24
|
+
secure_setting: 'goodbye',
|
25
|
+
secure_group: {
|
26
|
+
_secure_nested_setting: 'movie',
|
27
|
+
insecure_nested_setting: 'dinner' } })
|
28
28
|
|
29
29
|
expect(filtered_settings._secure_setting).to eql 'hello'
|
30
30
|
expect(filtered_settings.secure_setting).to be_nil
|
@@ -5,22 +5,25 @@ module Chamber
|
|
5
5
|
module Filters
|
6
6
|
describe TranslateSecureKeysFilter do
|
7
7
|
it 'will translate keys if they start with "_secure_"' do
|
8
|
-
filtered_settings = TranslateSecureKeysFilter.execute(
|
9
|
-
|
8
|
+
filtered_settings = TranslateSecureKeysFilter.execute(
|
9
|
+
data: {
|
10
|
+
_secure_my_secure_setting: 'hello' })
|
10
11
|
|
11
12
|
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
12
13
|
end
|
13
14
|
|
14
15
|
it 'will not translate keys if they do not start with "_secure_"' do
|
15
|
-
filtered_settings = TranslateSecureKeysFilter.execute(
|
16
|
-
|
16
|
+
filtered_settings = TranslateSecureKeysFilter.execute(
|
17
|
+
data: {
|
18
|
+
my_secure_setting: 'hello' })
|
17
19
|
|
18
20
|
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
19
21
|
end
|
20
22
|
|
21
23
|
it 'will not translate the key if it starts with "secure"' do
|
22
|
-
filtered_settings = TranslateSecureKeysFilter.execute(
|
23
|
-
|
24
|
+
filtered_settings = TranslateSecureKeysFilter.execute(
|
25
|
+
data: {
|
26
|
+
secure_setting: 'hello' })
|
24
27
|
|
25
28
|
expect(filtered_settings.secure_setting).to eql 'hello'
|
26
29
|
end
|
@@ -4,8 +4,8 @@ require 'chamber/namespace_set'
|
|
4
4
|
module Chamber
|
5
5
|
describe NamespaceSet do
|
6
6
|
it 'can create a set from from a hash' do
|
7
|
-
namespace_set = NamespaceSet.new(
|
8
|
-
|
7
|
+
namespace_set = NamespaceSet.new(environment: :development,
|
8
|
+
hostname: 'my host')
|
9
9
|
|
10
10
|
expect(namespace_set).to eq ['development', 'my host']
|
11
11
|
end
|
@@ -50,7 +50,9 @@ describe NamespaceSet do
|
|
50
50
|
expect(namespace_set.object_id).not_to eq original_set.object_id
|
51
51
|
end
|
52
52
|
|
53
|
-
it 'when creating itself from another NamespaceSet, it does not nest the
|
53
|
+
it 'when creating itself from another NamespaceSet, it does not nest the ' \
|
54
|
+
'NamespaceSets' do
|
55
|
+
|
54
56
|
original_set = NamespaceSet[:development, 'my host']
|
55
57
|
namespace_set = NamespaceSet.new(original_set)
|
56
58
|
|
@@ -105,11 +107,11 @@ describe NamespaceSet do
|
|
105
107
|
end
|
106
108
|
|
107
109
|
it 'will process a value by executing it if it is a callable' do
|
108
|
-
namespace_set = NamespaceSet[
|
110
|
+
namespace_set = NamespaceSet[-> { 'callable' }]
|
109
111
|
|
110
112
|
expect(namespace_set).to eq ['callable']
|
111
113
|
|
112
|
-
namespace_set = NamespaceSet.new(
|
114
|
+
namespace_set = NamespaceSet.new(my_namespace: -> { 'callable' })
|
113
115
|
|
114
116
|
expect(namespace_set).to eq ['callable']
|
115
117
|
end
|
@@ -4,28 +4,28 @@ require 'chamber/settings'
|
|
4
4
|
module Chamber
|
5
5
|
describe Settings do
|
6
6
|
it 'can verify that it is equal to another Settings object' do
|
7
|
-
settings = Settings.new(
|
8
|
-
|
9
|
-
other_settings = Settings.new(
|
10
|
-
|
7
|
+
settings = Settings.new(settings: { setting: 'value' },
|
8
|
+
namespaces: ['good'])
|
9
|
+
other_settings = Settings.new(settings: { setting: 'value' },
|
10
|
+
namespaces: ['good'])
|
11
11
|
|
12
12
|
expect(settings).to eql other_settings
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'does not consider itself equal if the namespaces are not equal' do
|
16
|
-
settings = Settings.new(
|
17
|
-
|
18
|
-
other_settings = Settings.new(
|
19
|
-
|
16
|
+
settings = Settings.new(settings: { setting: 'value' },
|
17
|
+
namespaces: ['good'])
|
18
|
+
other_settings = Settings.new(settings: { setting: 'value' },
|
19
|
+
namespaces: ['bad'])
|
20
20
|
|
21
21
|
expect(settings).not_to eql other_settings
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'does not consider itself equal if the settings are not equal' do
|
25
|
-
settings = Settings.new(
|
26
|
-
|
27
|
-
other_settings = Settings.new(
|
28
|
-
|
25
|
+
settings = Settings.new(settings: { setting: 'value' },
|
26
|
+
namespaces: ['good'])
|
27
|
+
other_settings = Settings.new(settings: { setting: 'value 1' },
|
28
|
+
namespaces: ['good'])
|
29
29
|
|
30
30
|
expect(settings).not_to eql other_settings
|
31
31
|
end
|
@@ -34,11 +34,11 @@ describe Settings do
|
|
34
34
|
settings = Settings.new(settings: {
|
35
35
|
my_setting: 'value',
|
36
36
|
level_1: {
|
37
|
-
level_2:
|
37
|
+
level_2: {
|
38
38
|
some_setting: 'hello',
|
39
39
|
another: 'goodbye',
|
40
40
|
},
|
41
|
-
body:
|
41
|
+
body: 'gracias',
|
42
42
|
},
|
43
43
|
there: 'was not that easy?',
|
44
44
|
})
|
@@ -52,45 +52,53 @@ describe Settings do
|
|
52
52
|
)
|
53
53
|
end
|
54
54
|
|
55
|
-
it 'sorts environment variables by name when converted to an environment hash so
|
55
|
+
it 'sorts environment variables by name when converted to an environment hash so ' \
|
56
|
+
'that they are easier to parse for humans' do
|
57
|
+
|
56
58
|
settings = Settings.new(settings: { 'C' => 'value',
|
57
59
|
'D' => 'value',
|
58
60
|
'A' => 'value',
|
59
61
|
'E' => 'value',
|
60
62
|
'B' => 'value' })
|
61
63
|
|
62
|
-
expect(settings.to_environment.to_a).to eql([
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
expect(settings.to_environment.to_a).to eql([%w{A value},
|
65
|
+
%w{B value},
|
66
|
+
%w{C value},
|
67
|
+
%w{D value},
|
68
|
+
%w{E value}])
|
67
69
|
end
|
68
70
|
|
69
71
|
it 'can convert itself into a string' do
|
70
72
|
settings = Settings.new(settings: {
|
71
73
|
my_setting: 'value',
|
72
74
|
level_1: {
|
73
|
-
level_2:
|
75
|
+
level_2: {
|
74
76
|
some_setting: 'hello',
|
75
77
|
another: 'goodbye',
|
76
78
|
},
|
77
|
-
body:
|
79
|
+
body: 'gracias',
|
78
80
|
},
|
79
81
|
there: 'was not that easy?',
|
80
82
|
})
|
81
83
|
|
82
|
-
expect(settings.to_s).to eql %
|
84
|
+
expect(settings.to_s).to eql %w{
|
85
|
+
LEVEL_1_BODY="gracias"
|
86
|
+
LEVEL_1_LEVEL_2_ANOTHER="goodbye"
|
87
|
+
LEVEL_1_LEVEL_2_SOME_SETTING="hello"
|
88
|
+
MY_SETTING="value"
|
89
|
+
THERE="was not that easy?"
|
90
|
+
}.join(' ')
|
83
91
|
end
|
84
92
|
|
85
93
|
it 'can convert itself into a string with custom options' do
|
86
94
|
settings = Settings.new(settings: {
|
87
95
|
my_setting: 'value',
|
88
96
|
level_1: {
|
89
|
-
level_2:
|
97
|
+
level_2: {
|
90
98
|
some_setting: 'hello',
|
91
99
|
another: 'goodbye',
|
92
100
|
},
|
93
|
-
body:
|
101
|
+
body: 'gracias',
|
94
102
|
},
|
95
103
|
there: 'was not that easy?',
|
96
104
|
})
|
@@ -110,32 +118,32 @@ HEREDOC
|
|
110
118
|
end
|
111
119
|
|
112
120
|
it 'can merge itself with a hash' do
|
113
|
-
settings = Settings.new(settings: {setting: 'value'})
|
121
|
+
settings = Settings.new(settings: { setting: 'value' })
|
114
122
|
other_settings = { other_setting: 'another value' }
|
115
123
|
|
116
124
|
merged_settings = settings.merge(other_settings)
|
117
125
|
|
118
126
|
expect(merged_settings).to eq('setting' => 'value',
|
119
|
-
|
127
|
+
'other_setting' => 'another value')
|
120
128
|
end
|
121
129
|
|
122
130
|
it 'can merge itself with Settings' do
|
123
|
-
settings = Settings.new(settings: {setting: 'value'},
|
131
|
+
settings = Settings.new(settings: { setting: 'value' },
|
124
132
|
namespaces: ['good'])
|
125
|
-
other_settings = Settings.new(settings: {other_setting: 'another value'},
|
133
|
+
other_settings = Settings.new(settings: { other_setting: 'another value' },
|
126
134
|
namespaces: ['bad'])
|
127
135
|
|
128
136
|
merged_settings = settings.merge(other_settings)
|
129
137
|
|
130
138
|
expect(merged_settings).to eql Settings.new(settings: {
|
131
|
-
setting:
|
132
|
-
other_setting:
|
133
|
-
namespaces:
|
139
|
+
setting: 'value',
|
140
|
+
other_setting: 'another value' },
|
141
|
+
namespaces: %w{good bad})
|
134
142
|
end
|
135
143
|
|
136
144
|
it 'does not manipulate the existing Settings but instead returns a new one' do
|
137
|
-
settings = Settings.new(settings: {setting: 'value'})
|
138
|
-
other_settings = Settings.new(settings: {other_setting: 'another value'})
|
145
|
+
settings = Settings.new(settings: { setting: 'value' })
|
146
|
+
other_settings = Settings.new(settings: { other_setting: 'another value' })
|
139
147
|
|
140
148
|
merged_settings = settings.merge(other_settings)
|
141
149
|
|
@@ -144,7 +152,7 @@ HEREDOC
|
|
144
152
|
end
|
145
153
|
|
146
154
|
it 'can convert itself into a hash' do
|
147
|
-
settings = Settings.new(settings: {setting: 'value'})
|
155
|
+
settings = Settings.new(settings: { setting: 'value' })
|
148
156
|
|
149
157
|
expect(settings.to_hash).to eql('setting' => 'value')
|
150
158
|
expect(settings.to_hash).to be_a Hash
|
@@ -155,28 +163,30 @@ HEREDOC
|
|
155
163
|
settings = Settings.new(settings: {
|
156
164
|
my_setting: 'value',
|
157
165
|
level_1: {
|
158
|
-
level_2:
|
166
|
+
level_2: {
|
159
167
|
some_setting: 'hello',
|
160
168
|
another: 'goodbye',
|
161
169
|
},
|
162
|
-
body:
|
170
|
+
body: 'gracias',
|
163
171
|
},
|
164
172
|
there: 'was not that easy?',
|
165
173
|
})
|
166
174
|
|
167
175
|
expect(settings.to_flattened_name_hash).to eql(
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
176
|
+
%w{my_setting} => 'value',
|
177
|
+
%w{level_1 level_2 some_setting} => 'hello',
|
178
|
+
%w{level_1 level_2 another} => 'goodbye',
|
179
|
+
%w{level_1 body} => 'gracias',
|
180
|
+
%w{there} => 'was not that easy?',
|
173
181
|
)
|
174
182
|
expect(settings.to_flattened_name_hash).to be_a Hash
|
175
183
|
expect(settings.to_flattened_name_hash).not_to be_a Hashie::Mash
|
176
184
|
end
|
177
185
|
|
178
|
-
it 'does not allow manipulation of the internal setting hash when converted to
|
179
|
-
|
186
|
+
it 'does not allow manipulation of the internal setting hash when converted to ' \
|
187
|
+
'a Hash' do
|
188
|
+
|
189
|
+
settings = Settings.new(settings: { setting: 'value' })
|
180
190
|
|
181
191
|
settings_hash = settings.to_hash
|
182
192
|
settings_hash['setting'] = 'foo'
|
@@ -186,60 +196,69 @@ HEREDOC
|
|
186
196
|
end
|
187
197
|
|
188
198
|
it 'allows messages to be passed through to the underlying data' do
|
189
|
-
settings = Settings.new(settings: {setting: 'value'})
|
199
|
+
settings = Settings.new(settings: { setting: 'value' })
|
190
200
|
|
191
201
|
expect(settings.setting).to eql 'value'
|
192
202
|
end
|
193
203
|
|
194
204
|
it 'will still raise an error if the underlying data does not respond to it' do
|
195
|
-
settings = Settings.new(settings: {setting: 'value'})
|
205
|
+
settings = Settings.new(settings: { setting: 'value' })
|
196
206
|
|
197
207
|
expect { settings.unknown }.to raise_error NoMethodError
|
198
208
|
end
|
199
209
|
|
200
210
|
it 'can notify properly whether it responds to messages if the underlying data does' do
|
201
|
-
settings = Settings.new(settings: {setting: 'value'})
|
211
|
+
settings = Settings.new(settings: { setting: 'value' })
|
202
212
|
|
203
213
|
expect(settings.respond_to?(:setting)).to be_a TrueClass
|
204
214
|
end
|
205
215
|
|
206
216
|
it 'only includes namespaced data if any exists' do
|
207
217
|
settings = Settings.new(settings: {
|
208
|
-
namespace_value:
|
209
|
-
namespace_setting:
|
210
|
-
other_namespace_value:
|
211
|
-
other_namespace_setting:
|
212
|
-
non_namespace_setting:
|
218
|
+
namespace_value: {
|
219
|
+
namespace_setting: 'value' },
|
220
|
+
other_namespace_value: {
|
221
|
+
other_namespace_setting: 'value' },
|
222
|
+
non_namespace_setting: 'other value',
|
213
223
|
},
|
214
|
-
namespaces:
|
224
|
+
namespaces: %w{namespace_value other_namespace_value})
|
215
225
|
|
216
|
-
expect(settings).to eq('namespace_setting'
|
217
|
-
|
226
|
+
expect(settings).to eq('namespace_setting' => 'value',
|
227
|
+
'other_namespace_setting' => 'value')
|
218
228
|
end
|
219
229
|
|
220
230
|
it 'can decrypt a setting if it finds a secure key' do
|
221
|
-
settings = Settings.new(
|
222
|
-
|
223
|
-
|
224
|
-
|
231
|
+
settings = Settings.new(
|
232
|
+
settings: {
|
233
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTha' \
|
234
|
+
'V4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4ak' \
|
235
|
+
'un6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkE' \
|
236
|
+
'jY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8M' \
|
237
|
+
'v4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/' \
|
238
|
+
'1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86' \
|
239
|
+
'wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmU' \
|
240
|
+
'p2Y0H1jPgGkBKQJKArfQ==',
|
241
|
+
},
|
242
|
+
decryption_key: './spec/spec_key')
|
225
243
|
|
226
244
|
expect(settings).to eq('my_encrypted_setting' => 'hello')
|
227
245
|
end
|
228
246
|
|
229
247
|
it 'can encrypt a setting if it finds a secure key' do
|
230
|
-
settings = Settings.new(settings:
|
231
|
-
_secure_my_encrypted_setting: 'hello'
|
248
|
+
settings = Settings.new(settings: {
|
249
|
+
_secure_my_encrypted_setting: 'hello',
|
232
250
|
},
|
233
251
|
encryption_key: './spec/spec_key.pub',
|
234
252
|
pre_filters: [],
|
235
|
-
post_filters: [
|
253
|
+
post_filters: [Filters::EncryptionFilter])
|
236
254
|
|
237
|
-
expect(settings._secure_my_encrypted_setting).to match
|
255
|
+
expect(settings._secure_my_encrypted_setting).to match \
|
256
|
+
Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
238
257
|
end
|
239
258
|
|
240
259
|
it 'can encrypt a settings without explicitly having to have a filter passed' do
|
241
|
-
settings = Settings.new(settings:
|
242
|
-
_secure_my_encrypted_setting: 'hello'
|
260
|
+
settings = Settings.new(settings: {
|
261
|
+
_secure_my_encrypted_setting: 'hello',
|
243
262
|
},
|
244
263
|
decryption_key: './spec/spec_key',
|
245
264
|
encryption_key: './spec/spec_key.pub')
|
@@ -248,22 +267,31 @@ HEREDOC
|
|
248
267
|
|
249
268
|
secure_settings = settings.secure
|
250
269
|
|
251
|
-
expect(secure_settings.my_encrypted_setting).to match
|
270
|
+
expect(secure_settings.my_encrypted_setting).to match \
|
271
|
+
Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
252
272
|
end
|
253
273
|
|
254
274
|
it 'can check if it is equal to other items which can be converted into hashes' do
|
255
|
-
settings = Settings.new(settings: {setting: 'value'})
|
275
|
+
settings = Settings.new(settings: { setting: 'value' })
|
256
276
|
|
257
277
|
expect(settings).to eq('setting' => 'value')
|
258
278
|
end
|
259
279
|
|
260
280
|
it 'can filter securable settings' do
|
261
|
-
settings = Settings.new(
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
281
|
+
settings = Settings.new(
|
282
|
+
settings: {
|
283
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTha' \
|
284
|
+
'V4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4ak' \
|
285
|
+
'un6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkE' \
|
286
|
+
'jY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8M' \
|
287
|
+
'v4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/' \
|
288
|
+
'1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86' \
|
289
|
+
'wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmU' \
|
290
|
+
'p2Y0H1jPgGkBKQJKArfQ==',
|
291
|
+
_secure_my_unencrypted_setting: 'nifty',
|
292
|
+
my_insecure_setting: 'goodbye',
|
293
|
+
},
|
294
|
+
decryption_key: './spec/spec_key')
|
267
295
|
|
268
296
|
secured_settings = settings.securable
|
269
297
|
|
@@ -273,12 +301,20 @@ HEREDOC
|
|
273
301
|
end
|
274
302
|
|
275
303
|
it 'can filter unencrypted settings' do
|
276
|
-
settings = Settings.new(
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
304
|
+
settings = Settings.new(
|
305
|
+
settings: {
|
306
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTha' \
|
307
|
+
'V4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4ak' \
|
308
|
+
'un6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkE' \
|
309
|
+
'jY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8M' \
|
310
|
+
'v4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/' \
|
311
|
+
'1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86' \
|
312
|
+
'wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmU' \
|
313
|
+
'p2Y0H1jPgGkBKQJKArfQ==',
|
314
|
+
_secure_my_unencrypted_setting: 'nifty',
|
315
|
+
my_insecure_setting: 'goodbye',
|
316
|
+
},
|
317
|
+
decryption_key: './spec/spec_key')
|
282
318
|
|
283
319
|
secured_settings = settings.insecure
|
284
320
|
|
@@ -286,5 +322,58 @@ HEREDOC
|
|
286
322
|
expect(secured_settings.my_unencrypted_setting).to eql 'nifty'
|
287
323
|
expect(secured_settings.my_insecure_setting?).to eql false
|
288
324
|
end
|
325
|
+
|
326
|
+
it 'raises an exception when it accesses a value which cannot be decrypted' do
|
327
|
+
settings = Settings.new(
|
328
|
+
settings: {
|
329
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTha' \
|
330
|
+
'V4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4ak' \
|
331
|
+
'un6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkE' \
|
332
|
+
'jY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8M' \
|
333
|
+
'v4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/' \
|
334
|
+
'1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86' \
|
335
|
+
'wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmU' \
|
336
|
+
'p2Y0H1jPgGkBKQJKArfQ==',
|
337
|
+
},
|
338
|
+
)
|
339
|
+
|
340
|
+
expect { settings.my_encrypted_setting }.
|
341
|
+
to raise_error Chamber::Errors::DecryptionFailure
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'prefers environment variable values over encrypted values' do
|
345
|
+
ENV['MY_ENCRYPTED_SETTING'] = 'my env setting'
|
346
|
+
ENV['ENCRYPTED_GROUP_MY_ENCRYPTED_GROUP_SETTING'] = 'my env group'
|
347
|
+
|
348
|
+
settings = Settings.new(
|
349
|
+
settings: {
|
350
|
+
_secure_my_encrypted_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYTha' \
|
351
|
+
'V4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4ak' \
|
352
|
+
'un6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkE' \
|
353
|
+
'jY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8M' \
|
354
|
+
'v4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/' \
|
355
|
+
'1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86' \
|
356
|
+
'wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmU' \
|
357
|
+
'p2Y0H1jPgGkBKQJKArfQ==',
|
358
|
+
encrypted_group: {
|
359
|
+
_secure_my_encrypted_group_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdn' \
|
360
|
+
'MoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3Fx' \
|
361
|
+
'ptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEA' \
|
362
|
+
'QLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUT' \
|
363
|
+
'f34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5k' \
|
364
|
+
'LAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlz' \
|
365
|
+
'pKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgU' \
|
366
|
+
'Kc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84Xz' \
|
367
|
+
'mUp2Y0H1jPgGkBKQJKArfQ==',
|
368
|
+
},
|
369
|
+
},
|
370
|
+
)
|
371
|
+
|
372
|
+
expect(settings.my_encrypted_setting).to eql 'my env setting'
|
373
|
+
expect(settings.encrypted_group.my_encrypted_group_setting).to eql 'my env group'
|
374
|
+
|
375
|
+
ENV['MY_ENCRYPTED_SETTING'] = nil
|
376
|
+
ENV['ENCRYPTED_GROUP_MY_ENCRYPTED_GROUP_SETTING'] = nil
|
377
|
+
end
|
289
378
|
end
|
290
379
|
end
|