chamber 1.0.3 → 2.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.
- checksums.yaml +4 -4
- data/README.md +288 -173
- data/bin/chamber +2 -288
- data/lib/chamber.rb +19 -67
- data/lib/chamber/binary/heroku.rb +59 -0
- data/lib/chamber/binary/runner.rb +94 -0
- data/lib/chamber/binary/travis.rb +23 -0
- data/lib/chamber/commands/base.rb +33 -0
- data/lib/chamber/commands/comparable.rb +37 -0
- data/lib/chamber/commands/compare.rb +46 -0
- data/lib/chamber/commands/context_resolver.rb +72 -0
- data/lib/chamber/commands/files.rb +12 -0
- data/lib/chamber/commands/heroku.rb +30 -0
- data/lib/chamber/commands/heroku/clear.rb +25 -0
- data/lib/chamber/commands/heroku/compare.rb +31 -0
- data/lib/chamber/commands/heroku/pull.rb +30 -0
- data/lib/chamber/commands/heroku/push.rb +25 -0
- data/lib/chamber/commands/initialize.rb +73 -0
- data/lib/chamber/commands/securable.rb +48 -0
- data/lib/chamber/commands/secure.rb +16 -0
- data/lib/chamber/commands/show.rb +23 -0
- data/lib/chamber/commands/travis.rb +14 -0
- data/lib/chamber/commands/travis/secure.rb +35 -0
- data/lib/chamber/configuration.rb +34 -0
- data/lib/chamber/environmentable.rb +23 -0
- data/lib/chamber/errors/undecryptable_value_error.rb +6 -0
- data/lib/chamber/file.rb +17 -5
- data/lib/chamber/file_set.rb +18 -12
- data/lib/chamber/filters/boolean_conversion_filter.rb +41 -0
- data/lib/chamber/filters/decryption_filter.rb +69 -0
- data/lib/chamber/filters/encryption_filter.rb +57 -0
- data/lib/chamber/filters/environment_filter.rb +75 -0
- data/lib/chamber/filters/namespace_filter.rb +37 -0
- data/lib/chamber/filters/secure_filter.rb +39 -0
- data/lib/chamber/instance.rb +40 -0
- data/lib/chamber/namespace_set.rb +55 -16
- data/lib/chamber/rails/railtie.rb +1 -1
- data/lib/chamber/settings.rb +103 -42
- data/lib/chamber/system_environment.rb +3 -93
- data/lib/chamber/version.rb +2 -2
- data/spec/fixtures/settings.yml +27 -0
- data/spec/lib/chamber/commands/context_resolver_spec.rb +106 -0
- data/spec/lib/chamber/commands/files_spec.rb +19 -0
- data/spec/lib/chamber/commands/heroku/clear_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/compare_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/pull_spec.rb +11 -0
- data/spec/lib/chamber/commands/heroku/push_spec.rb +11 -0
- data/spec/lib/chamber/commands/secure_spec.rb +29 -0
- data/spec/lib/chamber/commands/show_spec.rb +43 -0
- data/spec/lib/chamber/file_set_spec.rb +1 -1
- data/spec/lib/chamber/file_spec.rb +32 -9
- data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +44 -0
- data/spec/lib/chamber/filters/decryption_filter_spec.rb +55 -0
- data/spec/lib/chamber/filters/encryption_filter_spec.rb +48 -0
- data/spec/lib/chamber/filters/environment_filter_spec.rb +35 -0
- data/spec/lib/chamber/filters/namespace_filter_spec.rb +73 -0
- data/spec/lib/chamber/filters/secure_filter_spec.rb +36 -0
- data/spec/lib/chamber/namespace_set_spec.rb +61 -18
- data/spec/lib/chamber/settings_spec.rb +99 -23
- data/spec/lib/chamber/system_environment_spec.rb +1 -71
- data/spec/lib/chamber_spec.rb +40 -26
- data/spec/rails-2-test/config.ru +0 -0
- data/spec/rails-2-test/config/application.rb +5 -0
- data/spec/rails-2-test/script/console +0 -0
- data/spec/rails-3-test/config.ru +0 -0
- data/spec/rails-3-test/config/application.rb +5 -0
- data/spec/rails-3-test/script/rails +0 -0
- data/spec/rails-4-test/bin/rails +0 -0
- data/spec/rails-4-test/config.ru +0 -0
- data/spec/rails-4-test/config/application.rb +5 -0
- data/spec/spec_key +27 -0
- data/spec/spec_key.pub +9 -0
- metadata +85 -4
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chamber/commands/base'
|
2
|
+
require 'chamber/commands/securable'
|
3
|
+
require 'chamber/commands/heroku'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
module Heroku
|
8
|
+
class Push < Chamber::Commands::Base
|
9
|
+
include Chamber::Commands::Securable
|
10
|
+
include Chamber::Commands::Heroku
|
11
|
+
|
12
|
+
def call
|
13
|
+
securable_environment_variables.each do |key, value|
|
14
|
+
if dry_run
|
15
|
+
shell.say_status 'push', key, :blue
|
16
|
+
else
|
17
|
+
shell.say_status 'push', key, :green
|
18
|
+
shell.say heroku(%Q{config:set #{key}=#{value}})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'chamber/commands/base'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
class Initialize < Chamber::Commands::Base
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
super
|
10
|
+
|
11
|
+
self.basepath = options[:basepath]
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
shell.create_file private_key_filepath, rsa_private_key.to_pem
|
16
|
+
shell.create_file public_key_filepath, rsa_public_key.to_pem
|
17
|
+
|
18
|
+
`chmod 600 #{private_key_filepath}`
|
19
|
+
`chmod 644 #{public_key_filepath}`
|
20
|
+
|
21
|
+
unless ::File.read(gitignore_filepath).match(/^.chamber.pem$/)
|
22
|
+
shell.append_to_file gitignore_filepath, private_key_filepath.basename
|
23
|
+
end
|
24
|
+
|
25
|
+
shell.copy_file settings_template_filepath, settings_filepath
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.call(options = {})
|
29
|
+
self.new(options).call
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
attr_accessor :basepath
|
35
|
+
|
36
|
+
def settings_template_filepath
|
37
|
+
@settings_template_filepath ||= templates_path + 'settings.yml'
|
38
|
+
end
|
39
|
+
|
40
|
+
def templates_path
|
41
|
+
@templates_path ||= Pathname.new(::File.expand_path('../../../../templates', __FILE__))
|
42
|
+
end
|
43
|
+
|
44
|
+
def settings_filepath
|
45
|
+
@settings_filepath ||= basepath + 'settings.yml'
|
46
|
+
end
|
47
|
+
|
48
|
+
def gitignore_filepath
|
49
|
+
@gitignore_filepath ||= rootpath + '.gitignore'
|
50
|
+
end
|
51
|
+
|
52
|
+
def private_key_filepath
|
53
|
+
@private_key_filepath ||= rootpath + '.chamber.pem'
|
54
|
+
end
|
55
|
+
|
56
|
+
def public_key_filepath
|
57
|
+
@public_key_filepath ||= rootpath + '.chamber.pub.pem'
|
58
|
+
end
|
59
|
+
|
60
|
+
def rsa_key
|
61
|
+
@rsa_key ||= OpenSSL::PKey::RSA.new(2048)
|
62
|
+
end
|
63
|
+
|
64
|
+
def rsa_private_key
|
65
|
+
rsa_key
|
66
|
+
end
|
67
|
+
|
68
|
+
def rsa_public_key
|
69
|
+
rsa_key.public_key
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'chamber/instance'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
module Securable
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
super
|
10
|
+
|
11
|
+
ignored_settings_options = options.
|
12
|
+
merge(files: ignored_settings_filepaths).
|
13
|
+
reject { |k, v| k == 'basepath' }
|
14
|
+
self.ignored_settings_instance = Chamber::Instance.new(ignored_settings_options)
|
15
|
+
self.all_settings_instance = Chamber::Instance.new(options)
|
16
|
+
self.only_sensitive = options[:only_sensitive]
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
attr_accessor :only_sensitive,
|
22
|
+
:ignored_settings_instance,
|
23
|
+
:all_settings_instance
|
24
|
+
|
25
|
+
def securable_environment_variables
|
26
|
+
if only_sensitive
|
27
|
+
secured_settings.to_environment
|
28
|
+
else
|
29
|
+
all_settings.to_environment
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def secured_settings
|
34
|
+
ignored_settings_instance.settings.merge(all_settings.secured)
|
35
|
+
end
|
36
|
+
|
37
|
+
def all_settings
|
38
|
+
all_settings_instance.settings
|
39
|
+
end
|
40
|
+
|
41
|
+
def ignored_settings_filepaths
|
42
|
+
shell_escaped_chamber_filenames = chamber.filenames.map { |filename| Shellwords.escape(filename) }
|
43
|
+
|
44
|
+
`git ls-files --other --ignored --exclude-from=.gitignore | sed -e "s|^|#{Shellwords.escape(rootpath)}/|" | grep --colour=never -E '#{shell_escaped_chamber_filenames.join('|')}'`.split("\n")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'chamber/commands/base'
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Commands
|
5
|
+
class Secure < Chamber::Commands::Base
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
super(options.merge(namespaces: ['*']))
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
chamber.secure
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'chamber/commands/base'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
class Show < Chamber::Commands::Base
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
super
|
10
|
+
|
11
|
+
self.as_env = options[:as_env]
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
as_env ? chamber.to_s(pair_separator: "\n") : PP.pp(chamber.to_hash, StringIO.new, 60).string.chomp
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_accessor :as_env
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'chamber/commands/base'
|
2
|
+
require 'chamber/commands/travis'
|
3
|
+
require 'chamber/commands/securable'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
module Travis
|
8
|
+
class Secure < Chamber::Commands::Base
|
9
|
+
include Chamber::Commands::Travis
|
10
|
+
include Chamber::Commands::Securable
|
11
|
+
|
12
|
+
def call
|
13
|
+
securable_environment_variables.each do |key, value|
|
14
|
+
if dry_run
|
15
|
+
shell.say_status 'encrypt', key, :blue
|
16
|
+
else
|
17
|
+
command = first_environment_variable?(key) ? '--override' : '--append'
|
18
|
+
|
19
|
+
shell.say_status 'encrypt', key, :green
|
20
|
+
travis_encrypt("#{command} #{key}=#{value}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def first_environment_variable?(key)
|
28
|
+
@first_environment_key ||= securable_environment_variables.first[0]
|
29
|
+
|
30
|
+
@first_environment_key == key
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Chamber
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :basepath,
|
4
|
+
:decryption_key,
|
5
|
+
:encryption_key,
|
6
|
+
:files,
|
7
|
+
:namespaces
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
self.basepath = options[:basepath] || ''
|
11
|
+
self.namespaces = options[:namespaces] || []
|
12
|
+
self.decryption_key = options[:decryption_key]
|
13
|
+
self.encryption_key = options[:encryption_key]
|
14
|
+
self.files = options[:files] || [
|
15
|
+
self.basepath + 'credentials*.yml',
|
16
|
+
self.basepath + 'settings*.yml',
|
17
|
+
self.basepath + 'settings' ]
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
{
|
22
|
+
basepath: self.basepath,
|
23
|
+
decryption_key: self.decryption_key,
|
24
|
+
encryption_key: self.encryption_key,
|
25
|
+
files: self.files,
|
26
|
+
namespaces: self.namespaces,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def basepath=(pathlike)
|
31
|
+
@basepath = pathlike == '' ? '' : Pathname.new(::File.expand_path(pathlike))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Environmentable
|
5
|
+
def with_environment(settings, parent_keys, hash_block, value_block)
|
6
|
+
environment_hash = Hashie::Mash.new
|
7
|
+
|
8
|
+
settings.each_pair do |key, value|
|
9
|
+
environment_keys = parent_keys.dup.push(key)
|
10
|
+
|
11
|
+
if value.respond_to? :each_pair
|
12
|
+
environment_hash.merge!(hash_block.call(key, value, environment_keys))
|
13
|
+
else
|
14
|
+
environment_key = environment_keys.join('_').upcase
|
15
|
+
|
16
|
+
environment_hash.merge!(value_block.call(key, value, environment_key))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
environment_hash
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/chamber/file.rb
CHANGED
@@ -6,7 +6,7 @@ require 'erb'
|
|
6
6
|
# Internal: Represents a single file containing settings information in a given
|
7
7
|
# file set.
|
8
8
|
#
|
9
|
-
|
9
|
+
module Chamber
|
10
10
|
class File < Pathname
|
11
11
|
|
12
12
|
###
|
@@ -37,7 +37,9 @@ class File < Pathname
|
|
37
37
|
# # => <Chamber::File>
|
38
38
|
#
|
39
39
|
def initialize(options = {})
|
40
|
-
self.namespaces
|
40
|
+
self.namespaces = options[:namespaces] || {}
|
41
|
+
self.decryption_key = options[:decryption_key]
|
42
|
+
self.encryption_key = options[:encryption_key]
|
41
43
|
|
42
44
|
super options.fetch(:path)
|
43
45
|
end
|
@@ -62,13 +64,23 @@ class File < Pathname
|
|
62
64
|
# ```
|
63
65
|
#
|
64
66
|
def to_settings
|
65
|
-
@data ||= Settings.new(settings:
|
66
|
-
namespaces:
|
67
|
+
@data ||= Settings.new(settings: file_contents_hash,
|
68
|
+
namespaces: namespaces,
|
69
|
+
decryption_key: decryption_key,
|
70
|
+
encryption_key: encryption_key)
|
71
|
+
end
|
72
|
+
|
73
|
+
def secure
|
74
|
+
secure_settings = to_settings.secure
|
75
|
+
|
76
|
+
::File.open(self, 'w') { |file| file.write YAML.dump(secure_settings.to_hash) }
|
67
77
|
end
|
68
78
|
|
69
79
|
protected
|
70
80
|
|
71
|
-
attr_accessor :namespaces
|
81
|
+
attr_accessor :namespaces,
|
82
|
+
:decryption_key,
|
83
|
+
:encryption_key
|
72
84
|
|
73
85
|
private
|
74
86
|
|
data/lib/chamber/file_set.rb
CHANGED
@@ -107,12 +107,14 @@ require 'chamber/settings'
|
|
107
107
|
# FileSet.new(files: '/tmp/settings/*.json',
|
108
108
|
# namespaces: %w{blue green})
|
109
109
|
#
|
110
|
-
|
110
|
+
module Chamber
|
111
111
|
class FileSet
|
112
112
|
|
113
113
|
def initialize(options = {})
|
114
|
-
self.namespaces
|
115
|
-
self.
|
114
|
+
self.namespaces = options[:namespaces] || {}
|
115
|
+
self.decryption_key = options[:decryption_key]
|
116
|
+
self.encryption_key = options[:encryption_key]
|
117
|
+
self.paths = options.fetch(:files)
|
116
118
|
end
|
117
119
|
|
118
120
|
###
|
@@ -161,21 +163,23 @@ class FileSet
|
|
161
163
|
# # => <Chamber::Settings>
|
162
164
|
#
|
163
165
|
def to_settings
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
if block_given?
|
168
|
-
yield file.to_settings
|
169
|
-
else
|
170
|
-
settings.merge!(file.to_settings)
|
166
|
+
files.reduce(Settings.new) do |settings, file|
|
167
|
+
settings.merge(file.to_settings).tap do |merged|
|
168
|
+
yield merged if block_given?
|
171
169
|
end
|
172
170
|
end
|
173
171
|
end
|
174
172
|
|
173
|
+
def secure
|
174
|
+
files.each(&:secure)
|
175
|
+
end
|
176
|
+
|
175
177
|
protected
|
176
178
|
|
177
179
|
attr_reader :namespaces,
|
178
180
|
:paths
|
181
|
+
attr_accessor :decryption_key,
|
182
|
+
:encryption_key
|
179
183
|
|
180
184
|
###
|
181
185
|
# Internal: Allows the paths for the FileSet to be set. It can either be an
|
@@ -210,8 +214,10 @@ class FileSet
|
|
210
214
|
current_glob_files = Pathname.glob(glob)
|
211
215
|
relevant_glob_files = relevant_files & current_glob_files
|
212
216
|
|
213
|
-
relevant_glob_files.map! { |file| File.new( path:
|
214
|
-
namespaces:
|
217
|
+
relevant_glob_files.map! { |file| File.new( path: file,
|
218
|
+
namespaces: namespaces,
|
219
|
+
decryption_key: decryption_key,
|
220
|
+
encryption_key: encryption_key) }
|
215
221
|
|
216
222
|
sorted_relevant_files += relevant_glob_files
|
217
223
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Chamber
|
2
|
+
module Filters
|
3
|
+
class BooleanConversionFilter
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
self.data = options.fetch(:data).dup
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.execute(options = {})
|
10
|
+
self.new(options).send(:execute)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
attr_accessor :data
|
16
|
+
|
17
|
+
def execute(settings = data)
|
18
|
+
settings.each_pair do |key, value|
|
19
|
+
if value.respond_to? :each_pair
|
20
|
+
execute(value)
|
21
|
+
else
|
22
|
+
break if value.nil?
|
23
|
+
|
24
|
+
settings[key] = if value.is_a? String
|
25
|
+
case value
|
26
|
+
when 'false', 'f', 'no'
|
27
|
+
false
|
28
|
+
when 'true', 't', 'yes'
|
29
|
+
true
|
30
|
+
else
|
31
|
+
value
|
32
|
+
end
|
33
|
+
else
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|