chamber 2.10.2 → 2.11.0

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