chamber 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +288 -173
  3. data/bin/chamber +2 -288
  4. data/lib/chamber.rb +19 -67
  5. data/lib/chamber/binary/heroku.rb +59 -0
  6. data/lib/chamber/binary/runner.rb +94 -0
  7. data/lib/chamber/binary/travis.rb +23 -0
  8. data/lib/chamber/commands/base.rb +33 -0
  9. data/lib/chamber/commands/comparable.rb +37 -0
  10. data/lib/chamber/commands/compare.rb +46 -0
  11. data/lib/chamber/commands/context_resolver.rb +72 -0
  12. data/lib/chamber/commands/files.rb +12 -0
  13. data/lib/chamber/commands/heroku.rb +30 -0
  14. data/lib/chamber/commands/heroku/clear.rb +25 -0
  15. data/lib/chamber/commands/heroku/compare.rb +31 -0
  16. data/lib/chamber/commands/heroku/pull.rb +30 -0
  17. data/lib/chamber/commands/heroku/push.rb +25 -0
  18. data/lib/chamber/commands/initialize.rb +73 -0
  19. data/lib/chamber/commands/securable.rb +48 -0
  20. data/lib/chamber/commands/secure.rb +16 -0
  21. data/lib/chamber/commands/show.rb +23 -0
  22. data/lib/chamber/commands/travis.rb +14 -0
  23. data/lib/chamber/commands/travis/secure.rb +35 -0
  24. data/lib/chamber/configuration.rb +34 -0
  25. data/lib/chamber/environmentable.rb +23 -0
  26. data/lib/chamber/errors/undecryptable_value_error.rb +6 -0
  27. data/lib/chamber/file.rb +17 -5
  28. data/lib/chamber/file_set.rb +18 -12
  29. data/lib/chamber/filters/boolean_conversion_filter.rb +41 -0
  30. data/lib/chamber/filters/decryption_filter.rb +69 -0
  31. data/lib/chamber/filters/encryption_filter.rb +57 -0
  32. data/lib/chamber/filters/environment_filter.rb +75 -0
  33. data/lib/chamber/filters/namespace_filter.rb +37 -0
  34. data/lib/chamber/filters/secure_filter.rb +39 -0
  35. data/lib/chamber/instance.rb +40 -0
  36. data/lib/chamber/namespace_set.rb +55 -16
  37. data/lib/chamber/rails/railtie.rb +1 -1
  38. data/lib/chamber/settings.rb +103 -42
  39. data/lib/chamber/system_environment.rb +3 -93
  40. data/lib/chamber/version.rb +2 -2
  41. data/spec/fixtures/settings.yml +27 -0
  42. data/spec/lib/chamber/commands/context_resolver_spec.rb +106 -0
  43. data/spec/lib/chamber/commands/files_spec.rb +19 -0
  44. data/spec/lib/chamber/commands/heroku/clear_spec.rb +11 -0
  45. data/spec/lib/chamber/commands/heroku/compare_spec.rb +11 -0
  46. data/spec/lib/chamber/commands/heroku/pull_spec.rb +11 -0
  47. data/spec/lib/chamber/commands/heroku/push_spec.rb +11 -0
  48. data/spec/lib/chamber/commands/secure_spec.rb +29 -0
  49. data/spec/lib/chamber/commands/show_spec.rb +43 -0
  50. data/spec/lib/chamber/file_set_spec.rb +1 -1
  51. data/spec/lib/chamber/file_spec.rb +32 -9
  52. data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +44 -0
  53. data/spec/lib/chamber/filters/decryption_filter_spec.rb +55 -0
  54. data/spec/lib/chamber/filters/encryption_filter_spec.rb +48 -0
  55. data/spec/lib/chamber/filters/environment_filter_spec.rb +35 -0
  56. data/spec/lib/chamber/filters/namespace_filter_spec.rb +73 -0
  57. data/spec/lib/chamber/filters/secure_filter_spec.rb +36 -0
  58. data/spec/lib/chamber/namespace_set_spec.rb +61 -18
  59. data/spec/lib/chamber/settings_spec.rb +99 -23
  60. data/spec/lib/chamber/system_environment_spec.rb +1 -71
  61. data/spec/lib/chamber_spec.rb +40 -26
  62. data/spec/rails-2-test/config.ru +0 -0
  63. data/spec/rails-2-test/config/application.rb +5 -0
  64. data/spec/rails-2-test/script/console +0 -0
  65. data/spec/rails-3-test/config.ru +0 -0
  66. data/spec/rails-3-test/config/application.rb +5 -0
  67. data/spec/rails-3-test/script/rails +0 -0
  68. data/spec/rails-4-test/bin/rails +0 -0
  69. data/spec/rails-4-test/config.ru +0 -0
  70. data/spec/rails-4-test/config/application.rb +5 -0
  71. data/spec/spec_key +27 -0
  72. data/spec/spec_key.pub +9 -0
  73. 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,11 @@
1
+ require 'rspectacular'
2
+ require 'chamber/commands/heroku/clear'
3
+
4
+ module Chamber
5
+ module Commands
6
+ module Heroku
7
+ describe Clear do
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspectacular'
2
+ require 'chamber/commands/heroku/compare'
3
+
4
+ module Chamber
5
+ module Commands
6
+ module Heroku
7
+ describe Compare do
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspectacular'
2
+ require 'chamber/commands/heroku/pull'
3
+
4
+ module Chamber
5
+ module Commands
6
+ module Heroku
7
+ describe Pull do
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspectacular'
2
+ require 'chamber/commands/heroku/push'
3
+
4
+ module Chamber
5
+ module Commands
6
+ module Heroku
7
+ describe Push do
8
+ end
9
+ end
10
+ end
11
+ 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
- class Chamber
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
- class Chamber
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: {'test' => '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