chamber 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 212f658524053ccae210207899aaadd11fca8dc3
4
- data.tar.gz: 2ab2300b8a8a0107f7c094b79e344209f24a385a
3
+ metadata.gz: f2244ac836ff26be17476fae140643427bd61ec3
4
+ data.tar.gz: 3acbda9e98904305001f0aad0cd45f92909afbfa
5
5
  SHA512:
6
- metadata.gz: 6d90c504c34d974a5d915aa1eb63f5c5c1c6dff4cf7fda43a072b2464e04d6d11ecacf196d921a5ecb9c2521a685a6199421abcfb6dad90c62f149cba277a273
7
- data.tar.gz: d9168743dc703563e8e5ef86f4fb5fce13d00a3d6a7c590a7147d0902d2f8e73df7957fb070f8ce7d5541b483a7c5f8d94bf7b350ec56ab63a8d5ef58f27f357
6
+ metadata.gz: ca89abd49137ef3cae8a54b5a4a38029a55ef4e9498473dab173094704be265f0801e8698c34281dc624cbedb1b3f9f5d68ff6a3466b97b6c328575a6ab5c829
7
+ data.tar.gz: 5205ce62e2c54e5d5348a50e7bffa7fe2e196516b9d667f2b903c086f646e885c7d6459aba57fb9620edd96930f1480aa8655baa10f658fd312ad294a5e2c44a
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -1,45 +1,56 @@
1
- # Chamber [![Build Status](https://travis-ci.org/thekompanee/chamber.png)](https://travis-ci.org/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber.png)](https://codeclimate.com/github/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber/coverage.png)](https://codeclimate.com/github/thekompanee/chamber)
1
+ # Chamber
2
+ [![Gem Version](https://img.shields.io/gem/v/chamber.svg)](https://rubygems.org/gems/chamber) ![Rubygems Rank Overall](https://img.shields.io/gem/rt/chamber.svg) ![Rubygems Rank Daily](https://img.shields.io/gem/rd/chamber.svg) ![Rubygems Downloads](https://img.shields.io/gem/dv/chamber/stable.svg) [![Build Status](https://img.shields.io/travis/thekompanee/chamber/master.svg)](http://travis-ci.org/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber.svg)](https://codeclimate.com/github/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber/coverage.svg)](https://codeclimate.com/github/thekompanee/chamber)
2
3
 
3
- Chamber is the auto-encrypting, extremely organizable, Heroku-loving, CLI-having,
4
- non-extra-repo-needing, non-Rails-specific-ing, CI-serving configuration
5
- management library.
4
+ Chamber is the auto-encrypting, extremely organizable, Heroku-loving,
5
+ CLI-having, non-extra-repo-needing, non-Rails-specific-ing, CI-serving
6
+ configuration management library.
6
7
 
7
- [![TrueFact](https://cloud.githubusercontent.com/assets/285582/4803823/ad8110fa-5e5e-11e4-90d6-59320045a786.png)](https://www.youtube.com/watch?v=NNG1OoH2RwE)
8
+ We looked at all of the options out there and thought something was still
9
+ missing, so we wrote Chamber. We made it with lots of ❤ and we hope you like it
10
+ as much as we do.
8
11
 
9
- **Our Ten Commandments of Configuration Management**
12
+ ## What Sets Chamber Apart?
10
13
 
11
- <img src="https://akiajm7spx4gtbhaxe3qcomhaystacksoftwarearp.s3.amazonaws.com/photos/readmes/ten-commandments.png" align="right" />
14
+ For an idea of how Chamber compares to other popular libraries, check out our
15
+ [Gem Comparison][comparison].
12
16
 
13
- 1. Thou shalt be configurable, but [use conventions so that configuration isn't
14
- necessary](https://github.com/thekompanee/chamber/wiki/Basic-Usage#convention-over-configuration)
15
- 1. Thou shalt [seamlessly work with Heroku](https://github.com/thekompanee/chamber/wiki/Heroku) or other deployment platforms, where custom
16
- settings must be stored in [environment variables](https://github.com/thekompanee/chamber/wiki/Environment-Variable-Compatibility)
17
- 1. Thou shalt seamlessly work with [Travis CI](https://github.com/thekompanee/chamber/wiki/TravisCI) and other cloud CI platforms
18
- 1. Thou shalt not force users to use arcane
19
- [long_variables_to_keep_their_settings_organized](https://github.com/thekompanee/chamber/wiki/Accessing-Settings)
20
- 1. Thou shalt not require users keep a separate repo or cloud share sync [just to
21
- keep their secure settings updated](https://github.com/thekompanee/chamber/wiki/Encrypting-Your-Settings)
22
- 1. Thou shalt not be bound to a single framework like Rails (it should be usable [in
23
- plain Ruby projects](https://github.com/thekompanee/chamber/wiki/Basic-Usage#in-a-plain-old-ruby-project))
24
- 1. Thou shalt have an [easy-to-use CLI](https://github.com/thekompanee/chamber/wiki/Command-Line-Reference) for scripting
25
- 1. Thou shalt easily integrate with Capistrano for deployments
26
- 1. Thou shalt be [well documented](https://github.com/thekompanee/chamber/wiki/) with full test coverage
27
- 1. Thou shalt not have to worry about [accidentally committing secure settings](https://github.com/thekompanee/chamber/wiki/Git-Commit-Hook)
17
+ ## Basic Usage
28
18
 
29
- ## Full Reference
30
-
31
- Visit the [wiki](https://github.com/thekompanee/chamber/wiki)
19
+ You can view our Basic Usage Guide [here][basic-usage]. Otherwise, for the full
20
+ Chamber guide, visit the [wiki][wiki].
32
21
 
33
22
  ## Credits
34
23
 
35
- Chamber was written by Jeff Felchner and Mark McEahern.
24
+ Chamber was written by [Jeff Felchner][jeff-profile] and
25
+ [Mark McEahern][mark-profile]
36
26
 
37
- ![The Kompanee](https://www.dropbox.com/s/86jfka1d6bhv8as/kompanee-text-black.png?dl=1)
27
+ ![The Kompanee][kompanee-logo]
38
28
 
39
- Chamber is maintained and funded by [The Kompanee, Ltd.](http://www.thekompanee.com/)
29
+ Chamber is maintained and funded by [The Kompanee, Ltd.][kompanee-site]
40
30
 
41
31
  The names and logos for The Kompanee are trademarks of The Kompanee, Ltd.
42
32
 
43
33
  ## License
44
34
 
45
- Chamber is Copyright © 2014 Jeff Felchner and Mark McEahern. It is free software, and may be redistributed under the terms specified in the [LICENSE](https://github.com/thekompanee/chamber/blob/master/LICENSE) file.
35
+ Chamber is Copyright © 2014-2018 Jeff Felchner and Mark McEahern. It is free
36
+ software, and may be redistributed under the terms specified in the
37
+ [LICENSE][license] file.
38
+
39
+ [accessing]: https://github.com/thekompanee/chamber/wiki/Accessing-Settings
40
+ [basic-usage]: https://github.com/thekompanee/chamber/wiki/Basic-Usage
41
+ [cli]: https://github.com/thekompanee/chamber/wiki/CLI-Overview
42
+ [commit-hook]: https://github.com/thekompanee/chamber/wiki/Git-Commit-Hooks
43
+ [comparison]: https://github.com/thekompanee/chamber/wiki/Gem-Comparison
44
+ [encryption]: https://github.com/thekompanee/chamber/wiki/Encryption-Basics
45
+ [env-vars]: https://github.com/thekompanee/chamber/wiki/Environment-Variables
46
+ [heroku]: https://github.com/thekompanee/chamber/wiki/Heroku
47
+ [inch]: https://inch-ci.org/github/thekompanee/chamber
48
+ [jeff-profile]: https://github.com/jfelchner
49
+ [kompanee-logo]: https://kompanee-public-assets.s3.amazonaws.com/readmes/kompanee-horizontal-black.png
50
+ [kompanee-site]: http://www.thekompanee.com
51
+ [license]: https://github.com/thekompanee/chamber/blob/master/LICENSE.txt
52
+ [mark-profile]: https://github.com/m5rk
53
+ [namespace-keys]: https://github.com/thekompanee/chamber/wiki/Namespaced-Key-Pairs
54
+ [plain-ruby]: https://github.com/thekompanee/chamber/wiki/Installation#in-a-ruby-project-or-ruby-gem
55
+ [travis]: https://github.com/thekompanee/chamber/wiki/TravisCI
56
+ [wiki]: https://github.com/thekompanee/chamber/wiki
@@ -7,6 +7,8 @@ require 'chamber/binary/heroku'
7
7
  require 'chamber/commands/show'
8
8
  require 'chamber/commands/files'
9
9
  require 'chamber/commands/secure'
10
+ require 'chamber/commands/sign'
11
+ require 'chamber/commands/verify'
10
12
  require 'chamber/commands/compare'
11
13
  require 'chamber/commands/initialize'
12
14
 
@@ -143,9 +145,30 @@ class Runner < Thor
143
145
 
144
146
  ################################################################################
145
147
 
148
+ desc 'sign', 'Creates or verifies signatures for all current settings files using ' \
149
+ 'the signature private key.'
150
+
151
+ method_option :verify,
152
+ type: :boolean,
153
+ default: false
154
+
155
+ def sign
156
+ if options[:verify]
157
+ Commands::Verify.call(options.merge(shell: self))
158
+ else
159
+ Commands::Sign.call(options.merge(shell: self))
160
+ end
161
+ end
162
+
163
+ ################################################################################
164
+
146
165
  desc 'init', 'Sets Chamber up using best practices for secure configuration ' \
147
166
  'management'
148
167
 
168
+ method_option :signature,
169
+ type: :boolean,
170
+ default: false
171
+
149
172
  def init
150
173
  Commands::Initialize.call(options.merge(shell: self))
151
174
  end
@@ -16,13 +16,15 @@ class Initialize < Chamber::Commands::Base
16
16
  end
17
17
 
18
18
  attr_accessor :basepath,
19
- :namespaces
19
+ :namespaces,
20
+ :signature
20
21
 
21
22
  def initialize(options = {})
22
23
  super
23
24
 
24
25
  self.basepath = Chamber.configuration.basepath
25
26
  self.namespaces = options.fetch(:namespaces, [])
27
+ self.signature = options.fetch(:signature)
26
28
  end
27
29
 
28
30
  # rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
@@ -36,9 +38,16 @@ class Initialize < Chamber::Commands::Base
36
38
 
37
39
  key_pairs.each { |key_pair| generate_key_pair(key_pair) }
38
40
 
41
+ if signature
42
+ signature_key_pair = Chamber::KeyPair.new(namespace: 'signature',
43
+ key_file_path: rootpath)
44
+
45
+ generate_key_pair(signature_key_pair)
46
+ end
47
+
39
48
  append_to_gitignore
40
49
 
41
- shell.copy_file settings_template_filepath, settings_filepath
50
+ shell.copy_file settings_template_filepath, settings_filepath, skip: true
42
51
 
43
52
  shell.say ''
44
53
  shell.say '********************************************************************************', :green
@@ -46,47 +55,103 @@ class Initialize < Chamber::Commands::Base
46
55
  shell.say '********************************************************************************', :green
47
56
  shell.say ''
48
57
 
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
56
- shell.say ''
58
+ if namespaces.empty?
59
+ shell.say '.chamber.pem is your DEFAULT Chamber key.', :yellow
60
+ shell.say ''
61
+ shell.say 'If you would like a key which is used only for a certain environment (such as'
62
+ shell.say 'production), or your local machine, you can rerun the command like so:'
63
+ shell.say ''
64
+ shell.say '$ chamber init --namespaces="production my_machines_hostname"', :yellow
65
+ shell.say ''
66
+ shell.say 'You can find more information about namespace keys here:'
67
+ shell.say ''
68
+ shell.say ' * '
69
+ shell.say 'https://github.com/thekompanee/chamber/wiki/Namespaced-Key-Pairs', :blue
70
+ shell.say ''
71
+ shell.say '--------------------------------------------------------------------------------'
72
+ shell.say ''
73
+ end
74
+
75
+ if signature
76
+ shell.say ' Your Signature Keys'
77
+ shell.say ''
78
+ shell.say 'Your signature keys, which will be used for verification, are located at:'
79
+ shell.say ''
80
+ shell.say ' * Public Key: '
81
+ shell.say signature_key_pair.
82
+ public_key_filepath.
83
+ relative_path_from(Pathname.pwd), :yellow
84
+ shell.say ' * Private Key: '
85
+ shell.say signature_key_pair.
86
+ unencrypted_private_key_filepath.
87
+ relative_path_from(Pathname.pwd), :yellow
88
+ shell.say ' * Encrypted Private Key: '
89
+ shell.say signature_key_pair.
90
+ encrypted_private_key_filepath.
91
+ relative_path_from(Pathname.pwd), :yellow
92
+ shell.say ' * Encrypted Passphrase: '
93
+ shell.say signature_key_pair.
94
+ encrypted_private_key_passphrase_filepath.
95
+ relative_path_from(Pathname.pwd), :yellow
96
+
97
+ shell.say ''
98
+ shell.say 'The signature private keys should be thought of separately from the other'
99
+ shell.say 'project private keys you generate. They are not required to run the app'
100
+ shell.say 'and should only be given out to *very select* people.'
101
+ shell.say ''
102
+ shell.say 'You can find more information about settings verification here:'
103
+ shell.say ''
104
+ shell.say ' * '
105
+ shell.say 'https://github.com/thekompanee/chamber/wiki/Verifying-Settings', :blue
106
+ shell.say ''
107
+ shell.say '--------------------------------------------------------------------------------'
108
+ shell.say ''
109
+ end
57
110
 
58
- shell.say 'The passphrase for your encrypted private key(s) are:'
111
+ shell.say ' Your Encrypted Keys'
112
+ shell.say ''
113
+ shell.say 'You can send your team members any of the file(s) located at:'
59
114
  shell.say ''
60
115
 
61
116
  key_pairs.each do |key_pair|
62
- shell.say "* #{key_pair.encrypted_private_key_filename}: "
63
- shell.say key_pair.passphrase, :yellow
117
+ shell.say ' * '
118
+ shell.say key_pair.encrypted_private_key_filepath.relative_path_from(Pathname.pwd), :yellow
64
119
  end
65
120
 
66
121
  shell.say ''
67
- shell.say 'Store these securely somewhere.'
122
+ shell.say 'and not have to worry about sending them via a secure medium, however do'
123
+ shell.say 'not send the passphrase along with it. Give it to your team members in'
124
+ shell.say 'person.'
68
125
  shell.say ''
69
- shell.say 'You can send your team members any of the file(s) located at:'
126
+ shell.say 'You can learn more about encrypted keys here:'
127
+ shell.say ''
128
+ shell.say ' * '
129
+ shell.say 'https://github.com/thekompanee/chamber/wiki/Keypair-Encryption#the-encrypted-private-key', :blue
130
+ shell.say ''
131
+ shell.say '--------------------------------------------------------------------------------'
132
+ shell.say ''
133
+ shell.say ' Your Key Passphrases'
134
+ shell.say ''
135
+ shell.say 'The passphrases for your encrypted private key(s) are stored in the'
136
+ shell.say 'following locations:'
70
137
  shell.say ''
71
138
 
72
139
  key_pairs.each do |key_pair|
73
- shell.say '* '
74
- shell.say key_pair.encrypted_private_key_filepath, :yellow
140
+ shell.say ' * '
141
+ shell.say key_pair.encrypted_private_key_passphrase_filepath.relative_path_from(Pathname.pwd), :yellow
75
142
  end
76
143
 
77
- shell.say ''
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.'
81
144
  shell.say ''
82
145
  shell.say 'In order for them to decrypt it (for use with Chamber), they can use something'
83
146
  shell.say 'like the following (swapping out the actual key filenames if necessary):'
84
147
  shell.say ''
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
148
+ shell.say "$ cp #{key_pairs[0].encrypted_private_key_filepath.relative_path_from(Pathname.pwd)} #{key_pairs[0].unencrypted_private_key_filepath.relative_path_from(Pathname.pwd)}", :yellow
149
+ shell.say "$ ssh-keygen -p -f #{key_pairs[0].unencrypted_private_key_filepath.relative_path_from(Pathname.pwd)}", :yellow
87
150
  shell.say ''
88
151
  shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.'
89
152
  shell.say ''
153
+ shell.say '--------------------------------------------------------------------------------'
154
+ shell.say ''
90
155
  end
91
156
  # rubocop:enable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
92
157
 
@@ -102,27 +167,34 @@ class Initialize < Chamber::Commands::Base
102
167
  shell.create_file key_pair.public_key_filepath,
103
168
  key_pair.public_key_pem,
104
169
  skip: true
170
+ shell.create_file key_pair.encrypted_private_key_passphrase_filepath,
171
+ key_pair.passphrase,
172
+ skip: true
105
173
 
106
174
  `chmod 600 #{key_pair.unencrypted_private_key_filepath}`
107
175
  `chmod 600 #{key_pair.encrypted_private_key_filepath}`
176
+ `chmod 600 #{key_pair.encrypted_private_key_passphrase_filepath}`
108
177
  `chmod 644 #{key_pair.public_key_filepath}`
109
178
  end
110
179
 
111
- # rubocop:disable Style/GuardClause
112
180
  def append_to_gitignore
113
181
  ::FileUtils.touch gitignore_filepath
114
182
 
115
183
  gitignore_contents = ::File.read(gitignore_filepath)
116
184
 
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"
185
+ %w{
186
+ **/settings/*-local.yml
187
+ **/settings-local.yml
188
+ .chamber*.enc
189
+ .chamber*.pem
190
+ .chamber*.enc.pass
191
+ !.chamber*.pub.pem
192
+ }.each do |pattern|
193
+ unless gitignore_contents =~ Regexp.new(Regexp.escape(pattern))
194
+ shell.append_to_file gitignore_filepath, "#{pattern}\n"
195
+ end
123
196
  end
124
197
  end
125
- # rubocop:enable Style/GuardClause
126
198
 
127
199
  def settings_template_filepath
128
200
  @settings_template_filepath ||= templates_path + 'settings.yml'
@@ -15,11 +15,9 @@ class Secure < Chamber::Commands::Base
15
15
  def call
16
16
  disable_warnings do
17
17
  insecure_environment_variables.each_key do |key|
18
- if dry_run
19
- shell.say_status 'encrypt', key, :blue
20
- else
21
- shell.say_status 'encrypt', key, :green
22
- end
18
+ color = dry_run ? :blue : :green
19
+
20
+ shell.say_status 'encrypt', key, color
23
21
  end
24
22
  end
25
23
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'chamber/commands/base'
4
+
5
+ module Chamber
6
+ module Commands
7
+ class Sign < Chamber::Commands::Base
8
+ def initialize(options = {})
9
+ super(options.merge(namespaces: ['*']))
10
+ end
11
+
12
+ def call
13
+ chamber.sign
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'chamber/commands/base'
4
+
5
+ module Chamber
6
+ module Commands
7
+ class Verify < Chamber::Commands::Base
8
+ def initialize(options = {})
9
+ super(options.merge(namespaces: ['*']))
10
+ end
11
+
12
+ def call
13
+ verification_results = chamber.verify
14
+
15
+ verification_results.each_pair do |filename, result|
16
+ unless result
17
+ shell.say("The signature for '#{filename}' failed verification.", :yellow)
18
+ end
19
+ end
20
+
21
+ verification_results
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
4
+
3
5
  module Chamber
4
6
  module EncryptionMethods
5
7
  class PublicKey
6
- def self.encrypt(_key, value, encryption_keys)
7
- value = YAML.dump(value)
8
- encrypted_string = encryption_keys.public_encrypt(value)
8
+ def self.encrypt(_key, value, encryption_key)
9
+ value = YAML.dump(value)
10
+ encrypted_string = encryption_key.public_encrypt(value)
9
11
 
10
12
  Base64.strict_encode64(encrypted_string)
11
13
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
4
+
3
5
  module Chamber
4
6
  module EncryptionMethods
5
7
  class Ssl
data/lib/chamber/file.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'pathname'
4
4
  require 'yaml'
5
5
  require 'erb'
6
+ require 'chamber/files/signature'
6
7
 
7
8
  ###
8
9
  # Internal: Represents a single file containing settings information in a given
@@ -104,6 +105,28 @@ class File < Pathname
104
105
  end
105
106
  # rubocop:enable Metrics/LineLength
106
107
 
108
+ def sign
109
+ signature_key_contents = decryption_keys[:signature]
110
+
111
+ fail ArgumentError, 'You asked to sign your settings files but no signature key was found. Run `chamber init --signature` to generate one.' \
112
+ unless signature_key_contents
113
+
114
+ signature = Files::Signature.new(to_s, read, signature_key_contents)
115
+
116
+ signature.write
117
+ end
118
+
119
+ def verify
120
+ signature_key_contents = encryption_keys[:signature]
121
+
122
+ fail ArgumentError, 'You asked to verify your settings files but no signature key was found. Run `chamber init --signature` to generate one.' \
123
+ unless signature_key_contents
124
+
125
+ signature = Files::Signature.new(to_s, read, signature_key_contents)
126
+
127
+ signature.verify
128
+ end
129
+
107
130
  private
108
131
 
109
132
  def secure_prefix
@@ -115,13 +115,15 @@ class FileSet
115
115
  attr_reader :namespaces,
116
116
  :paths
117
117
  attr_accessor :decryption_keys,
118
- :encryption_keys
118
+ :encryption_keys,
119
+ :basepath
119
120
 
120
121
  def initialize(options = {})
121
122
  self.namespaces = options[:namespaces] || {}
122
123
  self.decryption_keys = options[:decryption_keys]
123
124
  self.encryption_keys = options[:encryption_keys]
124
125
  self.paths = options.fetch(:files)
126
+ self.basepath = options[:basepath]
125
127
  end
126
128
 
127
129
  ###
@@ -181,6 +183,18 @@ class FileSet
181
183
  files.each(&:secure)
182
184
  end
183
185
 
186
+ def sign
187
+ files.each(&:sign)
188
+ end
189
+
190
+ def verify
191
+ files.each_with_object({}) do |file, memo|
192
+ relative_filepath = Pathname.new(file.to_s).relative_path_from(basepath).to_s
193
+
194
+ memo[relative_filepath] = file.verify
195
+ end
196
+ end
197
+
184
198
  protected
185
199
 
186
200
  ###
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'pathname'
5
+ require 'time'
6
+
7
+ module Chamber
8
+ module Files
9
+ class Signature
10
+ SIGNATURE_HEADER = '-----BEGIN CHAMBER SIGNATURE-----'
11
+ SIGNATURE_FOOTER = '-----END CHAMBER SIGNATURE-----'
12
+ SIGNATURE_IN_SIGNATURE_FILE_PATTERN = /#{SIGNATURE_HEADER}\n(.*)\n#{SIGNATURE_FOOTER}/
13
+
14
+ attr_accessor :settings_content,
15
+ :settings_filename
16
+
17
+ attr_reader :signature_key
18
+
19
+ def initialize(settings_filename, settings_content, signature_key)
20
+ self.signature_key = signature_key
21
+ self.settings_content = settings_content
22
+ self.settings_filename = Pathname.new(settings_filename)
23
+ end
24
+
25
+ def signature_key=(keyish)
26
+ @signature_key ||= if keyish.is_a?(OpenSSL::PKey::RSA)
27
+ keyish
28
+ elsif ::File.readable?(::File.expand_path(keyish))
29
+ file_contents = ::File.read(::File.expand_path(keyish))
30
+ OpenSSL::PKey::RSA.new(file_contents)
31
+ else
32
+ OpenSSL::PKey::RSA.new(keyish)
33
+ end
34
+ end
35
+
36
+ def write
37
+ signature_filename.write(<<-HEREDOC, 0, mode: 'w+')
38
+ Signed By: #{`git config --get 'user.name'`.chomp}
39
+ Signed At: #{Time.now.utc.iso8601}
40
+
41
+ #{SIGNATURE_HEADER}
42
+ #{encoded_signature}
43
+ #{SIGNATURE_FOOTER}
44
+ HEREDOC
45
+ end
46
+
47
+ def verify
48
+ signature_key.verify(digest, signature_content, settings_content)
49
+ end
50
+
51
+ private
52
+
53
+ def encoded_signature
54
+ @encoded_signature ||= Base64.strict_encode64(raw_signature)
55
+ end
56
+
57
+ def raw_signature
58
+ @raw_signature ||= signature_key.
59
+ sign(digest, settings_content)
60
+ end
61
+
62
+ def signature_filename
63
+ @signature_filename ||= settings_filename.
64
+ sub('.yml', '.sig').
65
+ sub('.erb', '')
66
+ end
67
+
68
+ def encoded_signature_content
69
+ @encoded_signature_content ||= signature_filename.
70
+ read.
71
+ match(SIGNATURE_IN_SIGNATURE_FILE_PATTERN) do |match|
72
+ match[1]
73
+ end
74
+ end
75
+
76
+ def signature_content
77
+ @signature_content ||= Base64.strict_decode64(encoded_signature_content)
78
+ end
79
+
80
+ def digest
81
+ @digest ||= OpenSSL::Digest::SHA512.new
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openssl'
4
- require 'base64'
5
4
  require 'hashie/mash'
6
5
  require 'yaml'
7
6
  require 'chamber/encryption_methods/public_key'
@@ -151,6 +151,8 @@ class EnvironmentFilter
151
151
  end
152
152
  when 'Float'
153
153
  Float(environment_value)
154
+ when 'Time'
155
+ Time.iso8601(environment_value)
154
156
  when 'Array'
155
157
  YAML.safe_load(environment_value).tap do |parsed_value|
156
158
  unless parsed_value.is_a?(Array)
@@ -26,6 +26,14 @@ class Instance
26
26
  files.secure
27
27
  end
28
28
 
29
+ def sign
30
+ files.sign
31
+ end
32
+
33
+ def verify
34
+ files.verify
35
+ end
36
+
29
37
  def encrypt(data, options = {})
30
38
  config = configuration.to_hash.merge(options)
31
39
 
@@ -3,8 +3,8 @@
3
3
  require 'socket'
4
4
 
5
5
  module Chamber
6
- module Rails
7
- class Railtie < ::Rails::Railtie
6
+ module Integrations
7
+ class Rails < ::Rails::Railtie
8
8
  initializer 'chamber.load', before: :load_environment_config do
9
9
  Chamber.load(basepath: ::Rails.root.join('config'),
10
10
  namespaces: {
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ module Chamber
6
+ module Integrations
7
+ module Sinatra
8
+ def self.registered(app)
9
+ app.configure do |inner_app|
10
+ env = inner_app.environment || ENV['RACK_ENV']
11
+ root = inner_app.root
12
+
13
+ if defined?(Padrino)
14
+ env = Padrino.env if Padrino.respond_to?(:env)
15
+ root = Padrino.root if Padrino.respond_to?(:root)
16
+ end
17
+
18
+ Chamber.load(
19
+ basepath: root,
20
+ namespaces: {
21
+ environment: -> { env },
22
+ hostname: -> { Socket.gethostname },
23
+ },
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -15,6 +15,10 @@ class KeyPair
15
15
  self.key_file_path = Pathname.new(options.fetch(:key_file_path))
16
16
  end
17
17
 
18
+ def encrypted_private_key_passphrase_filepath
19
+ key_file_path + "#{encrypted_private_key_filename}.pass"
20
+ end
21
+
18
22
  def encrypted_private_key_filepath
19
23
  key_file_path + encrypted_private_key_filename
20
24
  end
@@ -7,9 +7,9 @@ class Base
7
7
  new(*args).resolve
8
8
  end
9
9
 
10
- attr_accessor :namespaces,
11
- :rootpath
12
- attr_reader :filenames
10
+ attr_accessor :rootpath
11
+ attr_reader :filenames,
12
+ :namespaces
13
13
 
14
14
  def initialize(options = {})
15
15
  self.rootpath = Pathname.new(options.fetch(:rootpath))
@@ -45,6 +45,18 @@ class Base
45
45
 
46
46
  private
47
47
 
48
+ def namespaces=(other)
49
+ @namespaces ||= begin
50
+ keys = if other.respond_to?(:keys)
51
+ other.keys.map(&:to_s)
52
+ else
53
+ other
54
+ end
55
+
56
+ keys + %w{signature}
57
+ end
58
+ end
59
+
48
60
  def key_from_file_contents(filename)
49
61
  filename.readable? && filename.read
50
62
  end
data/lib/chamber/rails.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'chamber/rails/railtie' if defined?(::Rails)
3
+ require 'chamber/integrations/rails' if defined?(::Rails)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chamber
4
- VERSION = '2.11.0'
4
+ VERSION = '2.12.0'
5
5
  end
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: 2.11.0
4
+ version: 2.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thekompanee
@@ -34,7 +34,7 @@ cert_chain:
34
34
  etYUO0DlNY/qYfSfExrgt0W5dZeT09V++WPlYauHw/EZtAB0AsJwVdtIscq0HSvX
35
35
  yH9AFp3KIe0v70EXzao/94n+XoDULrHEhqGMo34iS+37ZA==
36
36
  -----END CERTIFICATE-----
37
- date: 2018-01-12 00:00:00.000000000 Z
37
+ date: 2018-01-16 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: thor
@@ -120,6 +120,20 @@ dependencies:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
122
  version: '4.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: timecop
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '0.0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '0.0'
123
137
  description: Chamber lets you source your Settings from an arbitrary number of YAML
124
138
  files and provides a simple mechanism for overriding settings from the ENV, which
125
139
  is friendly to how Heroku addons work.
@@ -149,8 +163,10 @@ files:
149
163
  - lib/chamber/commands/securable.rb
150
164
  - lib/chamber/commands/secure.rb
151
165
  - lib/chamber/commands/show.rb
166
+ - lib/chamber/commands/sign.rb
152
167
  - lib/chamber/commands/travis.rb
153
168
  - lib/chamber/commands/travis/secure.rb
169
+ - lib/chamber/commands/verify.rb
154
170
  - lib/chamber/configuration.rb
155
171
  - lib/chamber/context_resolver.rb
156
172
  - lib/chamber/encryption_methods/none.rb
@@ -159,6 +175,7 @@ files:
159
175
  - lib/chamber/errors/decryption_failure.rb
160
176
  - lib/chamber/file.rb
161
177
  - lib/chamber/file_set.rb
178
+ - lib/chamber/files/signature.rb
162
179
  - lib/chamber/filters/decryption_filter.rb
163
180
  - lib/chamber/filters/encryption_filter.rb
164
181
  - lib/chamber/filters/environment_filter.rb
@@ -168,13 +185,14 @@ files:
168
185
  - lib/chamber/filters/secure_filter.rb
169
186
  - lib/chamber/filters/translate_secure_keys_filter.rb
170
187
  - lib/chamber/instance.rb
188
+ - lib/chamber/integrations/rails.rb
189
+ - lib/chamber/integrations/sinatra.rb
171
190
  - lib/chamber/key_pair.rb
172
191
  - lib/chamber/keys/base.rb
173
192
  - lib/chamber/keys/decryption.rb
174
193
  - lib/chamber/keys/encryption.rb
175
194
  - lib/chamber/namespace_set.rb
176
195
  - lib/chamber/rails.rb
177
- - lib/chamber/rails/railtie.rb
178
196
  - lib/chamber/rubinius_fix.rb
179
197
  - lib/chamber/settings.rb
180
198
  - lib/chamber/types/secured.rb
metadata.gz.sig CHANGED
Binary file