chamber 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|