chamber 2.12.5 → 2.14.2

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +101 -26
  5. data/lib/chamber.rb +82 -10
  6. data/lib/chamber/adapters/cloud/circle_ci.rb +85 -0
  7. data/lib/chamber/adapters/cloud/heroku.rb +74 -0
  8. data/lib/chamber/binary/circle_ci.rb +122 -0
  9. data/lib/chamber/binary/heroku.rb +45 -16
  10. data/lib/chamber/binary/runner.rb +42 -26
  11. data/lib/chamber/binary/travis.rb +5 -3
  12. data/lib/chamber/commands/base.rb +10 -16
  13. data/lib/chamber/commands/cloud/base.rb +35 -0
  14. data/lib/chamber/commands/{heroku → cloud}/clear.rb +6 -8
  15. data/lib/chamber/commands/cloud/compare.rb +26 -0
  16. data/lib/chamber/commands/cloud/pull.rb +29 -0
  17. data/lib/chamber/commands/cloud/push.rb +44 -0
  18. data/lib/chamber/commands/comparable.rb +2 -2
  19. data/lib/chamber/commands/compare.rb +6 -9
  20. data/lib/chamber/commands/initialize.rb +26 -22
  21. data/lib/chamber/commands/securable.rb +9 -9
  22. data/lib/chamber/commands/secure.rb +2 -2
  23. data/lib/chamber/commands/show.rb +8 -8
  24. data/lib/chamber/commands/sign.rb +2 -2
  25. data/lib/chamber/commands/verify.rb +2 -2
  26. data/lib/chamber/configuration.rb +8 -3
  27. data/lib/chamber/context_resolver.rb +8 -7
  28. data/lib/chamber/encryption_methods/ssl.rb +12 -12
  29. data/lib/chamber/file.rb +16 -14
  30. data/lib/chamber/file_set.rb +18 -8
  31. data/lib/chamber/files/signature.rb +16 -14
  32. data/lib/chamber/filters/decryption_filter.rb +17 -13
  33. data/lib/chamber/filters/encryption_filter.rb +8 -8
  34. data/lib/chamber/filters/environment_filter.rb +12 -14
  35. data/lib/chamber/filters/failed_decryption_filter.rb +6 -6
  36. data/lib/chamber/filters/insecure_filter.rb +3 -3
  37. data/lib/chamber/filters/namespace_filter.rb +5 -5
  38. data/lib/chamber/filters/secure_filter.rb +5 -5
  39. data/lib/chamber/filters/translate_secure_keys_filter.rb +5 -5
  40. data/lib/chamber/instance.rb +45 -21
  41. data/lib/chamber/key_pair.rb +7 -7
  42. data/lib/chamber/keys/base.rb +31 -49
  43. data/lib/chamber/keys/decryption.rb +5 -5
  44. data/lib/chamber/keys/encryption.rb +5 -5
  45. data/lib/chamber/namespace_set.rb +2 -4
  46. data/lib/chamber/settings.rb +73 -45
  47. data/lib/chamber/types/secured.rb +8 -10
  48. data/lib/chamber/version.rb +1 -1
  49. data/templates/settings.yml +2 -0
  50. metadata +46 -39
  51. metadata.gz.sig +0 -0
  52. data/lib/chamber/commands/heroku.rb +0 -31
  53. data/lib/chamber/commands/heroku/compare.rb +0 -33
  54. data/lib/chamber/commands/heroku/pull.rb +0 -30
  55. data/lib/chamber/commands/heroku/push.rb +0 -27
@@ -9,10 +9,10 @@ class KeyPair
9
9
  :namespace,
10
10
  :passphrase
11
11
 
12
- def initialize(options = {})
13
- self.namespace = options[:namespace]
14
- self.passphrase = options.fetch(:passphrase, SecureRandom.uuid)
15
- self.key_file_path = Pathname.new(options.fetch(:key_file_path))
12
+ def initialize(key_file_path:, namespace: nil, passphrase: ::SecureRandom.uuid)
13
+ self.namespace = namespace
14
+ self.passphrase = passphrase
15
+ self.key_file_path = Pathname.new(key_file_path)
16
16
  end
17
17
 
18
18
  def encrypted_private_key_passphrase_filepath
@@ -78,9 +78,9 @@ class KeyPair
78
78
  @base_key_filename ||= [
79
79
  '.chamber',
80
80
  namespace ? namespace.tr('-.', '') : nil,
81
- ].
82
- compact.
83
- join('.')
81
+ ]
82
+ .compact
83
+ .join('.')
84
84
  end
85
85
  end
86
86
  end
@@ -3,81 +3,63 @@
3
3
  module Chamber
4
4
  module Keys
5
5
  class Base
6
- def self.resolve(*args)
7
- new(*args).resolve
6
+ def self.resolve(**args)
7
+ new(**args).resolve
8
8
  end
9
9
 
10
10
  attr_accessor :rootpath
11
11
  attr_reader :filenames,
12
12
  :namespaces
13
13
 
14
- def initialize(options = {})
15
- self.rootpath = Pathname.new(options.fetch(:rootpath))
16
- self.namespaces = options.fetch(:namespaces)
17
- self.filenames = options[:filenames]
14
+ def initialize(rootpath:, namespaces:, filenames: nil)
15
+ self.rootpath = Pathname.new(rootpath)
16
+ self.namespaces = namespaces
17
+ self.filenames = filenames
18
18
  end
19
19
 
20
20
  def resolve
21
- filenames.each_with_object({}) do |filename, memo|
22
- namespace = namespace_from_filename(filename) || '__default'
23
- value = key_from_file_contents(filename) ||
24
- key_from_environment_variable(filename)
21
+ key_paths.each_with_object({}) do |path, memo|
22
+ namespace = namespace_from_path(path) || '__default'
23
+ value = path.readable? ? path.read : ENV[environment_variable_from_path(path)]
25
24
 
26
25
  memo[namespace.downcase.to_sym] = value if value
27
26
  end
28
27
  end
29
28
 
30
- # rubocop:disable Performance/ChainArrayAllocation
31
- def filenames=(other)
32
- @filenames = begin
33
- paths = Array(other).
34
- map { |o| Pathname.new(o) }.
35
- compact
36
-
37
- paths << default_key_file_path if paths.empty?
38
-
39
- (
40
- paths +
41
- generate_key_filenames
42
- ).
43
- uniq
44
- end
29
+ def as_environment_variables
30
+ key_paths.select(&:readable?).each_with_object({}) do |path, memo|
31
+ memo[environment_variable_from_path(path)] = path.read
32
+ end
45
33
  end
46
- # rubocop:enable Performance/ChainArrayAllocation
47
34
 
48
35
  private
49
36
 
50
- def namespaces=(other)
51
- @namespaces = begin
52
- keys = if other.respond_to?(:keys)
53
- other.keys.map(&:to_s)
54
- else
55
- other
56
- end
57
-
58
- keys + %w{signature}
59
- end
37
+ def key_paths
38
+ @key_paths = (filenames.any? ? filenames : [default_key_file_path]) +
39
+ namespaces.map { |n| namespace_to_key_path(n) }
60
40
  end
61
41
 
62
- def key_from_file_contents(filename)
63
- filename.readable? && filename.read
42
+ # rubocop:disable Performance/ChainArrayAllocation
43
+ def filenames=(other)
44
+ @filenames = Array(other)
45
+ .map { |o| Pathname.new(o) }
46
+ .compact
64
47
  end
48
+ # rubocop:enable Performance/ChainArrayAllocation
65
49
 
66
- def key_from_environment_variable(filename)
67
- ENV[environment_variable_from_filename(filename)]
50
+ def namespaces=(other)
51
+ @namespaces = other + %w{signature}
68
52
  end
69
53
 
70
- def namespace_from_filename(filename)
71
- filename.
72
- basename.
73
- to_s.
74
- match(self.class::NAMESPACE_PATTERN) { |m| m[1].upcase }
54
+ def namespace_from_path(path)
55
+ path
56
+ .basename
57
+ .to_s
58
+ .match(self.class::NAMESPACE_PATTERN) { |m| m[1].upcase }
75
59
  end
76
60
 
77
- def generate_key_filenames
78
- namespaces.map do |namespace|
79
- rootpath + ".chamber.#{namespace.to_s.tr('.-', '')}#{key_filename_extension}"
80
- end
61
+ def namespace_to_key_path(namespace)
62
+ rootpath + ".chamber.#{namespace.to_s.tr('.-', '')}#{key_filename_extension}"
81
63
  end
82
64
 
83
65
  def default_key_file_path
@@ -17,14 +17,14 @@ class Decryption < Chamber::Keys::Base
17
17
 
18
18
  private
19
19
 
20
- def environment_variable_from_filename(filename)
20
+ def environment_variable_from_path(path)
21
21
  [
22
22
  'CHAMBER',
23
- namespace_from_filename(filename),
23
+ namespace_from_path(path),
24
24
  'KEY',
25
- ].
26
- compact.
27
- join('_')
25
+ ]
26
+ .compact
27
+ .join('_')
28
28
  end
29
29
 
30
30
  def key_filename_extension
@@ -17,14 +17,14 @@ class Encryption < Chamber::Keys::Base
17
17
 
18
18
  private
19
19
 
20
- def environment_variable_from_filename(filename)
20
+ def environment_variable_from_path(path)
21
21
  [
22
22
  'CHAMBER',
23
- namespace_from_filename(filename),
23
+ namespace_from_path(path),
24
24
  'PUBLIC_KEY',
25
- ].
26
- compact.
27
- join('_')
25
+ ]
26
+ .compact
27
+ .join('_')
28
28
  end
29
29
 
30
30
  def key_filename_extension
@@ -71,10 +71,8 @@ class NamespaceSet
71
71
  # Internal: Iterates over each namespace value and allows it to be used in
72
72
  # a block.
73
73
  #
74
- def each
75
- namespaces.each do |namespace|
76
- yield namespace
77
- end
74
+ def each(&block)
75
+ namespaces.each(&block)
78
76
  end
79
77
 
80
78
  ###
@@ -16,29 +16,40 @@ require 'chamber/filters/failed_decryption_filter'
16
16
  #
17
17
  module Chamber
18
18
  class Settings
19
- attr_accessor :pre_filters,
20
- :post_filters,
19
+ attr_accessor :decryption_keys,
21
20
  :encryption_keys,
22
- :decryption_keys
21
+ :post_filters,
22
+ :pre_filters,
23
+ :secure_key_prefix
23
24
  attr_reader :namespaces
24
25
 
25
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/LineLength
26
- def initialize(options = {})
27
- self.namespaces = options[:namespaces] || []
28
- self.raw_data = options[:settings] || {}
29
- self.decryption_keys = options[:decryption_keys] || {}
30
- self.encryption_keys = options[:encryption_keys] || {}
31
- self.pre_filters = options[:pre_filters] || [
32
- Filters::NamespaceFilter,
33
- ]
34
- self.post_filters = options[:post_filters] || [
35
- Filters::DecryptionFilter,
36
- Filters::EnvironmentFilter,
37
- Filters::FailedDecryptionFilter,
38
- Filters::TranslateSecureKeysFilter,
39
- ]
26
+ # rubocop:disable Metrics/ParameterLists
27
+ def initialize(
28
+ decryption_keys: {},
29
+ encryption_keys: {},
30
+ namespaces: [],
31
+ pre_filters: [
32
+ Filters::NamespaceFilter,
33
+ ],
34
+ post_filters: [
35
+ Filters::DecryptionFilter,
36
+ Filters::EnvironmentFilter,
37
+ Filters::FailedDecryptionFilter,
38
+ Filters::TranslateSecureKeysFilter,
39
+ ],
40
+ secure_key_prefix: '_secure_',
41
+ settings: {},
42
+ **_args
43
+ )
44
+ self.decryption_keys = decryption_keys
45
+ self.encryption_keys = encryption_keys
46
+ self.namespaces = namespaces
47
+ self.post_filters = post_filters
48
+ self.pre_filters = pre_filters
49
+ self.raw_data = settings
50
+ self.secure_key_prefix = secure_key_prefix
40
51
  end
41
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/LineLength
52
+ # rubocop:enable Metrics/ParameterLists
42
53
 
43
54
  ###
44
55
  # Internal: Converts a Settings object into a hash that is compatible as an
@@ -79,15 +90,11 @@ class Settings
79
90
  # } ).to_s
80
91
  # # => 'MY_KEY="my value" MY_OTHER_KEY="my other value"'
81
92
  #
82
- def to_s(options = {})
83
- hierarchical_separator = options[:hierarchical_separator] || '_'
84
- pair_separator = options[:pair_separator] || ' '
85
- value_surrounder = options[:value_surrounder] || '"'
86
- name_value_separator = options[:name_value_separator] || '='
87
-
88
- concatenated_name_hash = to_concatenated_name_hash(hierarchical_separator)
89
-
90
- pairs = concatenated_name_hash.to_a.map do |key, value|
93
+ def to_s(hierarchical_separator: '_',
94
+ pair_separator: ' ',
95
+ value_surrounder: '"',
96
+ name_value_separator: '=')
97
+ pairs = to_concatenated_name_hash(hierarchical_separator).to_a.map do |key, value|
91
98
  "#{key.upcase}#{name_value_separator}#{value_surrounder}#{value}#{value_surrounder}"
92
99
  end
93
100
 
@@ -182,20 +189,21 @@ class Settings
182
189
  # Returns a new Settings object
183
190
  #
184
191
  def merge(other)
185
- other_settings = if other.is_a? Settings
192
+ other_settings = case other
193
+ when Settings
186
194
  other
187
- elsif other.is_a? Hash
195
+ when Hash
188
196
  Settings.new(settings: other)
189
197
  end
190
198
 
191
- # rubocop:disable Metrics/LineLength
199
+ # rubocop:disable Layout/LineLength
192
200
  Settings.new(
193
201
  encryption_keys: encryption_keys.any? ? encryption_keys : other_settings.encryption_keys,
194
202
  decryption_keys: decryption_keys.any? ? decryption_keys : other_settings.decryption_keys,
195
203
  namespaces: (namespaces + other_settings.namespaces),
196
204
  settings: raw_data.merge(other_settings.raw_data),
197
205
  )
198
- # rubocop:enable Metrics/LineLength
206
+ # rubocop:enable Layout/LineLength
199
207
  end
200
208
 
201
209
  ###
@@ -219,15 +227,36 @@ class Settings
219
227
  namespaces == other.namespaces
220
228
  end
221
229
 
230
+ def [](key)
231
+ warn "WARNING: Bracket access will require strings instead of symbols in Chamber 3.0. You attempted to access the '#{key}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#removal-of-bracket-indifferent-access for full details." if key.is_a?(::Symbol) # rubocop:disable Layout/LineLength
232
+ warn "WARNING: Accessing a non-existent key ('#{key}') with brackets will fail in Chamber 3.0. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#bracket-access-now-fails-on-non-existent-keys for full details." unless data.has_key?(key) # rubocop:disable Layout/LineLength
233
+
234
+ data.[](key)
235
+ end
236
+
237
+ def dig!(*args)
238
+ args.inject(data) do |data_value, bracket_value|
239
+ key = bracket_value.is_a?(::Symbol) ? bracket_value.to_s : bracket_value
240
+
241
+ data_value.fetch(key)
242
+ end
243
+ end
244
+
245
+ def dig(*args)
246
+ dig!(*args)
247
+ rescue ::KeyError, ::IndexError # rubocop:disable Lint/ShadowedException
248
+ nil
249
+ end
250
+
222
251
  def securable
223
- Settings.new(metadata.merge(
252
+ Settings.new(**metadata.merge(
224
253
  settings: raw_data,
225
254
  pre_filters: [Filters::SecureFilter],
226
255
  ))
227
256
  end
228
257
 
229
258
  def secure
230
- Settings.new(metadata.merge(
259
+ Settings.new(**metadata.merge(
231
260
  settings: raw_data,
232
261
  pre_filters: [Filters::EncryptionFilter],
233
262
  post_filters: [Filters::TranslateSecureKeysFilter],
@@ -235,7 +264,7 @@ class Settings
235
264
  end
236
265
 
237
266
  def insecure
238
- Settings.new(metadata.merge(
267
+ Settings.new(**metadata.merge(
239
268
  settings: raw_data,
240
269
  pre_filters: [Filters::InsecureFilter],
241
270
  post_filters: [Filters::TranslateSecureKeysFilter],
@@ -243,9 +272,14 @@ class Settings
243
272
  end
244
273
 
245
274
  def method_missing(name, *args)
246
- return data.public_send(name, *args) if data.respond_to?(name)
275
+ if data.respond_to?(name)
276
+ warn "WARNING: Object notation access is deprecated and will be removed in Chamber 3.0. You attempted to access the '#{name}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#removal-of-object-notation-access for full details." # rubocop:disable Layout/LineLength
277
+ warn "WARNING: Predicate methods are deprecated and will be removed in Chamber 3.0. You attempted to access the '#{name}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#removal-of-predicate-accessors for full details." if name.to_s.end_with?('?') # rubocop:disable Layout/LineLength
247
278
 
248
- super
279
+ data.public_send(name, *args)
280
+ else
281
+ super
282
+ end
249
283
  end
250
284
 
251
285
  def respond_to_missing?(name, include_private = false)
@@ -265,23 +299,17 @@ class Settings
265
299
  # rubocop:disable Naming/MemoizedInstanceVariableName
266
300
  def raw_data
267
301
  @filtered_raw_data ||= pre_filters.inject(@raw_data) do |filtered_data, filter|
268
- filter.execute({ data: filtered_data }.
269
- merge(metadata))
302
+ filter.execute(**{ data: filtered_data }.merge(metadata))
270
303
  end
271
304
  end
272
305
  # rubocop:enable Naming/MemoizedInstanceVariableName
273
306
 
274
307
  def data
275
308
  @data ||= post_filters.inject(raw_data) do |filtered_data, filter|
276
- filter.execute({ data: filtered_data }.
277
- merge(metadata))
309
+ filter.execute(**{ data: filtered_data }.merge(metadata))
278
310
  end
279
311
  end
280
312
 
281
- def secure_key_prefix
282
- '_secure_'
283
- end
284
-
285
313
  def metadata
286
314
  {
287
315
  decryption_keys: decryption_keys,
@@ -3,21 +3,19 @@
3
3
  require 'active_support/json'
4
4
  require 'chamber'
5
5
 
6
- # rubocop:disable Lint/HandleExceptions, Layout/EmptyLinesAroundModuleBody
7
6
  module Chamber
8
-
9
7
  begin
10
8
  require 'active_record/type/value'
11
9
 
12
10
  CHAMBER_TYPE_VALUE_SUPERCLASS = ActiveRecord::Type::Value
13
- rescue LoadError
11
+ rescue LoadError # rubocop:disable Lint/SuppressedException
14
12
  end
15
13
 
16
14
  begin
17
15
  require 'active_model/type/value'
18
16
 
19
17
  CHAMBER_TYPE_VALUE_SUPERCLASS = ActiveModel::Type::Value
20
- rescue LoadError
18
+ rescue LoadError # rubocop:disable Lint/SuppressedException
21
19
  end
22
20
 
23
21
  module Types
@@ -25,11 +23,12 @@ class Secured < CHAMBER_TYPE_VALUE_SUPERCLASS
25
23
  attr_accessor :decryption_keys,
26
24
  :encryption_keys
27
25
 
28
- def initialize(options = {})
29
- self.encryption_keys = options.fetch(:encryption_keys,
30
- Chamber.configuration.encryption_keys)
31
- self.decryption_keys = options.fetch(:decryption_keys,
32
- Chamber.configuration.decryption_keys)
26
+ def initialize(decryption_keys: ::Chamber.configuration.decryption_keys,
27
+ encryption_keys: ::Chamber.configuration.encryption_keys)
28
+ self.decryption_keys = decryption_keys
29
+ self.encryption_keys = encryption_keys
30
+
31
+ super()
33
32
  end
34
33
 
35
34
  def type
@@ -78,4 +77,3 @@ class Secured < CHAMBER_TYPE_VALUE_SUPERCLASS
78
77
  end
79
78
  end
80
79
  end
81
- # rubocop:enable Lint/HandleExceptions, Layout/EmptyLinesAroundModuleBody
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chamber
4
- VERSION = '2.12.5'
4
+ VERSION = '2.14.2'
5
5
  end
@@ -1,3 +1,5 @@
1
+ ---
2
+
1
3
  development:
2
4
  setting: development_value
3
5
  # The following will become 'secure_setting'