chamber 2.13.0 → 3.0.0rc1

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 (54) 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 +77 -16
  6. data/lib/chamber/adapters/cloud/circle_ci.rb +16 -13
  7. data/lib/chamber/adapters/cloud/heroku.rb +40 -13
  8. data/lib/chamber/binary/circle_ci.rb +28 -14
  9. data/lib/chamber/binary/heroku.rb +34 -14
  10. data/lib/chamber/binary/runner.rb +40 -29
  11. data/lib/chamber/binary/travis.rb +10 -4
  12. data/lib/chamber/commands/base.rb +10 -16
  13. data/lib/chamber/commands/cloud/base.rb +3 -3
  14. data/lib/chamber/commands/cloud/pull.rb +2 -2
  15. data/lib/chamber/commands/cloud/push.rb +7 -7
  16. data/lib/chamber/commands/comparable.rb +2 -2
  17. data/lib/chamber/commands/compare.rb +6 -9
  18. data/lib/chamber/commands/initialize.rb +26 -22
  19. data/lib/chamber/commands/securable.rb +12 -9
  20. data/lib/chamber/commands/secure.rb +2 -2
  21. data/lib/chamber/commands/show.rb +8 -8
  22. data/lib/chamber/commands/sign.rb +2 -2
  23. data/lib/chamber/commands/verify.rb +2 -2
  24. data/lib/chamber/configuration.rb +6 -3
  25. data/lib/chamber/context_resolver.rb +7 -7
  26. data/lib/chamber/encryption_methods/ssl.rb +12 -12
  27. data/lib/chamber/file.rb +20 -15
  28. data/lib/chamber/file_set.rb +18 -8
  29. data/lib/chamber/files/signature.rb +16 -14
  30. data/lib/chamber/filters/decryption_filter.rb +19 -15
  31. data/lib/chamber/filters/encryption_filter.rb +14 -11
  32. data/lib/chamber/filters/environment_filter.rb +21 -20
  33. data/lib/chamber/filters/failed_decryption_filter.rb +9 -6
  34. data/lib/chamber/filters/insecure_filter.rb +4 -5
  35. data/lib/chamber/filters/namespace_filter.rb +13 -9
  36. data/lib/chamber/filters/secure_filter.rb +9 -7
  37. data/lib/chamber/filters/translate_secure_keys_filter.rb +9 -7
  38. data/lib/chamber/instance.rb +48 -31
  39. data/lib/chamber/key_pair.rb +7 -7
  40. data/lib/chamber/keys/base.rb +13 -13
  41. data/lib/chamber/keys/decryption.rb +3 -3
  42. data/lib/chamber/keys/encryption.rb +3 -3
  43. data/lib/chamber/namespace_set.rb +2 -4
  44. data/lib/chamber/refinements/array.rb +20 -0
  45. data/lib/chamber/refinements/deep_dup.rb +58 -0
  46. data/lib/chamber/refinements/enumerable.rb +36 -0
  47. data/lib/chamber/refinements/hash.rb +51 -0
  48. data/lib/chamber/settings.rb +81 -66
  49. data/lib/chamber/types/secured.rb +21 -23
  50. data/lib/chamber/version.rb +1 -1
  51. data/templates/settings.yml +2 -0
  52. metadata +44 -51
  53. metadata.gz.sig +0 -0
  54. data/lib/chamber/core_ext/hash.rb +0 -15
@@ -5,11 +5,13 @@ require 'chamber/commands/cloud/clear'
5
5
  require 'chamber/commands/cloud/push'
6
6
  require 'chamber/commands/cloud/pull'
7
7
  require 'chamber/commands/cloud/compare'
8
+ require 'chamber/refinements/hash'
8
9
 
9
10
  module Chamber
10
11
  module Binary
11
- class Heroku < Thor
12
- include Thor::Actions
12
+ class Heroku < ::Thor
13
+ include ::Thor::Actions
14
+ using ::Chamber::Refinements::Hash
13
15
 
14
16
  class_option :app,
15
17
  type: :string,
@@ -18,8 +20,15 @@ class Heroku < Thor
18
20
  desc: 'The name of the Heroku application whose config values will ' \
19
21
  'be affected'
20
22
 
21
- desc 'clear', 'Removes all Heroku environment variables which match settings that ' \
22
- 'Chamber knows about'
23
+ class_option :api_token,
24
+ type: :string,
25
+ aliases: '-t',
26
+ required: true,
27
+ desc: 'The API token to access your Heroku project.'
28
+
29
+ desc 'clear',
30
+ 'Removes all Heroku environment variables which match settings that ' \
31
+ 'Chamber knows about'
23
32
 
24
33
  method_option :dry_run,
25
34
  type: :boolean,
@@ -28,11 +37,14 @@ class Heroku < Thor
28
37
  'would change if cleared'
29
38
 
30
39
  def clear
31
- Commands::Cloud::Clear.call(options.merge(shell: self, adapter: 'heroku'))
40
+ Commands::Cloud::Clear.call(**options
41
+ .deep_transform_keys(&:to_sym)
42
+ .merge(shell: self, adapter: 'heroku'))
32
43
  end
33
44
 
34
- desc 'push', 'Sends settings to Heroku so that they may be used in the application ' \
35
- 'once it is deployed'
45
+ desc 'push',
46
+ 'Sends settings to Heroku so that they may be used in the application ' \
47
+ 'once it is deployed'
36
48
 
37
49
  method_option :dry_run,
38
50
  type: :boolean,
@@ -57,11 +69,14 @@ class Heroku < Thor
57
69
  'will be pushed'
58
70
 
59
71
  def push
60
- Commands::Cloud::Push.call(options.merge(shell: self, adapter: 'heroku'))
72
+ Commands::Cloud::Push.call(**options
73
+ .deep_transform_keys(&:to_sym)
74
+ .merge(shell: self, adapter: 'heroku'))
61
75
  end
62
76
 
63
- desc 'pull', 'Retrieves the environment variables for the application and stores ' \
64
- 'them in a temporary file'
77
+ desc 'pull',
78
+ 'Retrieves the environment variables for the application and stores ' \
79
+ 'them in a temporary file'
65
80
 
66
81
  method_option :into,
67
82
  type: :string,
@@ -69,11 +84,14 @@ class Heroku < Thor
69
84
  'stored. This file WILL BE OVERRIDDEN.'
70
85
 
71
86
  def pull
72
- Commands::Cloud::Pull.call(options.merge(shell: self, adapter: 'heroku'))
87
+ Commands::Cloud::Pull.call(**options
88
+ .deep_transform_keys(&:to_sym)
89
+ .merge(shell: self, adapter: 'heroku'))
73
90
  end
74
91
 
75
- desc 'compare', 'Displays the difference between what is currently stored in the ' \
76
- 'Heroku application\'s config and what Chamber knows about locally'
92
+ desc 'compare',
93
+ 'Displays the difference between what is currently stored in the ' \
94
+ 'Heroku application\'s config and what Chamber knows about locally'
77
95
 
78
96
  method_option :only_sensitive,
79
97
  type: :boolean,
@@ -84,7 +102,9 @@ class Heroku < Thor
84
102
  'which are marked as "_secure"'
85
103
 
86
104
  def compare
87
- Commands::Cloud::Compare.call(options.merge(shell: self, adapter: 'heroku'))
105
+ Commands::Cloud::Compare.call(**options
106
+ .deep_transform_keys(&:to_sym)
107
+ .merge(shell: self, adapter: 'heroku'))
88
108
  end
89
109
  end
90
110
  end
@@ -12,13 +12,15 @@ require 'chamber/commands/sign'
12
12
  require 'chamber/commands/verify'
13
13
  require 'chamber/commands/compare'
14
14
  require 'chamber/commands/initialize'
15
+ require 'chamber/refinements/hash'
15
16
 
16
17
  module Chamber
17
18
  module Binary
18
- class Runner < Thor
19
- include Thor::Actions
19
+ class Runner < ::Thor
20
+ include ::Thor::Actions
21
+ using ::Chamber::Refinements::Hash
20
22
 
21
- source_root ::File.expand_path('../../../../templates', __FILE__)
23
+ source_root ::File.expand_path('../../../templates', __dir__)
22
24
 
23
25
  class_option :rootpath,
24
26
  type: :string,
@@ -62,17 +64,17 @@ class Runner < Thor
62
64
 
63
65
  ################################################################################
64
66
 
65
- desc 'travis SUBCOMMAND ...ARGS', 'For manipulating Travis CI environment variables'
67
+ desc 'travis SUBCOMMAND ...ARGS', 'For manipulating Travis CI environment variables'
66
68
  subcommand 'travis', Chamber::Binary::Travis
67
69
 
68
70
  ################################################################################
69
71
 
70
- desc 'heroku SUBCOMMAND ...ARGS', 'For manipulating Heroku environment variables'
72
+ desc 'heroku SUBCOMMAND ...ARGS', 'For manipulating Heroku environment variables'
71
73
  subcommand 'heroku', Chamber::Binary::Heroku
72
74
 
73
75
  ################################################################################
74
76
 
75
- desc 'circleci SUBCOMMAND ...ARGS', 'For manipulating CircleCI environment variables'
77
+ desc 'circleci SUBCOMMAND ...ARGS', 'For manipulating CircleCI environment variables'
76
78
  subcommand 'circleci', Chamber::Binary::CircleCi
77
79
 
78
80
  ################################################################################
@@ -92,7 +94,7 @@ class Runner < Thor
92
94
  'Useful for debugging.'
93
95
 
94
96
  def show
95
- puts Commands::Show.call(options.merge(shell: self))
97
+ puts Commands::Show.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
96
98
  end
97
99
 
98
100
  ################################################################################
@@ -100,15 +102,16 @@ class Runner < Thor
100
102
  desc 'files', 'Lists the settings files which are parsed with the given options'
101
103
 
102
104
  def files
103
- puts Commands::Files.call(options.merge(shell: self))
105
+ puts Commands::Files.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
104
106
  end
105
107
 
106
108
  ################################################################################
107
109
 
108
- desc 'compare', 'Displays the difference between the settings in the first set ' \
109
- 'of namespaces and the settings in the second set. Useful for ' \
110
- 'tracking down why there may be issues in development versus test ' \
111
- 'or differences between staging and production.'
110
+ desc 'compare',
111
+ 'Displays the difference between the settings in the first set ' \
112
+ 'of namespaces and the settings in the second set. Useful for ' \
113
+ 'tracking down why there may be issues in development versus test ' \
114
+ 'or differences between staging and production.'
112
115
 
113
116
  method_option :keys_only,
114
117
  type: :boolean,
@@ -117,23 +120,26 @@ class Runner < Thor
117
120
  'of the two sets of settings'
118
121
 
119
122
  method_option :first,
120
- type: :array,
121
- desc: 'The list of namespaces which will be used as the source of ' \
122
- 'the comparison'
123
+ type: :array,
124
+ required: true,
125
+ desc: 'The list of namespaces which will be used as the source of ' \
126
+ 'the comparison'
123
127
 
124
128
  method_option :second,
125
- type: :array,
126
- desc: 'The list of namespaces which will be used as the destination ' \
127
- 'of the comparison'
129
+ type: :array,
130
+ required: true,
131
+ desc: 'The list of namespaces which will be used as the ' \
132
+ 'destination of the comparison'
128
133
 
129
134
  def compare
130
- Commands::Compare.call(options.merge(shell: self))
135
+ Commands::Compare.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
131
136
  end
132
137
 
133
138
  ################################################################################
134
139
 
135
- desc 'secure', 'Secures any values which appear to need to be encrypted in any of ' \
136
- 'the settings files which match irrespective of namespaces'
140
+ desc 'secure',
141
+ 'Secures any values which appear to need to be encrypted in any of ' \
142
+ 'the settings files which match irrespective of namespaces'
137
143
 
138
144
  method_option :only_sensitive,
139
145
  type: :boolean,
@@ -146,37 +152,42 @@ class Runner < Thor
146
152
  'what values would be encrypted'
147
153
 
148
154
  def secure
149
- Commands::Secure.call(options.merge(shell: self))
155
+ Commands::Secure.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
150
156
  end
151
157
 
152
158
  ################################################################################
153
159
 
154
- desc 'sign', 'Creates or verifies signatures for all current settings files using ' \
155
- 'the signature private key.'
160
+ desc 'sign',
161
+ 'Creates or verifies signatures for all current settings files using ' \
162
+ 'the signature private key.'
156
163
 
157
164
  method_option :verify,
158
165
  type: :boolean,
159
166
  default: false
160
167
 
168
+ method_option :signature_name,
169
+ type: :string,
170
+ default: `git config --get 'user.name'`.chomp
171
+
161
172
  def sign
162
173
  if options[:verify]
163
- Commands::Verify.call(options.merge(shell: self))
174
+ Commands::Verify.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
164
175
  else
165
- Commands::Sign.call(options.merge(shell: self))
176
+ Commands::Sign.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
166
177
  end
167
178
  end
168
179
 
169
180
  ################################################################################
170
181
 
171
- desc 'init', 'Sets Chamber up using best practices for secure configuration ' \
172
- 'management'
182
+ desc 'init',
183
+ 'Sets Chamber up using best practices for secure configuration management'
173
184
 
174
185
  method_option :signature,
175
186
  type: :boolean,
176
187
  default: false
177
188
 
178
189
  def init
179
- Commands::Initialize.call(options.merge(shell: self))
190
+ Commands::Initialize.call(**options.deep_transform_keys(&:to_sym).merge(shell: self))
180
191
  end
181
192
  end
182
193
  end
@@ -2,12 +2,16 @@
2
2
 
3
3
  require 'thor'
4
4
  require 'chamber/commands/travis/secure'
5
+ require 'chamber/refinements/hash'
5
6
 
6
7
  module Chamber
7
8
  module Binary
8
- class Travis < Thor
9
- desc 'secure', 'Uses your Travis CI public key to encrypt the settings you have ' \
10
- 'chosen not to commit to the repo'
9
+ class Travis < ::Thor
10
+ using ::Chamber::Refinements::Hash
11
+
12
+ desc 'secure',
13
+ 'Uses your Travis CI public key to encrypt the settings you have ' \
14
+ 'chosen not to commit to the repo'
11
15
 
12
16
  method_option :dry_run,
13
17
  type: :boolean,
@@ -24,7 +28,9 @@ class Travis < Thor
24
28
  'which are marked as "_secure"'
25
29
 
26
30
  def secure
27
- Commands::Travis::Secure.call(options.merge(shell: self))
31
+ Commands::Travis::Secure.call(**options
32
+ .deep_transform_keys(&:to_sym)
33
+ .merge(shell: self))
28
34
  end
29
35
  end
30
36
  end
@@ -6,26 +6,20 @@ require 'chamber/instance'
6
6
  module Chamber
7
7
  module Commands
8
8
  class Base
9
- def self.call(options = {})
10
- new(options).call
9
+ def self.call(**args)
10
+ new(**args).call
11
11
  end
12
12
 
13
13
  attr_accessor :chamber,
14
- :shell,
15
- :dry_run
16
- attr_reader :rootpath
14
+ :dry_run,
15
+ :rootpath,
16
+ :shell
17
17
 
18
- def initialize(options = {})
19
- self.chamber = Chamber::Instance.new options
20
- self.shell = options[:shell]
21
- self.rootpath = options[:rootpath]
22
- self.dry_run = options[:dry_run]
23
- end
24
-
25
- protected
26
-
27
- def rootpath=(other)
28
- @rootpath = Pathname.new(other)
18
+ def initialize(shell: nil, rootpath: nil, dry_run: nil, **args)
19
+ self.chamber = Chamber::Instance.new(rootpath: rootpath, **args)
20
+ self.shell = shell
21
+ self.rootpath = chamber.configuration.rootpath
22
+ self.dry_run = dry_run
29
23
  end
30
24
  end
31
25
  end
@@ -8,10 +8,10 @@ module Cloud
8
8
  class Base < Chamber::Commands::Base
9
9
  attr_accessor :adapter
10
10
 
11
- def initialize(options = {})
12
- super
11
+ def initialize(adapter:, **args)
12
+ super(**args)
13
13
 
14
- self.adapter = adapter_class(options[:adapter]).new(options)
14
+ self.adapter = adapter_class(adapter).new(**args)
15
15
  end
16
16
 
17
17
  private
@@ -9,10 +9,10 @@ module Cloud
9
9
  class Pull < Chamber::Commands::Cloud::Base
10
10
  attr_accessor :target_file
11
11
 
12
- def initialize(options = {})
12
+ def initialize(into:, **args)
13
13
  super
14
14
 
15
- self.target_file = options[:into]
15
+ self.target_file = into
16
16
  end
17
17
 
18
18
  def call
@@ -12,18 +12,18 @@ class Push < Chamber::Commands::Cloud::Base
12
12
 
13
13
  attr_accessor :keys
14
14
 
15
- def initialize(options = {})
16
- super
15
+ def initialize(keys:, **args)
16
+ super(**args)
17
17
 
18
- self.keys = options[:keys]
18
+ self.keys = keys
19
19
  end
20
20
 
21
21
  def call
22
22
  environment_variables = if keys
23
- Keys::Decryption.
24
- new(rootpath: chamber.configuration.rootpath,
25
- namespaces: chamber.configuration.namespaces).
26
- as_environment_variables
23
+ Keys::Decryption
24
+ .new(rootpath: chamber.configuration.rootpath,
25
+ namespaces: chamber.configuration.namespaces)
26
+ .as_environment_variables
27
27
  else
28
28
  securable_environment_variables
29
29
  end
@@ -5,10 +5,10 @@ require 'tempfile'
5
5
  module Chamber
6
6
  module Commands
7
7
  module Comparable
8
- def initialize(options = {})
8
+ def initialize(keys_only:, **args)
9
9
  super
10
10
 
11
- self.keys_only = options[:keys_only]
11
+ self.keys_only = keys_only
12
12
  end
13
13
 
14
14
  def call
@@ -12,18 +12,15 @@ class Compare < Chamber::Commands::Base
12
12
  attr_accessor :first_settings_instance,
13
13
  :second_settings_instance
14
14
 
15
- def self.call(options = {})
16
- new(options).call
15
+ def self.call(**args)
16
+ new(**args).call
17
17
  end
18
18
 
19
- def initialize(options = {})
20
- super
19
+ def initialize(first:, second:, **args)
20
+ super(**args)
21
21
 
22
- first_settings_options = options.merge(namespaces: options[:first])
23
- self.first_settings_instance = Chamber::Instance.new(first_settings_options)
24
-
25
- second_settings_options = options.merge(namespaces: options[:second])
26
- self.second_settings_instance = Chamber::Instance.new(second_settings_options)
22
+ self.first_settings_instance = Chamber::Instance.new(args.merge(namespaces: first))
23
+ self.second_settings_instance = Chamber::Instance.new(args.merge(namespaces: second))
27
24
  end
28
25
 
29
26
  protected
@@ -11,23 +11,23 @@ require 'chamber/commands/base'
11
11
  module Chamber
12
12
  module Commands
13
13
  class Initialize < Chamber::Commands::Base
14
- def self.call(options = {})
15
- new(options).call
14
+ def self.call(**args)
15
+ new(**args).call
16
16
  end
17
17
 
18
18
  attr_accessor :basepath,
19
19
  :namespaces,
20
20
  :signature
21
21
 
22
- def initialize(options = {})
23
- super
22
+ def initialize(signature:, namespaces: [], **args)
23
+ super(**args)
24
24
 
25
25
  self.basepath = Chamber.configuration.basepath
26
- self.namespaces = options.fetch(:namespaces, [])
27
- self.signature = options.fetch(:signature)
26
+ self.namespaces = namespaces
27
+ self.signature = signature
28
28
  end
29
29
 
30
- # rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
30
+ # rubocop:disable Layout/LineLength, Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
31
31
  def call
32
32
  key_pairs = namespaces.map do |namespace|
33
33
  Chamber::KeyPair.new(namespace: namespace,
@@ -78,21 +78,25 @@ class Initialize < Chamber::Commands::Base
78
78
  shell.say 'Your signature keys, which will be used for verification, are located at:'
79
79
  shell.say ''
80
80
  shell.say ' * Public Key: '
81
- shell.say signature_key_pair.
82
- public_key_filepath.
83
- relative_path_from(Pathname.pwd), :yellow
81
+ shell.say signature_key_pair
82
+ .public_key_filepath
83
+ .relative_path_from(Pathname.pwd),
84
+ :yellow
84
85
  shell.say ' * Private Key: '
85
- shell.say signature_key_pair.
86
- unencrypted_private_key_filepath.
87
- relative_path_from(Pathname.pwd), :yellow
86
+ shell.say signature_key_pair
87
+ .unencrypted_private_key_filepath
88
+ .relative_path_from(Pathname.pwd),
89
+ :yellow
88
90
  shell.say ' * Encrypted Private Key: '
89
- shell.say signature_key_pair.
90
- encrypted_private_key_filepath.
91
- relative_path_from(Pathname.pwd), :yellow
91
+ shell.say signature_key_pair
92
+ .encrypted_private_key_filepath
93
+ .relative_path_from(Pathname.pwd),
94
+ :yellow
92
95
  shell.say ' * Encrypted Passphrase: '
93
- shell.say signature_key_pair.
94
- encrypted_private_key_passphrase_filepath.
95
- relative_path_from(Pathname.pwd), :yellow
96
+ shell.say signature_key_pair
97
+ .encrypted_private_key_passphrase_filepath
98
+ .relative_path_from(Pathname.pwd),
99
+ :yellow
96
100
 
97
101
  shell.say ''
98
102
  shell.say 'The signature private keys should be thought of separately from the other'
@@ -153,7 +157,7 @@ class Initialize < Chamber::Commands::Base
153
157
  shell.say '--------------------------------------------------------------------------------'
154
158
  shell.say ''
155
159
  end
156
- # rubocop:enable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
160
+ # rubocop:enable Layout/LineLength, Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
157
161
 
158
162
  protected
159
163
 
@@ -178,7 +182,7 @@ class Initialize < Chamber::Commands::Base
178
182
  end
179
183
 
180
184
  def append_to_gitignore
181
- ::FileUtils.touch gitignore_filepath
185
+ ::FileUtils.touch(gitignore_filepath)
182
186
 
183
187
  gitignore_contents = ::File.read(gitignore_filepath)
184
188
 
@@ -206,7 +210,7 @@ class Initialize < Chamber::Commands::Base
206
210
 
207
211
  def gem_path
208
212
  @gem_path ||= Pathname.new(
209
- ::File.expand_path('../../../..', __FILE__),
213
+ ::File.expand_path('../../..', __dir__),
210
214
  )
211
215
  end
212
216