chamber 1.0.3 → 2.0.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 +288 -173
- data/bin/chamber +2 -288
- data/lib/chamber.rb +19 -67
- data/lib/chamber/binary/heroku.rb +59 -0
- data/lib/chamber/binary/runner.rb +94 -0
- data/lib/chamber/binary/travis.rb +23 -0
- data/lib/chamber/commands/base.rb +33 -0
- data/lib/chamber/commands/comparable.rb +37 -0
- data/lib/chamber/commands/compare.rb +46 -0
- data/lib/chamber/commands/context_resolver.rb +72 -0
- data/lib/chamber/commands/files.rb +12 -0
- data/lib/chamber/commands/heroku.rb +30 -0
- data/lib/chamber/commands/heroku/clear.rb +25 -0
- data/lib/chamber/commands/heroku/compare.rb +31 -0
- data/lib/chamber/commands/heroku/pull.rb +30 -0
- data/lib/chamber/commands/heroku/push.rb +25 -0
- data/lib/chamber/commands/initialize.rb +73 -0
- data/lib/chamber/commands/securable.rb +48 -0
- data/lib/chamber/commands/secure.rb +16 -0
- data/lib/chamber/commands/show.rb +23 -0
- data/lib/chamber/commands/travis.rb +14 -0
- data/lib/chamber/commands/travis/secure.rb +35 -0
- data/lib/chamber/configuration.rb +34 -0
- data/lib/chamber/environmentable.rb +23 -0
- data/lib/chamber/errors/undecryptable_value_error.rb +6 -0
- data/lib/chamber/file.rb +17 -5
- data/lib/chamber/file_set.rb +18 -12
- data/lib/chamber/filters/boolean_conversion_filter.rb +41 -0
- data/lib/chamber/filters/decryption_filter.rb +69 -0
- data/lib/chamber/filters/encryption_filter.rb +57 -0
- data/lib/chamber/filters/environment_filter.rb +75 -0
- data/lib/chamber/filters/namespace_filter.rb +37 -0
- data/lib/chamber/filters/secure_filter.rb +39 -0
- data/lib/chamber/instance.rb +40 -0
- data/lib/chamber/namespace_set.rb +55 -16
- data/lib/chamber/rails/railtie.rb +1 -1
- data/lib/chamber/settings.rb +103 -42
- data/lib/chamber/system_environment.rb +3 -93
- data/lib/chamber/version.rb +2 -2
- data/spec/fixtures/settings.yml +27 -0
- data/spec/lib/chamber/commands/context_resolver_spec.rb +106 -0
- data/spec/lib/chamber/commands/files_spec.rb +19 -0
- data/spec/lib/chamber/commands/heroku/clear_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/compare_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/pull_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/push_spec.rb +11 -0
- data/spec/lib/chamber/commands/secure_spec.rb +29 -0
- data/spec/lib/chamber/commands/show_spec.rb +43 -0
- data/spec/lib/chamber/file_set_spec.rb +1 -1
- data/spec/lib/chamber/file_spec.rb +32 -9
- data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +44 -0
- data/spec/lib/chamber/filters/decryption_filter_spec.rb +55 -0
- data/spec/lib/chamber/filters/encryption_filter_spec.rb +48 -0
- data/spec/lib/chamber/filters/environment_filter_spec.rb +35 -0
- data/spec/lib/chamber/filters/namespace_filter_spec.rb +73 -0
- data/spec/lib/chamber/filters/secure_filter_spec.rb +36 -0
- data/spec/lib/chamber/namespace_set_spec.rb +61 -18
- data/spec/lib/chamber/settings_spec.rb +99 -23
- data/spec/lib/chamber/system_environment_spec.rb +1 -71
- data/spec/lib/chamber_spec.rb +40 -26
- data/spec/rails-2-test/config.ru +0 -0
- data/spec/rails-2-test/config/application.rb +5 -0
- data/spec/rails-2-test/script/console +0 -0
- data/spec/rails-3-test/config.ru +0 -0
- data/spec/rails-3-test/config/application.rb +5 -0
- data/spec/rails-3-test/script/rails +0 -0
- data/spec/rails-4-test/bin/rails +0 -0
- data/spec/rails-4-test/config.ru +0 -0
- data/spec/rails-4-test/config/application.rb +5 -0
- data/spec/spec_key +27 -0
- data/spec/spec_key.pub +9 -0
- metadata +85 -4
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/commands/files'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
describe Files do
|
7
|
+
let(:rootpath) { ::File.expand_path('./spec/fixtures') }
|
8
|
+
let(:options) { { basepath: rootpath,
|
9
|
+
rootpath: rootpath } }
|
10
|
+
|
11
|
+
it 'can return values formatted as environment variables' do
|
12
|
+
files = Files.call(options)
|
13
|
+
|
14
|
+
expect(files.size).to eql 1
|
15
|
+
expect(files.first).to include 'spec/fixtures/settings.yml'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/commands/secure'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
describe Secure do
|
7
|
+
let(:rootpath) { Pathname.new(::File.expand_path('./spec/fixtures')) }
|
8
|
+
let(:settings_filename) { rootpath + 'settings' + 'unencrypted.yml' }
|
9
|
+
let(:options) { { basepath: rootpath,
|
10
|
+
rootpath: rootpath,
|
11
|
+
encryption_key: rootpath + '../spec_key'} }
|
12
|
+
|
13
|
+
it 'can return values formatted as environment variables' do
|
14
|
+
::File.open(settings_filename, 'w') do |file|
|
15
|
+
file.write <<-HEREDOC
|
16
|
+
test:
|
17
|
+
_secure_my_unencrpyted_setting: hello
|
18
|
+
HEREDOC
|
19
|
+
end
|
20
|
+
|
21
|
+
files = Secure.call(options)
|
22
|
+
|
23
|
+
expect(::File.read(settings_filename)).to match %r{_secure_my_unencrpyted_setting: [A-Za-z0-9\+\/]{342}==}
|
24
|
+
|
25
|
+
::File.delete(settings_filename)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/commands/show'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
describe Show do
|
7
|
+
let(:rootpath) { ::File.expand_path('./spec/fixtures') }
|
8
|
+
let(:options) { { basepath: rootpath,
|
9
|
+
rootpath: rootpath,
|
10
|
+
namespaces: 'test' } }
|
11
|
+
|
12
|
+
it 'can return values formatted as environment variables' do
|
13
|
+
expect(Show.call(options.merge(as_env: true))).to eql(
|
14
|
+
<<-HEREDOC.chomp
|
15
|
+
ANOTHER_LEVEL_LEVEL_THREE_AN_ARRAY="["item 1", "item 2", "item 3"]"
|
16
|
+
ANOTHER_LEVEL_LEVEL_THREE_A_SCALAR="hello"
|
17
|
+
ANOTHER_LEVEL_SETTING_ONE="1"
|
18
|
+
ANOTHER_LEVEL_SETTING_TWO="2"
|
19
|
+
MY_BOOLEAN="false"
|
20
|
+
MY_DYNAMIC_SETTING="2"
|
21
|
+
MY_SETTING="my_value"
|
22
|
+
HEREDOC
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'can return values formatted as a hash' do
|
27
|
+
expect(Show.call(options)).to eql(
|
28
|
+
<<-HEREDOC.chomp
|
29
|
+
{"my_setting"=>"my_value",
|
30
|
+
"my_boolean"=>false,
|
31
|
+
"my_dynamic_setting"=>2,
|
32
|
+
"another_level"=>
|
33
|
+
{"setting_one"=>1,
|
34
|
+
"setting_two"=>2,
|
35
|
+
"level_three"=>
|
36
|
+
{"an_array"=>["item 1", "item 2", "item 3"],
|
37
|
+
"a_scalar"=>"hello"}}}
|
38
|
+
HEREDOC
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -3,7 +3,7 @@ require 'chamber/file_set'
|
|
3
3
|
require 'fileutils'
|
4
4
|
|
5
5
|
|
6
|
-
|
6
|
+
module Chamber
|
7
7
|
describe FileSet do
|
8
8
|
before(:each) { FileUtils.mkdir '/tmp/settings' unless ::File.exist? '/tmp/settings' }
|
9
9
|
after(:each) { FileUtils.rm_rf '/tmp/settings' if ::File.exist? '/tmp/settings' }
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rspectacular'
|
2
2
|
require 'chamber/file'
|
3
3
|
require 'chamber/settings'
|
4
|
+
require 'chamber/filters/encryption_filter'
|
4
5
|
require 'tempfile'
|
5
6
|
|
6
7
|
def create_tempfile_with_content(content)
|
@@ -10,7 +11,7 @@ def create_tempfile_with_content(content)
|
|
10
11
|
tempfile
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
+
module Chamber
|
14
15
|
describe File do
|
15
16
|
it 'can convert file contents to settings' do
|
16
17
|
tempfile = create_tempfile_with_content %Q({ test: settings })
|
@@ -23,8 +24,10 @@ describe File do
|
|
23
24
|
|
24
25
|
expect(file_settings).to eql :settings
|
25
26
|
expect(Settings).to have_received(:new).
|
26
|
-
with(settings:
|
27
|
-
namespaces:
|
27
|
+
with(settings: {'test' => 'settings'},
|
28
|
+
namespaces: {},
|
29
|
+
decryption_key: nil,
|
30
|
+
encryption_key: nil)
|
28
31
|
end
|
29
32
|
|
30
33
|
it 'can convert a file whose contents are empty' do
|
@@ -38,8 +41,10 @@ describe File do
|
|
38
41
|
|
39
42
|
expect(file_settings).to eql :settings
|
40
43
|
expect(Settings).to have_received(:new).
|
41
|
-
with(settings:
|
42
|
-
namespaces:
|
44
|
+
with(settings: {},
|
45
|
+
namespaces: {},
|
46
|
+
decryption_key: nil,
|
47
|
+
encryption_key: nil)
|
43
48
|
end
|
44
49
|
|
45
50
|
it 'throws an error when the file contents are malformed' do
|
@@ -62,7 +67,9 @@ describe File do
|
|
62
67
|
expect(Settings).to have_received(:new).
|
63
68
|
with( settings: {'test' => 'settings'},
|
64
69
|
namespaces: {
|
65
|
-
environment: :development }
|
70
|
+
environment: :development },
|
71
|
+
decryption_key: nil,
|
72
|
+
encryption_key: nil)
|
66
73
|
end
|
67
74
|
|
68
75
|
it 'can handle files which contain ERB markup' do
|
@@ -74,7 +81,9 @@ describe File do
|
|
74
81
|
settings_file.to_settings
|
75
82
|
expect(Settings).to have_received(:new).
|
76
83
|
with( settings: {'test' => 2},
|
77
|
-
namespaces: {}
|
84
|
+
namespaces: {},
|
85
|
+
decryption_key: nil,
|
86
|
+
encryption_key: nil)
|
78
87
|
end
|
79
88
|
|
80
89
|
it 'does not throw an error when attempting to convert a file which does not exist' do
|
@@ -87,8 +96,22 @@ describe File do
|
|
87
96
|
|
88
97
|
expect(file_settings).to eql :settings
|
89
98
|
expect(Settings).to have_received(:new).
|
90
|
-
with(settings:
|
91
|
-
namespaces:
|
99
|
+
with(settings: {},
|
100
|
+
namespaces: {},
|
101
|
+
decryption_key: nil,
|
102
|
+
encryption_key: nil)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'can securely encrypt the settings contained in a file' do
|
106
|
+
tempfile = create_tempfile_with_content %Q({ _secure_setting: hello })
|
107
|
+
settings_file = File.new path: tempfile.path,
|
108
|
+
encryption_key: './spec/spec_key.pub'
|
109
|
+
|
110
|
+
settings_file.secure
|
111
|
+
|
112
|
+
settings_file = File.new path: tempfile.path
|
113
|
+
|
114
|
+
expect(settings_file.to_settings.send(:raw_data)['_secure_setting']).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
|
92
115
|
end
|
93
116
|
end
|
94
117
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/boolean_conversion_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe BooleanConversionFilter do
|
7
|
+
it 'can convert string boolean values into TrueClass and FalseClass even if they are deeply nested' do
|
8
|
+
filtered_data = BooleanConversionFilter.execute(
|
9
|
+
data: {
|
10
|
+
true_boolean: 'true',
|
11
|
+
boolean_group: {
|
12
|
+
yes_boolean: 'yes',
|
13
|
+
t_boolean: 't',
|
14
|
+
non_boolean: 'hello',
|
15
|
+
sub_boolean_group: {
|
16
|
+
false_boolean: 'false',
|
17
|
+
no_boolean: 'no',
|
18
|
+
nilly: nil,
|
19
|
+
non_boolean: 3, },
|
20
|
+
f_boolean: 'f',
|
21
|
+
non_boolean: Time.utc(2012, 8, 1),
|
22
|
+
nilly: nil, },
|
23
|
+
false_boolean: 'false',
|
24
|
+
non_boolean: [1, 2, 3] })
|
25
|
+
|
26
|
+
expect(filtered_data).to eql( true_boolean: true,
|
27
|
+
boolean_group: {
|
28
|
+
yes_boolean: true,
|
29
|
+
t_boolean: true,
|
30
|
+
non_boolean: 'hello',
|
31
|
+
sub_boolean_group: {
|
32
|
+
false_boolean: false,
|
33
|
+
no_boolean: false,
|
34
|
+
nilly: nil,
|
35
|
+
non_boolean: 3, },
|
36
|
+
f_boolean: false,
|
37
|
+
non_boolean: Time.utc(2012, 8, 1),
|
38
|
+
nilly: nil, },
|
39
|
+
false_boolean: false,
|
40
|
+
non_boolean: [1, 2, 3] )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/decryption_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe DecryptionFilter do
|
7
|
+
it 'will attempt to decrypt values which are marked as "secure"' do
|
8
|
+
filtered_settings = DecryptionFilter.execute( data: {
|
9
|
+
_secure_my_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
10
|
+
decryption_key: './spec/spec_key' )
|
11
|
+
|
12
|
+
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'will not attempt to decrypt values which are not marked as "secure"' do
|
16
|
+
filtered_settings = DecryptionFilter.execute( data: {
|
17
|
+
my_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
18
|
+
decryption_key: './spec/spec_key' )
|
19
|
+
|
20
|
+
expect(filtered_settings.my_secure_setting).to eql 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'will not attempt to decrypt values even if they are prefixed with "secure"' do
|
24
|
+
filtered_settings = DecryptionFilter.execute( data: {
|
25
|
+
secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
26
|
+
decryption_key: './spec/spec_key' )
|
27
|
+
|
28
|
+
expect(filtered_settings.secure_setting).to eql 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'will not attempt to decrypt values even if they are not properly encoded' do
|
32
|
+
filtered_settings = DecryptionFilter.execute( data: {
|
33
|
+
_secure_my_secure_setting: 'cJbFe0NI5\wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ==' },
|
34
|
+
decryption_key: './spec/spec_key' )
|
35
|
+
|
36
|
+
expect(filtered_settings.my_secure_setting).to eql 'cJbFe0NI5\wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'will not attempt to decrypt values if it guesses that they are not encrpyted' do
|
40
|
+
filtered_settings = DecryptionFilter.execute( data: {
|
41
|
+
_secure_my_secure_setting: 'hello' },
|
42
|
+
decryption_key: './spec/spec_key' )
|
43
|
+
|
44
|
+
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'will raise an exception if there is an encrypted value that it cannot decrypt' do
|
48
|
+
expect { DecryptionFilter.execute(data: {
|
49
|
+
_secure_my_secure_setting: 'cJbFe0NI5wknmsp2fVgpC/YeBD2pvcdVD+p0pUdnMoYThaV4mpsspg/ZTBtmjx7kMwcF6cjXFLDVw3FxptTHwzJUd4akun6EZ57m+QzCMJYnfY95gB2/emEAQLSz4/YwsE4LDGydkEjY1ZprfXznf+rU31YGDJUTf34ESz7fsQGSc9DjkBb9ao8Mv4cI7pCXkQZDwS5kLAZDf6agy1GzeL71Z8lrmQzk8QQuf/1kQzxsWVlzpKNXWS7u2CJ0sN5eINMngJBfv5ZFrZgfXc86wdgUKc8aaoX8OQA1kKTcdgbE9NcAhNr1+WfNxMnz84XzmUp2Y0H1jPgGkBKQJKArfQ=='
|
50
|
+
}) }.to \
|
51
|
+
raise_error(Chamber::Errors::UndecryptableValueError, 'my_secure_setting appears to need decrypting but the decryption key is not available.')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/encryption_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe EncryptionFilter do
|
7
|
+
it 'will attempt to encrypt values which are marked as "secure"' do
|
8
|
+
filtered_settings = EncryptionFilter.execute( data: {
|
9
|
+
_secure_my_secure_setting: 'hello' },
|
10
|
+
encryption_key: './spec/spec_key.pub' )
|
11
|
+
|
12
|
+
expect(filtered_settings._secure_my_secure_setting).to match EncryptionFilter::BASE64_STRING_PATTERN
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'will not attempt to encrypt values which are not marked as "secure"' do
|
16
|
+
filtered_settings = EncryptionFilter.execute( data: {
|
17
|
+
my_secure_setting: 'hello' },
|
18
|
+
encryption_key: './spec/spec_key.pub' )
|
19
|
+
|
20
|
+
expect(filtered_settings.my_secure_setting).to eql 'hello'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'will not attempt to encrypt values even if they are prefixed with "secure"' do
|
24
|
+
filtered_settings = EncryptionFilter.execute( data: {
|
25
|
+
secure_setting: 'hello' },
|
26
|
+
encryption_key: './spec/spec_key.pub' )
|
27
|
+
|
28
|
+
expect(filtered_settings.secure_setting).to eql 'hello'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'will attempt to encrypt values if they are not properly encoded' do
|
32
|
+
filtered_settings = EncryptionFilter.execute( data: {
|
33
|
+
_secure_my_secure_setting: 'fNI5\jwlBn' },
|
34
|
+
encryption_key: './spec/spec_key.pub' )
|
35
|
+
|
36
|
+
expect(filtered_settings._secure_my_secure_setting).to match EncryptionFilter::BASE64_STRING_PATTERN
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'will not attempt to encrypt values if it guesses that they are already encrpyted' do
|
40
|
+
filtered_settings = EncryptionFilter.execute( data: {
|
41
|
+
_secure_my_secure_setting: 'fNI5wlBniNhEU4396pmhWwx+A09bRAMJOUASuP7PzprewBX8CXYqL+v/uXOJpIRCLDjwe8quuC+j9iLcPU7HBRMr054gGxeqZexbLevXcPk7SrMis3qeEKmnAuarQGXe7ZAntidMY9Lx4pqSkhYXwQnI48d2Dh44qfaS9w2OrehSkpdFRnuxQeOpCKO/bleB0J88WGkytCohyHCRIpbaEjEC3UD52pnqMeu/ClNm+PBgE6Ci94pu5UUnZuIE/y+P4A3wgD6G/u8hgvAW51JwVryg/im1rayGAwWYNgupQ/5LDmjffwx7Q3fyMH2uF3CDIKRIC6U+mnM5SRMO4Dzysw==' },
|
42
|
+
encryption_key: './spec/spec_key.pub' )
|
43
|
+
|
44
|
+
expect(filtered_settings._secure_my_secure_setting).to eql 'fNI5wlBniNhEU4396pmhWwx+A09bRAMJOUASuP7PzprewBX8CXYqL+v/uXOJpIRCLDjwe8quuC+j9iLcPU7HBRMr054gGxeqZexbLevXcPk7SrMis3qeEKmnAuarQGXe7ZAntidMY9Lx4pqSkhYXwQnI48d2Dh44qfaS9w2OrehSkpdFRnuxQeOpCKO/bleB0J88WGkytCohyHCRIpbaEjEC3UD52pnqMeu/ClNm+PBgE6Ci94pu5UUnZuIE/y+P4A3wgD6G/u8hgvAW51JwVryg/im1rayGAwWYNgupQ/5LDmjffwx7Q3fyMH2uF3CDIKRIC6U+mnM5SRMO4Dzysw=='
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/environment_filter'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Filters
|
6
|
+
describe EnvironmentFilter do
|
7
|
+
it 'can extract data from the environment if an existing variable matches the composite key' do
|
8
|
+
ENV['TEST_SETTING_GROUP_TEST_SETTING_LEVEL_TEST_SETTING'] = 'value 2'
|
9
|
+
|
10
|
+
filtered_data = EnvironmentFilter.execute(data: {
|
11
|
+
test_setting_group: {
|
12
|
+
test_setting_level: {
|
13
|
+
test_setting: 'value 1' }}})
|
14
|
+
|
15
|
+
expect(filtered_data.test_setting_group.test_setting_level.test_setting).to eql 'value 2'
|
16
|
+
|
17
|
+
ENV.delete('TEST_SETTING_GROUP_TEST_SETTING_LEVEL_TEST_SETTING')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'does not affect items which are not stored in the environment' do
|
21
|
+
ENV['TEST_SETTING_GROUP_TEST_SETTING_LEVEL_TEST_SETTING'] = 'value 2'
|
22
|
+
|
23
|
+
filtered_data = EnvironmentFilter.execute(data: {
|
24
|
+
test_setting_group: {
|
25
|
+
test_setting_level: {
|
26
|
+
test_setting: 'value 1',
|
27
|
+
another_setting: 'value 3', }}})
|
28
|
+
|
29
|
+
expect(filtered_data.test_setting_group.test_setting_level.another_setting).to eql 'value 3'
|
30
|
+
|
31
|
+
ENV.delete('TEST_SETTING_GROUP_TEST_SETTING_LEVEL_TEST_SETTING')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'chamber/filters/namespace_filter'
|
3
|
+
require 'chamber/namespace_set'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Filters
|
7
|
+
describe NamespaceFilter do
|
8
|
+
it 'can filter settings data based on the settings namespaces' do
|
9
|
+
filtered_settings = NamespaceFilter.execute(data: {
|
10
|
+
namespace_value: {
|
11
|
+
namespace_setting: 'value 1' },
|
12
|
+
other_namespace_value: {
|
13
|
+
other_namespace_setting: 'value 2' }},
|
14
|
+
namespaces: [
|
15
|
+
'namespace_value',
|
16
|
+
'other_namespace_value' ])
|
17
|
+
|
18
|
+
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
19
|
+
expect(filtered_settings.other_namespace_setting).to eql 'value 2'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'ignores data which is not part of a namespace' do
|
23
|
+
filtered_settings = NamespaceFilter.execute(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
|
+
|
31
|
+
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
32
|
+
expect(filtered_settings.non_namespaced_setting).to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'ignores namespaces which do not exist in the data' do
|
36
|
+
filtered_settings = NamespaceFilter.execute(data: {
|
37
|
+
namespace_value: {
|
38
|
+
namespace_setting: 'value 1' }},
|
39
|
+
namespaces: [
|
40
|
+
'namespace_value',
|
41
|
+
'other_namespace_value' ])
|
42
|
+
|
43
|
+
expect(filtered_settings.namespace_setting).to eql 'value 1'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does not filter data if it does not include any namespaces' do
|
47
|
+
filtered_settings = NamespaceFilter.execute(data: {
|
48
|
+
non_namespaced_setting: 'value 1' },
|
49
|
+
namespaces: [])
|
50
|
+
|
51
|
+
expect(filtered_settings.non_namespaced_setting).to eql 'value 1'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can filter if it is given NamespaceSets' do
|
55
|
+
filtered_settings = NamespaceFilter.execute(data: {
|
56
|
+
namespace_value: {
|
57
|
+
namespace_setting: 'value 1',
|
58
|
+
another_namespace_setting: 'value 2' },
|
59
|
+
other_namespace_value: {
|
60
|
+
namespace_setting_1: 'value 1',
|
61
|
+
another_namespace_setting_2: 'value 2' },
|
62
|
+
non_namespaced_value: 'value 3' },
|
63
|
+
namespaces:
|
64
|
+
NamespaceSet.new(['namespace_value', 'other_namespace_value']) )
|
65
|
+
|
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
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|