chamber 2.10.2 → 2.11.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 (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE.txt +1 -1
  5. data/lib/chamber.rb +3 -6
  6. data/lib/chamber/binary/heroku.rb +1 -0
  7. data/lib/chamber/binary/runner.rb +29 -13
  8. data/lib/chamber/binary/travis.rb +1 -0
  9. data/lib/chamber/commands/base.rb +10 -9
  10. data/lib/chamber/commands/comparable.rb +1 -0
  11. data/lib/chamber/commands/compare.rb +8 -7
  12. data/lib/chamber/commands/files.rb +1 -0
  13. data/lib/chamber/commands/heroku.rb +1 -0
  14. data/lib/chamber/commands/heroku/clear.rb +2 -1
  15. data/lib/chamber/commands/heroku/compare.rb +1 -0
  16. data/lib/chamber/commands/heroku/pull.rb +3 -4
  17. data/lib/chamber/commands/heroku/push.rb +1 -0
  18. data/lib/chamber/commands/initialize.rb +88 -76
  19. data/lib/chamber/commands/securable.rb +3 -2
  20. data/lib/chamber/commands/secure.rb +3 -1
  21. data/lib/chamber/commands/show.rb +7 -6
  22. data/lib/chamber/commands/travis.rb +1 -0
  23. data/lib/chamber/commands/travis/secure.rb +1 -0
  24. data/lib/chamber/configuration.rb +14 -13
  25. data/lib/chamber/context_resolver.rb +52 -55
  26. data/lib/chamber/encryption_methods/none.rb +4 -2
  27. data/lib/chamber/encryption_methods/public_key.rb +4 -2
  28. data/lib/chamber/encryption_methods/ssl.rb +11 -9
  29. data/lib/chamber/errors/decryption_failure.rb +1 -0
  30. data/lib/chamber/file.rb +27 -18
  31. data/lib/chamber/file_set.rb +14 -13
  32. data/lib/chamber/filters/decryption_filter.rb +48 -18
  33. data/lib/chamber/filters/encryption_filter.rb +32 -22
  34. data/lib/chamber/filters/environment_filter.rb +109 -16
  35. data/lib/chamber/filters/failed_decryption_filter.rb +10 -8
  36. data/lib/chamber/filters/insecure_filter.rb +1 -0
  37. data/lib/chamber/filters/namespace_filter.rb +8 -7
  38. data/lib/chamber/filters/secure_filter.rb +10 -9
  39. data/lib/chamber/filters/translate_secure_keys_filter.rb +10 -9
  40. data/lib/chamber/instance.rb +5 -4
  41. data/lib/chamber/key_pair.rb +82 -0
  42. data/lib/chamber/keys/base.rb +64 -0
  43. data/lib/chamber/keys/decryption.rb +41 -0
  44. data/lib/chamber/keys/encryption.rb +41 -0
  45. data/lib/chamber/namespace_set.rb +10 -9
  46. data/lib/chamber/rails.rb +1 -0
  47. data/lib/chamber/rails/railtie.rb +1 -0
  48. data/lib/chamber/rubinius_fix.rb +1 -0
  49. data/lib/chamber/settings.rb +45 -41
  50. data/lib/chamber/types/secured.rb +14 -12
  51. data/lib/chamber/version.rb +2 -1
  52. metadata +28 -27
  53. metadata.gz.sig +0 -0
  54. data/lib/chamber/decryption_key.rb +0 -52
  55. data/lib/chamber/environmentable.rb +0 -27
  56. data/lib/chamber/filters/boolean_conversion_filter.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9edabd92ed2fb227cb36bef070841da66a318d4e
4
- data.tar.gz: 773b623a400e9135391616bd93bd9b4b07ca8b87
3
+ metadata.gz: 212f658524053ccae210207899aaadd11fca8dc3
4
+ data.tar.gz: 2ab2300b8a8a0107f7c094b79e344209f24a385a
5
5
  SHA512:
6
- metadata.gz: 8986c275bcf25008895491027fff6015dd7ea0a0685e428e0b2464d62a9e5a9c96d22938a9d12469cb48c63a2de794467701e5dd7c1a1b38daa3e7bfe13d3190
7
- data.tar.gz: ab14d195f86e79e1f974f38bb6a73c3b2bee9437a82fe47fbb54c0290821720df364be375cbbb8fcdb92d271c430e2e6ed17c5edd2468eb2a4e3b2a862fec7d8
6
+ metadata.gz: 6d90c504c34d974a5d915aa1eb63f5c5c1c6dff4cf7fda43a072b2464e04d6d11ecacf196d921a5ecb9c2521a685a6199421abcfb6dad90c62f149cba277a273
7
+ data.tar.gz: d9168743dc703563e8e5ef86f4fb5fce13d00a3d6a7c590a7147d0902d2f8e73df7957fb070f8ce7d5541b483a7c5f8d94bf7b350ec56ab63a8d5ef58f27f357
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2016 The Kompanee, Ltd
1
+ Copyright (c) 2010-2018 The Kompanee, Ltd
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/rubinius_fix'
3
4
  require 'chamber/instance'
4
5
  require 'chamber/rails'
5
6
 
6
7
  module Chamber
8
+ attr_writer :instance
9
+
7
10
  def load(options = {})
8
11
  self.instance = Instance.new(options)
9
12
  end
@@ -16,16 +19,10 @@ module Chamber
16
19
  instance.settings
17
20
  end
18
21
 
19
- protected
20
-
21
- attr_accessor :instance
22
-
23
22
  def instance
24
23
  @instance ||= Instance.new({})
25
24
  end
26
25
 
27
- public
28
-
29
26
  def method_missing(name, *args)
30
27
  return instance.public_send(name, *args) if instance.respond_to?(name)
31
28
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'thor'
3
4
  require 'chamber/commands/heroku/clear'
4
5
  require 'chamber/commands/heroku/push'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'thor'
3
4
  require 'chamber/rubinius_fix'
4
5
  require 'chamber/binary/travis'
@@ -46,22 +47,28 @@ class Runner < Thor
46
47
  desc: 'Used to quickly assign a given scenario to the chamber ' \
47
48
  'command (eg Rails apps)'
48
49
 
49
- class_option :decryption_key,
50
- type: :string,
51
- desc: 'The path to or contents of the private key associated with ' \
52
- 'the project (typically .chamber.pem)'
50
+ class_option :decryption_keys,
51
+ type: :array,
52
+ desc: 'The path to or contents of the private key (or keys) associated ' \
53
+ 'with the project (typically .chamber.pem)'
54
+
55
+ class_option :encryption_keys,
56
+ type: :array,
57
+ desc: 'The path to or contents of the public key (or keys) associated ' \
58
+ 'with the project (typically .chamber.pub.pem)'
53
59
 
54
- class_option :encryption_key,
55
- type: :string,
56
- desc: 'The path to or contents of the public key associated with ' \
57
- 'the project (typically .chamber.pub.pem)'
60
+ ################################################################################
58
61
 
59
62
  desc 'travis SUBCOMMAND ...ARGS', 'For manipulating Travis CI environment variables'
60
63
  subcommand 'travis', Chamber::Binary::Travis
61
64
 
65
+ ################################################################################
66
+
62
67
  desc 'heroku SUBCOMMAND ...ARGS', 'For manipulating Heroku environment variables'
63
68
  subcommand 'heroku', Chamber::Binary::Heroku
64
69
 
70
+ ################################################################################
71
+
65
72
  desc 'show', 'Displays the list of settings and their values'
66
73
 
67
74
  method_option :as_env,
@@ -70,8 +77,6 @@ class Runner < Thor
70
77
  desc: 'Whether the displayed settings should be environment ' \
71
78
  'variable compatible'
72
79
 
73
- desc 'only_sensitive', 'Only show secured/securable settings'
74
-
75
80
  method_option :only_sensitive,
76
81
  type: :boolean,
77
82
  aliases: '-s',
@@ -82,13 +87,20 @@ class Runner < Thor
82
87
  puts Commands::Show.call(options.merge(shell: self))
83
88
  end
84
89
 
90
+ ################################################################################
91
+
85
92
  desc 'files', 'Lists the settings files which are parsed with the given options'
93
+
86
94
  def files
87
95
  puts Commands::Files.call(options.merge(shell: self))
88
96
  end
89
97
 
90
- desc 'compare', 'Displays the difference between what is currently stored in the ' \
91
- 'Heroku application\'s config and what Chamber knows about locally'
98
+ ################################################################################
99
+
100
+ desc 'compare', 'Displays the difference between the settings in the first set ' \
101
+ 'of namespaces and the settings in the second set. Useful for ' \
102
+ 'tracking down why there may be issues in development versus test ' \
103
+ 'or differences between staging and production.'
92
104
 
93
105
  method_option :keys_only,
94
106
  type: :boolean,
@@ -110,6 +122,8 @@ class Runner < Thor
110
122
  Commands::Compare.call(options.merge(shell: self))
111
123
  end
112
124
 
125
+ ################################################################################
126
+
113
127
  desc 'secure', 'Secures any values which appear to need to be encrypted in any of ' \
114
128
  'the settings files which match irrespective of namespaces'
115
129
 
@@ -127,7 +141,9 @@ class Runner < Thor
127
141
  Commands::Secure.call(options.merge(shell: self))
128
142
  end
129
143
 
130
- desc 'init', 'Sets Chamber up matching best practices for secure configuration ' \
144
+ ################################################################################
145
+
146
+ desc 'init', 'Sets Chamber up using best practices for secure configuration ' \
131
147
  'management'
132
148
 
133
149
  def init
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'thor'
3
4
  require 'chamber/commands/travis/secure'
4
5
 
@@ -1,28 +1,29 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'pathname'
3
4
  require 'chamber/instance'
4
5
 
5
6
  module Chamber
6
7
  module Commands
7
8
  class Base
8
- def initialize(options = {})
9
- self.chamber = Chamber::Instance.new options
10
- self.shell = options[:shell]
11
- self.rootpath = options[:rootpath]
12
- self.dry_run = options[:dry_run]
13
- end
14
-
15
9
  def self.call(options = {})
16
10
  new(options).call
17
11
  end
18
12
 
19
- protected
20
-
21
13
  attr_accessor :chamber,
22
14
  :shell,
23
15
  :dry_run
24
16
  attr_reader :rootpath
25
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
+
26
27
  def rootpath=(other)
27
28
  @rootpath ||= Pathname.new(other)
28
29
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'tempfile'
3
4
 
4
5
  module Chamber
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/instance'
3
4
  require 'chamber/commands/base'
4
5
  require 'chamber/commands/comparable'
@@ -8,6 +9,13 @@ module Commands
8
9
  class Compare < Chamber::Commands::Base
9
10
  include Chamber::Commands::Comparable
10
11
 
12
+ attr_accessor :first_settings_instance,
13
+ :second_settings_instance
14
+
15
+ def self.call(options = {})
16
+ new(options).call
17
+ end
18
+
11
19
  def initialize(options = {})
12
20
  super
13
21
 
@@ -18,15 +26,8 @@ class Compare < Chamber::Commands::Base
18
26
  self.second_settings_instance = Chamber::Instance.new(second_settings_options)
19
27
  end
20
28
 
21
- def self.call(options = {})
22
- new(options).call
23
- end
24
-
25
29
  protected
26
30
 
27
- attr_accessor :first_settings_instance,
28
- :second_settings_instance
29
-
30
31
  def first_settings_data
31
32
  settings_data(first_settings_instance)
32
33
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/commands/base'
3
4
 
4
5
  module Chamber
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'bundler'
3
4
 
4
5
  module Chamber
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/commands/base'
3
4
  require 'chamber/commands/heroku'
4
5
 
@@ -9,7 +10,7 @@ class Clear < Chamber::Commands::Base
9
10
  include Chamber::Commands::Heroku
10
11
 
11
12
  def call
12
- chamber.to_environment.keys.each do |key|
13
+ chamber.to_environment.each_key do |key|
13
14
  next unless configuration.match(key)
14
15
 
15
16
  if dry_run
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/commands/securable'
3
4
  require 'chamber/commands/heroku'
4
5
  require 'chamber/commands/comparable'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/commands/base'
3
4
  require 'chamber/commands/heroku'
4
5
 
@@ -8,6 +9,8 @@ module Heroku
8
9
  class Pull < Chamber::Commands::Base
9
10
  include Chamber::Commands::Heroku
10
11
 
12
+ attr_accessor :target_file
13
+
11
14
  def initialize(options = {})
12
15
  super
13
16
 
@@ -21,10 +24,6 @@ class Pull < Chamber::Commands::Base
21
24
  configuration
22
25
  end
23
26
  end
24
-
25
- protected
26
-
27
- attr_accessor :target_file
28
27
  end
29
28
  end
30
29
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'chamber/commands/base'
3
4
  require 'chamber/commands/securable'
4
5
  require 'chamber/commands/heroku'
@@ -1,71 +1,128 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'pathname'
3
4
  require 'fileutils'
4
5
  require 'openssl'
6
+ require 'securerandom'
5
7
  require 'chamber/configuration'
8
+ require 'chamber/key_pair'
6
9
  require 'chamber/commands/base'
7
10
 
8
11
  module Chamber
9
12
  module Commands
10
13
  class Initialize < Chamber::Commands::Base
14
+ def self.call(options = {})
15
+ new(options).call
16
+ end
17
+
18
+ attr_accessor :basepath,
19
+ :namespaces
20
+
11
21
  def initialize(options = {})
12
22
  super
13
23
 
14
- self.basepath = Chamber.configuration.basepath
24
+ self.basepath = Chamber.configuration.basepath
25
+ self.namespaces = options.fetch(:namespaces, [])
15
26
  end
16
27
 
17
28
  # rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
18
29
  def call
19
- shell.create_file private_key_filepath, rsa_private_key.to_pem
20
- shell.create_file protected_key_filepath, rsa_protected_key
21
- shell.create_file public_key_filepath, rsa_public_key.to_pem
22
-
23
- `chmod 600 #{private_key_filepath}`
24
- `chmod 600 #{protected_key_filepath}`
25
- `chmod 644 #{public_key_filepath}`
30
+ key_pairs = namespaces.map do |namespace|
31
+ Chamber::KeyPair.new(namespace: namespace,
32
+ key_file_path: rootpath)
33
+ end
34
+ key_pairs << Chamber::KeyPair.new(namespace: nil,
35
+ key_file_path: rootpath)
26
36
 
27
- ::FileUtils.touch gitignore_filepath
37
+ key_pairs.each { |key_pair| generate_key_pair(key_pair) }
28
38
 
29
- unless ::File.read(gitignore_filepath) =~ /^.chamber.pem$/
30
- shell.append_to_file gitignore_filepath, "\n# Private and protected key files for Chamber\n"
31
- shell.append_to_file gitignore_filepath, "#{private_key_filename}\n"
32
- shell.append_to_file gitignore_filepath, "#{protected_key_filename}\n"
33
- end
39
+ append_to_gitignore
34
40
 
35
41
  shell.copy_file settings_template_filepath, settings_filepath
36
42
 
37
43
  shell.say ''
38
- shell.say 'The passphrase for your encrypted private key is:', :green
44
+ shell.say '********************************************************************************', :green
45
+ shell.say ' Success!', :green
46
+ shell.say '********************************************************************************', :green
47
+ shell.say ''
48
+
49
+ shell.say '.chamber.pem is a DEFAULT Chamber key.', :red
50
+ shell.say ''
51
+ shell.say 'If you would like a key which is used only for things such as a certain'
52
+ shell.say 'environment (such as production), or your local machine, you can rerun'
53
+ shell.say 'the command like so:'
54
+ shell.say ''
55
+ shell.say '$ chamber init --namespaces="production my_machines_hostname"', :yellow
39
56
  shell.say ''
40
- shell.say rsa_key_passphrase, :green
57
+
58
+ shell.say 'The passphrase for your encrypted private key(s) are:'
41
59
  shell.say ''
42
- shell.say 'Store this securely somewhere.', :green
60
+
61
+ key_pairs.each do |key_pair|
62
+ shell.say "* #{key_pair.encrypted_private_key_filename}: "
63
+ shell.say key_pair.passphrase, :yellow
64
+ end
65
+
43
66
  shell.say ''
44
- shell.say 'You can send them the file located at:', :green
67
+ shell.say 'Store these securely somewhere.'
45
68
  shell.say ''
46
- shell.say protected_key_filepath, :green
69
+ shell.say 'You can send your team members any of the file(s) located at:'
70
+ shell.say ''
71
+
72
+ key_pairs.each do |key_pair|
73
+ shell.say '* '
74
+ shell.say key_pair.encrypted_private_key_filepath, :yellow
75
+ end
76
+
47
77
  shell.say ''
48
- shell.say 'and not have to worry about sending it via a secure medium (such as', :green
49
- shell.say 'email), however do not send the passphrase along with it. Give it to', :green
50
- shell.say 'your team members in person.', :green
78
+ shell.say 'and not have to worry about sending it via a secure medium (such as'
79
+ shell.say 'email), however do not send the passphrase along with it. Give it to'
80
+ shell.say 'your team members in person.'
51
81
  shell.say ''
52
- shell.say 'In order for them to decrypt it (for use with Chamber), they can run:', :green
82
+ shell.say 'In order for them to decrypt it (for use with Chamber), they can use something'
83
+ shell.say 'like the following (swapping out the actual key filenames if necessary):'
53
84
  shell.say ''
54
- shell.say "$ cp /path/to/{#{protected_key_filename},#{private_key_filename}}", :green
55
- shell.say "$ ssh-keygen -p -f /path/to/#{private_key_filename}", :green
85
+ shell.say "$ cp #{key_pairs[0].encrypted_private_key_filepath} #{key_pairs[0].unencrypted_private_key_filepath}", :yellow
86
+ shell.say "$ ssh-keygen -p -f #{key_pairs[0].unencrypted_private_key_filepath}", :yellow
56
87
  shell.say ''
57
- shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.', :green
88
+ shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.'
58
89
  shell.say ''
59
90
  end
60
91
  # rubocop:enable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
61
92
 
62
- def self.call(options = {})
63
- new(options).call
93
+ protected
94
+
95
+ def generate_key_pair(key_pair)
96
+ shell.create_file key_pair.unencrypted_private_key_filepath,
97
+ key_pair.unencrypted_private_key_pem,
98
+ skip: true
99
+ shell.create_file key_pair.encrypted_private_key_filepath,
100
+ key_pair.encrypted_private_key_pem,
101
+ skip: true
102
+ shell.create_file key_pair.public_key_filepath,
103
+ key_pair.public_key_pem,
104
+ skip: true
105
+
106
+ `chmod 600 #{key_pair.unencrypted_private_key_filepath}`
107
+ `chmod 600 #{key_pair.encrypted_private_key_filepath}`
108
+ `chmod 644 #{key_pair.public_key_filepath}`
64
109
  end
65
110
 
66
- protected
111
+ # rubocop:disable Style/GuardClause
112
+ def append_to_gitignore
113
+ ::FileUtils.touch gitignore_filepath
114
+
115
+ gitignore_contents = ::File.read(gitignore_filepath)
67
116
 
68
- attr_accessor :basepath
117
+ unless gitignore_contents =~ /^\.chamber\*\.enc$/
118
+ shell.append_to_file gitignore_filepath, ".chamber*.enc\n"
119
+ end
120
+
121
+ unless gitignore_contents =~ /^\.chamber\*\.pem$/
122
+ shell.append_to_file gitignore_filepath, ".chamber*.pem\n"
123
+ end
124
+ end
125
+ # rubocop:enable Style/GuardClause
69
126
 
70
127
  def settings_template_filepath
71
128
  @settings_template_filepath ||= templates_path + 'settings.yml'
@@ -78,7 +135,7 @@ class Initialize < Chamber::Commands::Base
78
135
  def gem_path
79
136
  @gem_path ||= Pathname.new(
80
137
  ::File.expand_path('../../../..', __FILE__),
81
- )
138
+ )
82
139
  end
83
140
 
84
141
  def settings_filepath
@@ -88,51 +145,6 @@ class Initialize < Chamber::Commands::Base
88
145
  def gitignore_filepath
89
146
  @gitignore_filepath ||= rootpath + '.gitignore'
90
147
  end
91
-
92
- def protected_key_filepath
93
- @protected_key_filepath ||= rootpath + protected_key_filename
94
- end
95
-
96
- def private_key_filepath
97
- @private_key_filepath ||= rootpath + private_key_filename
98
- end
99
-
100
- def public_key_filepath
101
- @public_key_filepath ||= rootpath + public_key_filename
102
- end
103
-
104
- def protected_key_filename
105
- '.chamber.pem.enc'
106
- end
107
-
108
- def private_key_filename
109
- '.chamber.pem'
110
- end
111
-
112
- def public_key_filename
113
- '.chamber.pub.pem'
114
- end
115
-
116
- def rsa_protected_key
117
- @rsa_protected_key ||= begin
118
- cipher = OpenSSL::Cipher.new 'AES-128-CBC'
119
- key = OpenSSL::PKey::RSA.new(2048)
120
-
121
- key.export cipher, rsa_key_passphrase
122
- end
123
- end
124
-
125
- def rsa_private_key
126
- @rsa_private_key ||= OpenSSL::PKey::RSA.new(2048)
127
- end
128
-
129
- def rsa_public_key
130
- rsa_private_key.public_key
131
- end
132
-
133
- def rsa_key_passphrase
134
- @rsa_key_passphrase ||= SecureRandom.uuid
135
- end
136
148
  end
137
149
  end
138
150
  end