chamber 3.0.0rc2 → 3.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +5 -5
  4. data/lib/chamber/binary/runner.rb +1 -1
  5. data/lib/chamber/commands/base.rb +4 -4
  6. data/lib/chamber/commands/initialize.rb +4 -4
  7. data/lib/chamber/commands/securable.rb +4 -5
  8. data/lib/chamber/commands/show.rb +0 -1
  9. data/lib/chamber/context_resolver.rb +4 -4
  10. data/lib/chamber/errors/disallowed_class.rb +1 -1
  11. data/lib/chamber/errors/invalid_key_type.rb +8 -0
  12. data/lib/chamber/errors/missing_index.rb +13 -0
  13. data/lib/chamber/errors/missing_setting.rb +13 -0
  14. data/lib/chamber/file_set.rb +0 -2
  15. data/lib/chamber/filters/decryption_filter.rb +4 -4
  16. data/lib/chamber/filters/encryption_filter.rb +4 -4
  17. data/lib/chamber/filters/environment_filter.rb +4 -4
  18. data/lib/chamber/filters/failed_decryption_filter.rb +3 -3
  19. data/lib/chamber/filters/namespace_filter.rb +3 -3
  20. data/lib/chamber/filters/secure_filter.rb +3 -3
  21. data/lib/chamber/filters/translate_secure_keys_filter.rb +3 -3
  22. data/lib/chamber/integrations/sinatra.rb +1 -1
  23. data/lib/chamber/keys/base.rb +11 -7
  24. data/lib/chamber/namespace_set.rb +2 -2
  25. data/lib/chamber/rails.rb +1 -1
  26. data/lib/chamber/settings.rb +18 -2
  27. data/lib/chamber/version.rb +1 -1
  28. data.tar.gz.sig +0 -0
  29. metadata +18 -26
  30. metadata.gz.sig +0 -0
  31. data/lib/chamber/adapters/cloud/circle_ci.rb +0 -85
  32. data/lib/chamber/adapters/cloud/heroku.rb +0 -74
  33. data/lib/chamber/binary/circle_ci.rb +0 -121
  34. data/lib/chamber/binary/heroku.rb +0 -109
  35. data/lib/chamber/binary/travis.rb +0 -32
  36. data/lib/chamber/commands/cloud/base.rb +0 -35
  37. data/lib/chamber/commands/cloud/clear.rb +0 -25
  38. data/lib/chamber/commands/cloud/compare.rb +0 -26
  39. data/lib/chamber/commands/cloud/pull.rb +0 -29
  40. data/lib/chamber/commands/cloud/push.rb +0 -44
  41. data/lib/chamber/commands/travis/secure.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9de7c74ea902d381006bd6b5f05bae3680d1beef940ae75e483f30c923bc310f
4
- data.tar.gz: b6f45eb5b668a5964e898ffb4caa5b9a3e9bc227736dd0e687e257cff0c99f84
3
+ metadata.gz: 0d89ed0b7af0eced2bb6890ea18af915dfdecaf4e521fb8f48bea9bc39fbbaae
4
+ data.tar.gz: 5befdc9cd11ca4e0aced5a7da916f6d849e49eb3a8a60df63cd61c9afb5e5637
5
5
  SHA512:
6
- metadata.gz: b1ab7fedfaf6cb26ab3e97402966368f3e686751ca76e441a7d9db64b7fe354a289ac4ac330cac806fb7960f3b4750c1ce4f7799e548c4f0f549ee57826e8552
7
- data.tar.gz: 64cfa0683ca78d71cd620e38e60c4d2c25683c5217d74858995b2ee65eda704f7d2aca9395451ac743424bd75b8974ee088ed3563e192be5ab057f49ad458165
6
+ metadata.gz: 3bdebbf96a6ca8183d4f480230d2cffe39d2d927f9ffa3fe396ab394271e3f33c7fcde2c58259483617817fc2fe1528c92391ecd822845de71e9d3dddca6a67a
7
+ data.tar.gz: 54603c3d40c94f6d4b7c57bd7a424730afe1e3d1ddd9e499426d14fa57549176bb32844034ef8da3b0fee1c38c9d3245e920941dc65c671a7362150f7ba157a9
checksums.yaml.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -19,7 +19,7 @@ Chamber
19
19
  </a>
20
20
 
21
21
  <a href="https://github.com/thekompanee/chamber/actions?query=workflow%3ABuild" alt="Build Status">
22
- <img src="https://img.shields.io/github/workflow/status/thekompanee/chamber/Build?label=CI&style=flat-square&logo=github" alt="Build Status" />
22
+ <img src="https://img.shields.io/github/actions/workflow/status/thekompanee/chamber/testing.yml?branch=master&label=CI&style=flat-square&logo=github" alt="Build Status" />
23
23
  </a>
24
24
 
25
25
  <a href="#" alt="Maintainability">
@@ -61,11 +61,11 @@ smtp_username: 'my_username'
61
61
  smtp_password: 'my_password'
62
62
  ```
63
63
 
64
- From there you can access your settings by using the special `Chamber.env`
64
+ From there you can access your settings by using the special `Chamber.dig`
65
65
  constant.
66
66
 
67
67
  ```ruby
68
- Chamber.env.smtp_password
68
+ Chamber.dig('smtp_password')
69
69
  # => 'my_password'
70
70
  ```
71
71
 
@@ -92,7 +92,7 @@ which you still access the same way because Chamber handles the decryption for
92
92
  you:
93
93
 
94
94
  ```ruby
95
- Chamber.env.smtp_password
95
+ Chamber.dig('smtp_password')
96
96
  # => 'my_password'
97
97
  ```
98
98
 
@@ -117,7 +117,7 @@ The names and logos for The Kompanee are trademarks of The Kompanee, Ltd.
117
117
  License
118
118
  --------------------------------------------------------------------------------
119
119
 
120
- Chamber is Copyright © 2014-2021 Jeff Felchner and Mark McEahern. It is free
120
+ Chamber is Copyright © 2014-2023 Jeff Felchner and Mark McEahern. It is free
121
121
  software, and may be redistributed under the terms specified in the
122
122
  [LICENSE][license] file.
123
123
 
@@ -23,7 +23,7 @@ class Runner < Thor
23
23
  class_option :rootpath,
24
24
  type: :string,
25
25
  aliases: '-r',
26
- default: ENV['PWD'],
26
+ default: ENV.fetch('PWD', nil),
27
27
  desc: 'The root filepath of the application'
28
28
 
29
29
  class_option :basepath,
@@ -6,15 +6,15 @@ require 'chamber/instance'
6
6
  module Chamber
7
7
  module Commands
8
8
  class Base
9
- def self.call(**args)
10
- new(**args).call
11
- end
12
-
13
9
  attr_accessor :chamber,
14
10
  :dry_run,
15
11
  :rootpath,
16
12
  :shell
17
13
 
14
+ def self.call(**args)
15
+ new(**args).call
16
+ end
17
+
18
18
  def initialize(shell: nil, rootpath: nil, dry_run: nil, **args)
19
19
  self.chamber = Chamber::Instance.new(rootpath: rootpath, **args)
20
20
  self.shell = shell
@@ -11,14 +11,14 @@ require 'chamber/commands/base'
11
11
  module Chamber
12
12
  module Commands
13
13
  class Initialize < Chamber::Commands::Base
14
- def self.call(**args)
15
- new(**args).call
16
- end
17
-
18
14
  attr_accessor :basepath,
19
15
  :namespaces,
20
16
  :signature
21
17
 
18
+ def self.call(**args)
19
+ new(**args).call
20
+ end
21
+
22
22
  def initialize(signature:, namespaces: [], **args)
23
23
  super(**args)
24
24
 
@@ -52,11 +52,10 @@ module Securable
52
52
  Shellwords.escape(filename)
53
53
  end
54
54
 
55
- `
56
- git ls-files --other --ignored --exclude-per-directory=.gitignore |
57
- sed -e "s|^|#{Shellwords.escape(rootpath.to_s)}/|" |
58
- grep --colour=never -E '#{shell_escaped_chamber_filenames.join('|')}'
59
- `.split("\n")
55
+ `git ls-files --other --ignored --exclude-per-directory=.gitignore`
56
+ .split("\n")
57
+ .map { |filename| "#{Shellwords.escape(rootpath.to_s)}/#{filename}" }
58
+ .select { |filename| shell_escaped_chamber_filenames.include?(filename) }
60
59
  end
61
60
  end
62
61
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp'
4
3
  require 'chamber/commands/base'
5
4
 
6
5
  module Chamber
@@ -10,6 +10,10 @@ module Chamber
10
10
  class ContextResolver
11
11
  attr_accessor :options
12
12
 
13
+ def self.resolve(**args)
14
+ new(**args).resolve
15
+ end
16
+
13
17
  def initialize(**args)
14
18
  self.options = args
15
19
  end
@@ -48,10 +52,6 @@ class ContextResolver
48
52
  end
49
53
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Layout/LineLength
50
54
 
51
- def self.resolve(**args)
52
- new(**args).resolve
53
- end
54
-
55
55
  protected
56
56
 
57
57
  def resolve_namespaces(other)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Chamber
4
4
  module Errors
5
- class DisallowedClass < ::Psych::DisallowedClass
5
+ class DisallowedClass < ::ArgumentError
6
6
  end
7
7
  end
8
8
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chamber
4
+ module Errors
5
+ class InvalidKeyType < ::ArgumentError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chamber
4
+ module Errors
5
+ class MissingIndex < ::IndexError
6
+ def initialize(missing_index, all_keys)
7
+ super(<<~HEREDOC.chomp)
8
+ You attempted to access setting '#{all_keys.join(':')}' but the index '#{missing_index}' in the array did not exist.
9
+ HEREDOC
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chamber
4
+ module Errors
5
+ class MissingSetting < ::KeyError
6
+ def initialize(missing_key, all_keys)
7
+ super(<<~HEREDOC.chomp)
8
+ You attempted to access setting '#{all_keys.join(':')}' but '#{missing_key}' did not exist.
9
+ HEREDOC
10
+ end
11
+ end
12
+ end
13
+ end
@@ -256,7 +256,6 @@ class FileSet
256
256
 
257
257
  private
258
258
 
259
- # rubocop:disable Performance/ChainArrayAllocation
260
259
  def all_files
261
260
  @all_files ||= file_globs
262
261
  .map { |fg| Pathname.glob(fg) }
@@ -264,7 +263,6 @@ class FileSet
264
263
  .uniq
265
264
  .sort
266
265
  end
267
- # rubocop:enable Performance/ChainArrayAllocation
268
266
 
269
267
  def non_namespaced_files
270
268
  @non_namespaced_files ||= all_files - namespaced_files
@@ -35,16 +35,16 @@ class DecryptionFilter
35
35
  :secure_key_token
36
36
  attr_reader :decryption_keys
37
37
 
38
+ def self.execute(**args)
39
+ new(**args).__send__(:execute)
40
+ end
41
+
38
42
  def initialize(data:, secure_key_prefix:, decryption_keys: {}, **_args)
39
43
  self.decryption_keys = (decryption_keys || {}).transform_keys(&:to_s)
40
44
  self.data = data.deep_dup
41
45
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
42
46
  end
43
47
 
44
- def self.execute(**args)
45
- new(**args).__send__(:execute)
46
- end
47
-
48
48
  protected
49
49
 
50
50
  def execute(raw_data = data)
@@ -28,16 +28,16 @@ class EncryptionFilter
28
28
  :secure_key_token
29
29
  attr_reader :encryption_keys
30
30
 
31
+ def self.execute(**args)
32
+ new(**args).__send__(:execute)
33
+ end
34
+
31
35
  def initialize(data:, secure_key_prefix:, encryption_keys: {}, **_args)
32
36
  self.encryption_keys = (encryption_keys || {}).transform_keys(&:to_s)
33
37
  self.data = data.deep_dup
34
38
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
35
39
  end
36
40
 
37
- def self.execute(**args)
38
- new(**args).__send__(:execute)
39
- end
40
-
41
41
  protected
42
42
 
43
43
  def execute(raw_data = data, namespace = nil)
@@ -7,6 +7,9 @@ require 'chamber/errors/environment_conversion'
7
7
  module Chamber
8
8
  module Filters
9
9
  class EnvironmentFilter
10
+ attr_accessor :data,
11
+ :secure_key_token
12
+
10
13
  ###
11
14
  # Internal: Allows the existing environment to be injected into the passed in
12
15
  # hash. The hash that is passed in is *not* modified, instead a new hash is
@@ -91,9 +94,6 @@ class EnvironmentFilter
91
94
  new(**args).__send__(:execute)
92
95
  end
93
96
 
94
- attr_accessor :data,
95
- :secure_key_token
96
-
97
97
  def initialize(data:, secure_key_prefix:, **_args)
98
98
  self.data = data
99
99
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
@@ -111,7 +111,7 @@ class EnvironmentFilter
111
111
  lambda do |key, value, environment_key|
112
112
  {
113
113
  key => convert_environment_value(environment_key,
114
- ENV[environment_key],
114
+ ENV.fetch(environment_key, nil),
115
115
  value),
116
116
  }
117
117
  end,
@@ -10,13 +10,13 @@ class FailedDecryptionFilter
10
10
 
11
11
  BASE64_STRING_PATTERN = %r{\A[A-Za-z0-9+/]{342}==\z}.freeze
12
12
 
13
+ attr_accessor :data,
14
+ :secure_key_token
15
+
13
16
  def self.execute(**args)
14
17
  new(**args).__send__(:execute)
15
18
  end
16
19
 
17
- attr_accessor :data,
18
- :secure_key_token
19
-
20
20
  def initialize(data:, secure_key_prefix:, **_args)
21
21
  self.data = data.deep_dup
22
22
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
@@ -9,13 +9,13 @@ class NamespaceFilter
9
9
  using ::Chamber::Refinements::DeepDup
10
10
  using ::Chamber::Refinements::Hash
11
11
 
12
+ attr_accessor :data,
13
+ :namespaces
14
+
12
15
  def self.execute(**args)
13
16
  new(**args).__send__(:execute)
14
17
  end
15
18
 
16
- attr_accessor :data,
17
- :namespaces
18
-
19
19
  def initialize(data:, namespaces:, **_args)
20
20
  self.data = data.deep_dup
21
21
  self.namespaces = namespaces
@@ -7,13 +7,13 @@ module Filters
7
7
  class SecureFilter
8
8
  using ::Chamber::Refinements::DeepDup
9
9
 
10
+ attr_accessor :data,
11
+ :secure_key_token
12
+
10
13
  def self.execute(**args)
11
14
  new(**args).__send__(:execute)
12
15
  end
13
16
 
14
- attr_accessor :data,
15
- :secure_key_token
16
-
17
17
  def initialize(data:, secure_key_prefix:, **_args)
18
18
  self.data = data.deep_dup
19
19
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
@@ -7,13 +7,13 @@ module Filters
7
7
  class TranslateSecureKeysFilter
8
8
  using ::Chamber::Refinements::DeepDup
9
9
 
10
+ attr_accessor :data,
11
+ :secure_key_token
12
+
10
13
  def self.execute(**args)
11
14
  new(**args).__send__(:execute)
12
15
  end
13
16
 
14
- attr_accessor :data,
15
- :secure_key_token
16
-
17
17
  def initialize(data:, secure_key_prefix:, **_args)
18
18
  self.data = data.deep_dup
19
19
  self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
@@ -7,7 +7,7 @@ module Integrations
7
7
  module Sinatra
8
8
  def self.registered(app)
9
9
  app.configure do |inner_app|
10
- env = inner_app.environment || ENV['RACK_ENV']
10
+ env = inner_app.environment || ENV.fetch('RACK_ENV', nil)
11
11
  root = inner_app.root
12
12
 
13
13
  if defined?(Padrino)
@@ -3,14 +3,14 @@
3
3
  module Chamber
4
4
  module Keys
5
5
  class Base
6
- def self.resolve(**args)
7
- new(**args).resolve
8
- end
9
-
10
6
  attr_accessor :rootpath
11
7
  attr_reader :filenames,
12
8
  :namespaces
13
9
 
10
+ def self.resolve(**args)
11
+ new(**args).resolve
12
+ end
13
+
14
14
  def initialize(rootpath:, namespaces:, filenames: nil)
15
15
  self.rootpath = Pathname.new(rootpath)
16
16
  self.namespaces = namespaces
@@ -20,7 +20,11 @@ class Base
20
20
  def resolve
21
21
  key_paths.each_with_object({}) do |path, memo|
22
22
  namespace = namespace_from_path(path) || '__default'
23
- value = path.readable? ? path.read : ENV[environment_variable_from_path(path)]
23
+ value = if path.readable?
24
+ path.read
25
+ else
26
+ ENV.fetch(environment_variable_from_path(path), nil)
27
+ end
24
28
 
25
29
  memo[namespace.downcase.to_sym] = value if value
26
30
  end
@@ -39,13 +43,13 @@ class Base
39
43
  namespaces.map { |n| namespace_to_key_path(n) }
40
44
  end
41
45
 
42
- # rubocop:disable Performance/ChainArrayAllocation, Performance/MapCompact
46
+ # rubocop:disable Performance/MapCompact
43
47
  def filenames=(other)
44
48
  @filenames = Array(other)
45
49
  .map { |o| Pathname.new(o) }
46
50
  .compact
47
51
  end
48
- # rubocop:enable Performance/ChainArrayAllocation, Performance/MapCompact
52
+ # rubocop:enable Performance/MapCompact
49
53
 
50
54
  def namespaces=(other)
51
55
  @namespaces = other + %w{signature}
@@ -14,6 +14,8 @@ module Chamber
14
14
  class NamespaceSet
15
15
  include Enumerable
16
16
 
17
+ attr_reader :raw_namespaces
18
+
17
19
  ###
18
20
  # Internal: Allows for more compact NamespaceSet creation by giving a list of
19
21
  # namespace values.
@@ -28,8 +30,6 @@ class NamespaceSet
28
30
  new(namespace_values)
29
31
  end
30
32
 
31
- attr_reader :raw_namespaces
32
-
33
33
  ###
34
34
  # Internal: Creates a new NamespaceSet from arrays, hashes and sets.
35
35
  #
data/lib/chamber/rails.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'chamber/integrations/rails' if defined?(::Rails)
3
+ require 'chamber/integrations/rails' if defined?(Rails)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'chamber/errors/missing_index'
4
+ require 'chamber/errors/missing_setting'
3
5
  require 'chamber/namespace_set'
4
6
  require 'chamber/filters/namespace_filter'
5
7
  require 'chamber/filters/encryption_filter'
@@ -236,9 +238,13 @@ class Settings
236
238
  end
237
239
 
238
240
  def [](key)
239
- fail ::ArgumentError, 'Bracket access with anything other than a String is unsupported.' unless key.is_a?(::String)
241
+ fail ::Chamber::Errors::InvalidKeyType, 'Bracket access with anything other than a String is unsupported.' unless key.is_a?(::String)
240
242
 
241
243
  data.fetch(key)
244
+ rescue ::KeyError => error
245
+ missing_setting_name = error.message.gsub(/.*key not found: "([^"]+)".*/, '\1')
246
+
247
+ raise ::Chamber::Errors::MissingSetting.new(missing_setting_name, [])
242
248
  end
243
249
 
244
250
  def dig!(*args)
@@ -247,11 +253,21 @@ class Settings
247
253
 
248
254
  data_value.fetch(key)
249
255
  end
256
+ rescue ::KeyError => error
257
+ missing_setting_name = error.message.gsub(/.*key not found: "([^"]+)".*/, '\1')
258
+
259
+ raise ::Chamber::Errors::MissingSetting.new(missing_setting_name, args)
260
+ rescue ::IndexError => error
261
+ missing_index_number = error.message.gsub(/.*index (\d+) outside.*/, '\1')
262
+
263
+ raise ::Chamber::Errors::MissingIndex.new(missing_index_number, args)
250
264
  end
251
265
 
252
266
  def dig(*args)
253
267
  dig!(*args)
254
- rescue ::KeyError, ::IndexError # rubocop:disable Lint/ShadowedException
268
+ rescue ::Chamber::Errors::MissingSetting,
269
+ ::Chamber::Errors::MissingIndex
270
+
255
271
  nil
256
272
  end
257
273
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chamber
4
- VERSION = '3.0.0rc2'
4
+ VERSION = '3.0.0'
5
5
  end
data.tar.gz.sig CHANGED
Binary file
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: 3.0.0rc2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thekompanee
@@ -14,8 +14,8 @@ cert_chain:
14
14
  - |
15
15
  -----BEGIN CERTIFICATE-----
16
16
  MIIEdjCCAt6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAyMTAwLgYDVQQDDCdhY2Nv
17
- dW50c19ydWJ5Z2Vtcy9EQz10aGVrb21wYW5lZS9EQz1jb20wHhcNMjIwMzA1MjM0
18
- OTEzWhcNMjMwMzA1MjM0OTEzWjAyMTAwLgYDVQQDDCdhY2NvdW50c19ydWJ5Z2Vt
17
+ dW50c19ydWJ5Z2Vtcy9EQz10aGVrb21wYW5lZS9EQz1jb20wHhcNMjMwMzA2MDM0
18
+ ODUxWhcNMjYwMzA1MDM0ODUxWjAyMTAwLgYDVQQDDCdhY2NvdW50c19ydWJ5Z2Vt
19
19
  cy9EQz10aGVrb21wYW5lZS9EQz1jb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw
20
20
  ggGKAoIBgQD0Z84PxtE0iiWCMTQbnit6D4w55GGBQZnhpWUCJwC0SpQ/jnT0Fsma
21
21
  g8oAIdDclLvLC9jzqSAmkOujlpkJMb5NabgkhKFwHi6cVW/gz/cVnISAv8LQTIM5
@@ -28,17 +28,17 @@ cert_chain:
28
28
  y7jqKMpOE1UCAwEAAaOBljCBkzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNV
29
29
  HQ4EFgQU7+XQuN042fZGvzLhYbIwDfsxZV8wLAYDVR0RBCUwI4EhYWNjb3VudHMr
30
30
  cnVieWdlbXNAdGhla29tcGFuZWUuY29tMCwGA1UdEgQlMCOBIWFjY291bnRzK3J1
31
- YnlnZW1zQHRoZWtvbXBhbmVlLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEA04F3jVFD
32
- BwHv8GVMkvUAc7r247lEEYfYuU/Iq0fivT1ugxN9pqT/ODwyPSdYy4Aqj8j4HHbM
33
- 2OQcKXb9SXjlIa/u5McPlhbsTQozs77bXOmrlAXN6shRJtTKSKm5ttmM/sDeks6p
34
- wdhM0KHu5PBFZQjWfJuqi0hH13l0qQH+8r2GzXTHMKNX+6m1cTAkP81OPFIekn0l
35
- boFRgsIr1j335pLV/+hgCRNSlU84E59YVVm+W9kP0Ym/n6051mBaaEMsWnm3td7a
36
- c7BNPTxfmZrtz3TVq9VvzdHad3/+1QdNl9+l3VdL7wZ3GKZLhyifn7dc5EXxiZHJ
37
- eDcSScq4x5NTMajXoJLKcoQPJDL7rUpPtvGj3v9O20RzHlWVDqVdzeYlswDjIqwe
38
- ZjvLRaDI6IVoq0skZju//VZLiN6slVhAYYQj0uka/T0DZieabVYDcT4BVpa9M7Gz
39
- CDW/VDWjvEEbsCIW0oYhtUrkqE8GLIdrpLUjefOERbS5TslD7lG/MH5k
31
+ YnlnZW1zQHRoZWtvbXBhbmVlLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAIaR7p1yv
32
+ +nE+JX/7nItZ0YKE71L6JdAuAlUfvTuHq8S1dpKdewrm3ewNPGt2nK9svy8vxNUQ
33
+ AqT3KWIaGVwkslL/y/MRxBQHOOZz9XCMmUYXIencNXqNzkWLubcCK7uF1h8mRS46
34
+ jvGfiXfYDwi8QzqJA8IFEK/oyKCCKlNiIbz8Q4yHM4wTqLwjYQqlHiBEgCF2UHc6
35
+ 0tCTD8eixdZUeuexdB7M7F/M086y1wjWyYCeijqbKmTPqKb8n6AmLo0fqkNBVibJ
36
+ nYVEOECVzKt/f3PoG0Z2oMnZ6FKqpFiDpPqgAlRDmVznjpMdZR204/t79NoEVlLf
37
+ lxz9Q1u83TUBUPvDRzKg6Kq9P28JV1Ipnst0ecQZOsnoLjl1BmxUt29hQPJKjd11
38
+ Z6HMkN0PHJ6eG0Zl3/H4H8Xb+KreWlEx3sXXfZj6UscrdHAVffRQnM1E98PCqnRX
39
+ l5EwT4ShG/HorJMQSTY1EoBLZf54NrD5WlWcfM0CLrcvT7QM77dIqmue
40
40
  -----END CERTIFICATE-----
41
- date: 2022-03-06 00:00:00.000000000 Z
41
+ date: 2023-03-07 00:00:00.000000000 Z
42
42
  dependencies:
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: thor
@@ -144,18 +144,8 @@ files:
144
144
  - README.md
145
145
  - bin/chamber
146
146
  - lib/chamber.rb
147
- - lib/chamber/adapters/cloud/circle_ci.rb
148
- - lib/chamber/adapters/cloud/heroku.rb
149
- - lib/chamber/binary/circle_ci.rb
150
- - lib/chamber/binary/heroku.rb
151
147
  - lib/chamber/binary/runner.rb
152
- - lib/chamber/binary/travis.rb
153
148
  - lib/chamber/commands/base.rb
154
- - lib/chamber/commands/cloud/base.rb
155
- - lib/chamber/commands/cloud/clear.rb
156
- - lib/chamber/commands/cloud/compare.rb
157
- - lib/chamber/commands/cloud/pull.rb
158
- - lib/chamber/commands/cloud/push.rb
159
149
  - lib/chamber/commands/comparable.rb
160
150
  - lib/chamber/commands/compare.rb
161
151
  - lib/chamber/commands/files.rb
@@ -165,7 +155,6 @@ files:
165
155
  - lib/chamber/commands/show.rb
166
156
  - lib/chamber/commands/sign.rb
167
157
  - lib/chamber/commands/travis.rb
168
- - lib/chamber/commands/travis/secure.rb
169
158
  - lib/chamber/commands/verify.rb
170
159
  - lib/chamber/configuration.rb
171
160
  - lib/chamber/context_resolver.rb
@@ -175,6 +164,9 @@ files:
175
164
  - lib/chamber/errors/decryption_failure.rb
176
165
  - lib/chamber/errors/disallowed_class.rb
177
166
  - lib/chamber/errors/environment_conversion.rb
167
+ - lib/chamber/errors/invalid_key_type.rb
168
+ - lib/chamber/errors/missing_index.rb
169
+ - lib/chamber/errors/missing_setting.rb
178
170
  - lib/chamber/errors/non_conforming_key.rb
179
171
  - lib/chamber/file.rb
180
172
  - lib/chamber/file_set.rb
@@ -226,9 +218,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
226
218
  version: 2.7.5
227
219
  required_rubygems_version: !ruby/object:Gem::Requirement
228
220
  requirements:
229
- - - ">"
221
+ - - ">="
230
222
  - !ruby/object:Gem::Version
231
- version: 1.3.1
223
+ version: '0'
232
224
  requirements: []
233
225
  rubygems_version: 3.1.6
234
226
  signing_key:
metadata.gz.sig CHANGED
Binary file
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
- require 'net/http'
5
- require 'uri'
6
-
7
- module Chamber
8
- module Adapters
9
- module Cloud
10
- class CircleCi
11
- API_HOST = 'circleci.com'
12
- API_PORT = 443
13
- API_BASE_URI = '/api/v1.1'
14
-
15
- attr_accessor :api_token,
16
- :project,
17
- :username,
18
- :vcs_type
19
-
20
- def initialize(api_token:, project:, username:, vcs_type:)
21
- self.api_token = api_token
22
- self.project = project
23
- self.username = username
24
- self.vcs_type = vcs_type
25
- end
26
-
27
- def add_environment_variable(name, value)
28
- value = value.gsub(/\n/, '\n')
29
- request = ::Net::HTTP::Post.new(request_uri(resource: 'envvar'))
30
-
31
- request.basic_auth api_token, ''
32
- request['Content-Type'] = 'application/json'
33
- request.body = ::JSON.dump(name: name, value: value)
34
-
35
- response = ::JSON.parse(response(request).body)
36
-
37
- fail NameError, response['message'] if response['message']
38
-
39
- response['name']
40
- end
41
-
42
- # rubocop:disable Layout/MultilineAssignmentLayout
43
- def environment_variables
44
- @environment_variables ||= \
45
- begin
46
- request = ::Net::HTTP::Get.new(request_uri(resource: 'envvar'))
47
-
48
- request.basic_auth api_token, ''
49
- request['Content-Type'] = 'application/json'
50
-
51
- ::JSON
52
- .parse(response(request).body)
53
- .each_with_object({}) { |e, m| m[e['name']] = e['value'] }
54
- end
55
- end
56
- # rubocop:enable Layout/MultilineAssignmentLayout
57
-
58
- def remove_environment_variable(name)
59
- request = ::Net::HTTP::Delete.new(request_uri(resource: "envvar/#{name}"))
60
-
61
- request.basic_auth api_token, ''
62
- request['Content-Type'] = 'application/json'
63
-
64
- ::JSON.parse(response(request).body)['message'] == 'ok'
65
- end
66
-
67
- private
68
-
69
- def request_uri(resource:)
70
- "#{API_BASE_URI}/project/#{vcs_type}/#{username}/#{project}/#{resource}"
71
- end
72
-
73
- def response(request)
74
- connection.request(request)
75
- end
76
-
77
- def connection
78
- @connection ||= ::Net::HTTP.new(API_HOST, API_PORT).tap do |conn|
79
- conn.use_ssl = true
80
- end
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
- require 'net/http'
5
- require 'uri'
6
-
7
- module Chamber
8
- module Adapters
9
- module Cloud
10
- class Heroku
11
- API_HOST = 'api.heroku.com'
12
- API_PORT = 443
13
- API_BASE_URI = ''
14
-
15
- attr_accessor :api_token,
16
- :app
17
-
18
- def initialize(api_token:, app:)
19
- self.api_token = api_token
20
- self.app = app
21
- end
22
-
23
- def add_environment_variable(name, value)
24
- value = value.gsub(/\n/, '\n') if value
25
- request = ::Net::HTTP::Patch.new(config_vars_uri)
26
-
27
- request['Authorization'] = "Bearer #{api_token}"
28
- request['Accept'] = 'application/vnd.heroku+json; version=3'
29
- request['Content-Type'] = 'application/json'
30
- request.body = ::JSON.dump({ name => value })
31
-
32
- response = ::JSON.parse(response(request).body)
33
-
34
- fail NameError, response['message'] if response['message']
35
-
36
- response
37
- end
38
-
39
- def environment_variables
40
- request = ::Net::HTTP::Get.new(config_vars_uri)
41
-
42
- request['Authorization'] = "Bearer #{api_token}"
43
- request['Accept'] = 'application/vnd.heroku+json; version=3'
44
-
45
- response = ::JSON.parse(response(request).body)
46
-
47
- fail NameError, response['message'] if response['message']
48
-
49
- response
50
- end
51
-
52
- def remove_environment_variable(name)
53
- add_environment_variable(name, nil)
54
- end
55
-
56
- private
57
-
58
- def config_vars_uri
59
- "#{API_BASE_URI}/apps/#{app}/config-vars"
60
- end
61
-
62
- def response(request)
63
- connection.request(request)
64
- end
65
-
66
- def connection
67
- @connection ||= ::Net::HTTP.new(API_HOST, API_PORT).tap do |conn|
68
- conn.use_ssl = true
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'thor'
4
- require 'chamber/commands/cloud/clear'
5
- require 'chamber/commands/cloud/push'
6
- require 'chamber/commands/cloud/pull'
7
- require 'chamber/commands/cloud/compare'
8
-
9
- module Chamber
10
- module Binary
11
- class CircleCi < Thor
12
- include Thor::Actions
13
-
14
- class_option :api_token,
15
- type: :string,
16
- aliases: '-t',
17
- required: true,
18
- desc: 'The API token to access your CircleCI project.'
19
-
20
- class_option :project,
21
- type: :string,
22
- aliases: '-p',
23
- required: true,
24
- desc: 'The project name in your VCS (eg Github).'
25
-
26
- class_option :username,
27
- type: :string,
28
- aliases: '-u',
29
- required: true,
30
- desc: 'The user/organization name in your VCS (eg Github).'
31
-
32
- class_option :vcs_type,
33
- type: :string,
34
- aliases: '-v',
35
- default: 'github',
36
- desc: 'The type of VCS your project is using.',
37
- enum: %w{github bitbucket}
38
-
39
- desc 'clear',
40
- 'Removes all CircleCi environment variables which match settings that Chamber ' \
41
- 'knows about'
42
-
43
- method_option :dry_run,
44
- type: :boolean,
45
- aliases: '-d',
46
- desc: 'Does not actually remove anything, but instead displays what ' \
47
- 'would change if cleared'
48
-
49
- def clear
50
- Commands::Cloud::Clear.call(**options
51
- .transform_keys(&:to_sym)
52
- .merge(shell: self, adapter: 'circle_ci'))
53
- end
54
-
55
- desc 'push',
56
- 'Sends settings to CircleCi so that they may be used in the application ' \
57
- 'once it is deployed'
58
-
59
- method_option :dry_run,
60
- type: :boolean,
61
- aliases: '-d',
62
- desc: 'Does not actually push anything to CircleCi, but instead ' \
63
- 'displays what would change if pushed'
64
-
65
- method_option :keys,
66
- type: :boolean,
67
- aliases: '-k',
68
- desc: 'Pushes private Chamber keys to CircleCi as environment ' \
69
- 'variables. Chamber will automatically detect it and ' \
70
- 'transparently decrypt your secure settings without any ' \
71
- 'further synchronization.'
72
-
73
- method_option :only_sensitive,
74
- type: :boolean,
75
- aliases: '-o',
76
- default: true,
77
- desc: 'When enabled, only settings contained in files which have ' \
78
- 'been gitignored or settings which are marked as "_secure" ' \
79
- 'will be pushed'
80
-
81
- def push
82
- Commands::Cloud::Push.call(**options
83
- .transform_keys(&:to_sym)
84
- .merge(shell: self, adapter: 'circle_ci'))
85
- end
86
-
87
- desc 'pull',
88
- 'Retrieves the environment variables for the application and stores them in a ' \
89
- 'temporary file'
90
-
91
- method_option :into,
92
- type: :string,
93
- desc: 'The file into which the CircleCi config information should be ' \
94
- 'stored. This file WILL BE OVERRIDDEN.'
95
-
96
- def pull
97
- Commands::Cloud::Pull.call(**options
98
- .transform_keys(&:to_sym)
99
- .merge(shell: self, adapter: 'circle_ci'))
100
- end
101
-
102
- desc 'compare',
103
- 'Displays the difference between what is currently stored in the ' \
104
- 'CircleCi application\'s config and what Chamber knows about locally'
105
-
106
- method_option :only_sensitive,
107
- type: :boolean,
108
- aliases: '-o',
109
- default: true,
110
- desc: 'When enabled, the diff will only consider settings ' \
111
- 'contained in files which have been gitignored or settings ' \
112
- 'which are marked as "_secure"'
113
-
114
- def compare
115
- Commands::Cloud::Compare.call(**options
116
- .transform_keys(&:to_sym)
117
- .merge(shell: self, adapter: 'circle_ci'))
118
- end
119
- end
120
- end
121
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'thor'
4
- require 'chamber/commands/cloud/clear'
5
- require 'chamber/commands/cloud/push'
6
- require 'chamber/commands/cloud/pull'
7
- require 'chamber/commands/cloud/compare'
8
-
9
- module Chamber
10
- module Binary
11
- class Heroku < Thor
12
- include Thor::Actions
13
-
14
- class_option :app,
15
- type: :string,
16
- aliases: '-a',
17
- required: true,
18
- desc: 'The name of the Heroku application whose config values will ' \
19
- 'be affected'
20
-
21
- class_option :api_token,
22
- type: :string,
23
- aliases: '-t',
24
- required: true,
25
- desc: 'The API token to access your Heroku project.'
26
-
27
- desc 'clear',
28
- 'Removes all Heroku environment variables which match settings that ' \
29
- 'Chamber knows about'
30
-
31
- method_option :dry_run,
32
- type: :boolean,
33
- aliases: '-d',
34
- desc: 'Does not actually remove anything, but instead displays what ' \
35
- 'would change if cleared'
36
-
37
- def clear
38
- Commands::Cloud::Clear.call(**options
39
- .transform_keys(&:to_sym)
40
- .merge(shell: self, adapter: 'heroku'))
41
- end
42
-
43
- desc 'push',
44
- 'Sends settings to Heroku so that they may be used in the application ' \
45
- 'once it is deployed'
46
-
47
- method_option :dry_run,
48
- type: :boolean,
49
- aliases: '-d',
50
- desc: 'Does not actually push anything to Heroku, but instead ' \
51
- 'displays what would change if pushed'
52
-
53
- method_option :keys,
54
- type: :boolean,
55
- aliases: '-k',
56
- desc: 'Pushes private Chamber keys to Heroku as environment ' \
57
- 'variables. Chamber will automatically detect it and ' \
58
- 'transparently decrypt your secure settings without any ' \
59
- 'further synchronization.'
60
-
61
- method_option :only_sensitive,
62
- type: :boolean,
63
- aliases: '-o',
64
- default: true,
65
- desc: 'When enabled, only settings contained in files which have ' \
66
- 'been gitignored or settings which are marked as "_secure" ' \
67
- 'will be pushed'
68
-
69
- def push
70
- Commands::Cloud::Push.call(**options
71
- .transform_keys(&:to_sym)
72
- .merge(shell: self, adapter: 'heroku'))
73
- end
74
-
75
- desc 'pull',
76
- 'Retrieves the environment variables for the application and stores ' \
77
- 'them in a temporary file'
78
-
79
- method_option :into,
80
- type: :string,
81
- desc: 'The file into which the Heroku config information should be ' \
82
- 'stored. This file WILL BE OVERRIDDEN.'
83
-
84
- def pull
85
- Commands::Cloud::Pull.call(**options
86
- .transform_keys(&:to_sym)
87
- .merge(shell: self, adapter: 'heroku'))
88
- end
89
-
90
- desc 'compare',
91
- 'Displays the difference between what is currently stored in the ' \
92
- 'Heroku application\'s config and what Chamber knows about locally'
93
-
94
- method_option :only_sensitive,
95
- type: :boolean,
96
- aliases: '-o',
97
- default: true,
98
- desc: 'When enabled, the diff will only consider settings ' \
99
- 'contained in files which have been gitignored or settings ' \
100
- 'which are marked as "_secure"'
101
-
102
- def compare
103
- Commands::Cloud::Compare.call(**options
104
- .transform_keys(&:to_sym)
105
- .merge(shell: self, adapter: 'heroku'))
106
- end
107
- end
108
- end
109
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'thor'
4
- require 'chamber/commands/travis/secure'
5
-
6
- module Chamber
7
- module Binary
8
- class Travis < Thor
9
- desc 'secure',
10
- 'Uses your Travis CI public key to encrypt the settings you have ' \
11
- 'chosen not to commit to the repo'
12
-
13
- method_option :dry_run,
14
- type: :boolean,
15
- aliases: '-d',
16
- desc: 'Does not actually encrypt anything to .travis.yml, but ' \
17
- 'instead displays what values would be encrypted'
18
-
19
- method_option :only_sensitive,
20
- type: :boolean,
21
- aliases: '-o',
22
- default: true,
23
- desc: 'Does not encrypt settings into .travis.yml unless they are ' \
24
- 'contained in files which have been gitignored or settings ' \
25
- 'which are marked as "_secure"'
26
-
27
- def secure
28
- Commands::Travis::Secure.call(**options.transform_keys(&:to_sym).merge(shell: self))
29
- end
30
- end
31
- end
32
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'chamber/commands/base'
4
-
5
- module Chamber
6
- module Commands
7
- module Cloud
8
- class Base < Chamber::Commands::Base
9
- attr_accessor :adapter
10
-
11
- def initialize(adapter:, **args)
12
- super(**args)
13
-
14
- self.adapter = adapter_class(adapter).new(**args)
15
- end
16
-
17
- private
18
-
19
- def adapter_class(adapter_name)
20
- require "chamber/adapters/cloud/#{adapter_name}"
21
-
22
- @adapter_class ||= case adapter_name
23
- when 'circle_ci'
24
- Chamber::Adapters::Cloud::CircleCi
25
- when 'heroku'
26
- Chamber::Adapters::Cloud::Heroku
27
- else
28
- fail ArgumentError,
29
- "Invalid Chamber cloud adapter name: #{adapter_name}"
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'chamber/commands/cloud/base'
4
-
5
- module Chamber
6
- module Commands
7
- module Cloud
8
- class Clear < Chamber::Commands::Cloud::Base
9
- def call
10
- chamber.to_environment.each_key do |key|
11
- next unless adapter.environment_variables.has_key?(key)
12
-
13
- if dry_run
14
- shell.say_status 'remove', key, :blue
15
- else
16
- shell.say_status 'remove', key, :green
17
-
18
- adapter.remove_environment_variable(key)
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'chamber/commands/cloud/base'
4
- require 'chamber/commands/comparable'
5
- require 'chamber/commands/securable'
6
-
7
- module Chamber
8
- module Commands
9
- module Cloud
10
- class Compare < Chamber::Commands::Cloud::Base
11
- include Chamber::Commands::Securable
12
- include Chamber::Commands::Comparable
13
-
14
- protected
15
-
16
- def first_settings_data
17
- ::JSON.pretty_generate(securable_environment_variables)
18
- end
19
-
20
- def second_settings_data
21
- ::JSON.pretty_generate(adapter.environment_variables)
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
- require 'chamber/commands/cloud/base'
5
-
6
- module Chamber
7
- module Commands
8
- module Cloud
9
- class Pull < Chamber::Commands::Cloud::Base
10
- attr_accessor :target_file
11
-
12
- def initialize(into:, **args)
13
- super
14
-
15
- self.target_file = into
16
- end
17
-
18
- def call
19
- if target_file
20
- shell.create_file(target_file,
21
- ::JSON.pretty_generate(adapter.environment_variables))
22
- else
23
- adapter.environment_variables
24
- end
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'chamber/commands/cloud/base'
4
- require 'chamber/commands/securable'
5
- require 'chamber/keys/decryption'
6
-
7
- module Chamber
8
- module Commands
9
- module Cloud
10
- class Push < Chamber::Commands::Cloud::Base
11
- include Chamber::Commands::Securable
12
-
13
- attr_accessor :keys
14
-
15
- def initialize(keys:, **args)
16
- super(**args)
17
-
18
- self.keys = keys
19
- end
20
-
21
- def call
22
- environment_variables = if keys
23
- Keys::Decryption
24
- .new(rootpath: chamber.configuration.rootpath,
25
- namespaces: chamber.configuration.namespaces)
26
- .as_environment_variables
27
- else
28
- securable_environment_variables
29
- end
30
-
31
- environment_variables.each do |key, value|
32
- if dry_run
33
- shell.say_status 'push', key, :blue
34
- else
35
- shell.say_status 'push', key, :green
36
-
37
- adapter.add_environment_variable(key, value)
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'chamber/commands/base'
4
- require 'chamber/commands/travis'
5
- require 'chamber/commands/securable'
6
-
7
- module Chamber
8
- module Commands
9
- module Travis
10
- class Secure < Chamber::Commands::Base
11
- include Chamber::Commands::Travis
12
- include Chamber::Commands::Securable
13
-
14
- def call
15
- securable_environment_variables.each do |key, value|
16
- if dry_run
17
- shell.say_status 'encrypt', key, :blue
18
- else
19
- command = first_environment_variable?(key) ? '--override' : '--append'
20
-
21
- shell.say_status 'encrypt', key, :green
22
- travis_encrypt("#{command} #{key}=#{value}")
23
- end
24
- end
25
- end
26
-
27
- protected
28
-
29
- def first_environment_variable?(key)
30
- @first_environment_key ||= securable_environment_variables.first[0]
31
-
32
- @first_environment_key == key
33
- end
34
- end
35
- end
36
- end
37
- end