chamber 1.0.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,94 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'chamber/binary/travis'
|
3
|
+
require 'chamber/binary/heroku'
|
4
|
+
require 'chamber/commands/show'
|
5
|
+
require 'chamber/commands/files'
|
6
|
+
require 'chamber/commands/secure'
|
7
|
+
require 'chamber/commands/compare'
|
8
|
+
require 'chamber/commands/initialize'
|
9
|
+
|
10
|
+
module Chamber
|
11
|
+
module Binary
|
12
|
+
class Runner < Thor
|
13
|
+
include Thor::Actions
|
14
|
+
|
15
|
+
class_option :rootpath,
|
16
|
+
type: :string,
|
17
|
+
aliases: '-r',
|
18
|
+
default: ENV['PWD'],
|
19
|
+
desc: 'The root filepath of the application'
|
20
|
+
class_option :basepath,
|
21
|
+
type: :string,
|
22
|
+
aliases: '-b',
|
23
|
+
desc: 'The base filepath where Chamber will look for the conventional settings files'
|
24
|
+
class_option :files,
|
25
|
+
type: :array,
|
26
|
+
aliases: '-f',
|
27
|
+
desc: 'The set of file globs that Chamber will use for processing'
|
28
|
+
class_option :namespaces,
|
29
|
+
type: :array,
|
30
|
+
aliases: '-n',
|
31
|
+
default: [],
|
32
|
+
desc: 'The set of namespaces that Chamber will use for processing'
|
33
|
+
class_option :preset,
|
34
|
+
type: :string,
|
35
|
+
aliases: '-p',
|
36
|
+
enum: ['rails'],
|
37
|
+
desc: 'Used to quickly assign a given scenario to the chamber command (eg Rails apps)'
|
38
|
+
class_option :decryption_key,
|
39
|
+
type: :string,
|
40
|
+
desc: 'The path to or contents of the private key associated with the project (typically .chamber.pem)'
|
41
|
+
class_option :encryption_key,
|
42
|
+
type: :string,
|
43
|
+
desc: 'The path to or contents of the public key associated with the project (typically .chamber.pub.pem)'
|
44
|
+
class_option :shell,
|
45
|
+
default: self.new,
|
46
|
+
desc: 'The command runner. Can be overridden for specific logging capabilities.'
|
47
|
+
|
48
|
+
desc 'travis SUBCOMMAND ...ARGS', 'For manipulating Travis CI environment variables'
|
49
|
+
subcommand 'travis', Chamber::Binary::Travis
|
50
|
+
|
51
|
+
desc 'heroku SUBCOMMAND ...ARGS', 'For manipulating Heroku environment variables'
|
52
|
+
subcommand 'heroku', Chamber::Binary::Heroku
|
53
|
+
|
54
|
+
desc 'show', 'Displays the list of settings and their values'
|
55
|
+
method_option :as_env,
|
56
|
+
type: :boolean,
|
57
|
+
aliases: '-e',
|
58
|
+
desc: 'Whether the displayed settings should be environment variable compatible'
|
59
|
+
def show
|
60
|
+
puts Commands::Show.call(options)
|
61
|
+
end
|
62
|
+
|
63
|
+
desc 'files', 'Lists the settings files which are parsed with the given options'
|
64
|
+
def files
|
65
|
+
puts Commands::Files.call(options)
|
66
|
+
end
|
67
|
+
|
68
|
+
desc 'compare', 'Displays the difference between what is currently stored in the Heroku application\'s config and what Chamber knows about locally'
|
69
|
+
method_option :keys_only,
|
70
|
+
type: :boolean,
|
71
|
+
default: true,
|
72
|
+
desc: 'Whether or not to only compare the keys but not the values of the two sets of settings'
|
73
|
+
method_option :first,
|
74
|
+
type: :array,
|
75
|
+
desc: 'The list of namespaces which will be used as the source of the comparison'
|
76
|
+
method_option :second,
|
77
|
+
type: :array,
|
78
|
+
desc: 'The list of namespaces which will be used as the destination of the comparison'
|
79
|
+
def compare
|
80
|
+
Commands::Compare.call(options)
|
81
|
+
end
|
82
|
+
|
83
|
+
desc 'secure', 'Secures any values which appear to need to be encrypted in any of the settings files which match irrespective of namespaces'
|
84
|
+
def secure
|
85
|
+
Commands::Secure.call(options)
|
86
|
+
end
|
87
|
+
|
88
|
+
desc 'init', 'Sets Chamber up matching best practices for secure configuration management'
|
89
|
+
def init
|
90
|
+
Commands::Initialize.call(options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'chamber/commands/travis/secure'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Binary
|
6
|
+
class Travis < Thor
|
7
|
+
|
8
|
+
desc 'secure', 'Uses your Travis CI public key to encrypt the settings you have chosen not to commit to the repo'
|
9
|
+
method_option :dry_run,
|
10
|
+
type: :boolean,
|
11
|
+
aliases: '-d',
|
12
|
+
desc: 'Does not actually encrypt anything to .travis.yml, but instead displays what values would be encrypted'
|
13
|
+
method_option :only_sensitive,
|
14
|
+
type: :boolean,
|
15
|
+
aliases: '-o',
|
16
|
+
default: true,
|
17
|
+
desc: 'Does not encrypt settings into .travis.yml unless they are contained in files which have been gitignored or settings which are marked as "_secure"'
|
18
|
+
def secure
|
19
|
+
Commands::Travis::Secure.call(options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'chamber/commands/context_resolver'
|
2
|
+
require 'chamber/instance'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
class Base
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
options = ContextResolver.resolve(options)
|
10
|
+
|
11
|
+
self.chamber = Chamber::Instance.new options
|
12
|
+
self.shell = options[:shell]
|
13
|
+
self.rootpath = options[:rootpath]
|
14
|
+
self.dry_run = options[:dry_run]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.call(options = {})
|
18
|
+
self.new(options).call
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
attr_accessor :chamber,
|
24
|
+
:shell,
|
25
|
+
:dry_run
|
26
|
+
attr_reader :rootpath
|
27
|
+
|
28
|
+
def rootpath=(other)
|
29
|
+
@rootpath ||= Pathname.new(other)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Commands
|
5
|
+
module Comparable
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
super
|
9
|
+
|
10
|
+
self.keys_only = options[:keys_only]
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
system("git diff --no-index #{first_settings_file} #{second_settings_file}")
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
attr_accessor :keys_only
|
20
|
+
|
21
|
+
def first_settings_file
|
22
|
+
create_comparable_settings_file 'first', first_settings_data
|
23
|
+
end
|
24
|
+
|
25
|
+
def second_settings_file
|
26
|
+
create_comparable_settings_file 'second', second_settings_data
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_comparable_settings_file(name, config)
|
30
|
+
Tempfile.open(name) do |file|
|
31
|
+
file.write config
|
32
|
+
file.to_path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'chamber/instance'
|
2
|
+
require 'chamber/commands/base'
|
3
|
+
require 'chamber/commands/comparable'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
class Compare < Chamber::Commands::Base
|
8
|
+
include Chamber::Commands::Comparable
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
super
|
12
|
+
|
13
|
+
first_settings_options = options.merge(namespaces: options[:first])
|
14
|
+
self.first_settings_instance = Chamber::Instance.new(first_settings_options)
|
15
|
+
|
16
|
+
second_settings_options = options.merge(namespaces: options[:second])
|
17
|
+
self.second_settings_instance = Chamber::Instance.new(second_settings_options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.call(options = {})
|
21
|
+
self.new(options).call
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
attr_accessor :first_settings_instance,
|
27
|
+
:second_settings_instance
|
28
|
+
|
29
|
+
def first_settings_data
|
30
|
+
settings_data(first_settings_instance)
|
31
|
+
end
|
32
|
+
|
33
|
+
def second_settings_data
|
34
|
+
settings_data(second_settings_instance)
|
35
|
+
end
|
36
|
+
|
37
|
+
def settings_data(instance)
|
38
|
+
if keys_only
|
39
|
+
instance.to_environment.keys.join("\n")
|
40
|
+
else
|
41
|
+
instance.to_s(pair_separator: "\n")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Chamber
|
2
|
+
module Commands
|
3
|
+
class ContextResolver
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
self.options = options.dup
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolve
|
10
|
+
options[:rootpath] ||= Pathname.pwd
|
11
|
+
options[:rootpath] = Pathname.new(options[:rootpath])
|
12
|
+
options[:encryption_key] = resolve_encryption_key(options[:encryption_key])
|
13
|
+
options[:decryption_key] = resolve_decryption_key(options[:decryption_key])
|
14
|
+
options[:namespaces] ||= []
|
15
|
+
options[:preset] ||= resolve_preset
|
16
|
+
|
17
|
+
if options[:preset] == 'rails'
|
18
|
+
options[:basepath] ||= options[:rootpath] + 'config'
|
19
|
+
|
20
|
+
if options[:namespaces] == []
|
21
|
+
require options[:rootpath].join('config', 'application')
|
22
|
+
|
23
|
+
options[:namespaces] = [::Rails.env]
|
24
|
+
end
|
25
|
+
else
|
26
|
+
options[:basepath] ||= options[:rootpath]
|
27
|
+
end
|
28
|
+
|
29
|
+
options
|
30
|
+
rescue LoadError
|
31
|
+
options
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.resolve(options = {})
|
35
|
+
self.new(options).resolve
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
attr_accessor :options
|
41
|
+
|
42
|
+
def resolve_preset
|
43
|
+
if in_a_rails_project?
|
44
|
+
'rails'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def resolve_encryption_key(key)
|
49
|
+
key ||= options[:rootpath] + '.chamber.pub.pem'
|
50
|
+
|
51
|
+
key if Pathname.new(key).readable?
|
52
|
+
end
|
53
|
+
|
54
|
+
def resolve_decryption_key(key)
|
55
|
+
key ||= options[:rootpath] + '.chamber.pem'
|
56
|
+
|
57
|
+
key if Pathname.new(key).readable?
|
58
|
+
end
|
59
|
+
|
60
|
+
def in_a_rails_project?
|
61
|
+
(options[:rootpath] + 'config.ru').exist? &&
|
62
|
+
rails_executable_exists?
|
63
|
+
end
|
64
|
+
|
65
|
+
def rails_executable_exists?
|
66
|
+
options[:rootpath].join('bin', 'rails').exist? ||
|
67
|
+
options[:rootpath].join('script', 'rails').exist? ||
|
68
|
+
options[:rootpath].join('script', 'console').exist?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Commands
|
5
|
+
module Heroku
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
super
|
9
|
+
|
10
|
+
self.app = options[:app]
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
attr_accessor :app
|
16
|
+
|
17
|
+
def configuration
|
18
|
+
@configuration ||= heroku("config --shell").chomp
|
19
|
+
end
|
20
|
+
|
21
|
+
def heroku(command)
|
22
|
+
Bundler.with_clean_env { `heroku #{command}#{app_option}` }
|
23
|
+
end
|
24
|
+
|
25
|
+
def app_option
|
26
|
+
app ? " --app #{app}" : ""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chamber/commands/base'
|
2
|
+
require 'chamber/commands/heroku'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
module Heroku
|
7
|
+
class Clear < Chamber::Commands::Base
|
8
|
+
include Chamber::Commands::Heroku
|
9
|
+
|
10
|
+
def call
|
11
|
+
chamber.to_environment.keys.each do |key|
|
12
|
+
next unless configuration.match(key)
|
13
|
+
|
14
|
+
if dry_run
|
15
|
+
shell.say_status 'remove', key, :blue
|
16
|
+
else
|
17
|
+
shell.say_status 'remove', key, :green
|
18
|
+
shell.say heroku("config:unset #{key}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'chamber/commands/securable'
|
2
|
+
require 'chamber/commands/heroku'
|
3
|
+
require 'chamber/commands/comparable'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
module Heroku
|
8
|
+
class Compare < Chamber::Commands::Base
|
9
|
+
include Chamber::Commands::Securable
|
10
|
+
include Chamber::Commands::Heroku
|
11
|
+
include Chamber::Commands::Comparable
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def first_settings_data
|
16
|
+
if only_sensitive
|
17
|
+
secured_settings.to_s(pair_separator: "\n",
|
18
|
+
value_surrounder: '')
|
19
|
+
else
|
20
|
+
all_settings.to_s(pair_separator: "\n",
|
21
|
+
value_surrounder: '')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def second_settings_data
|
26
|
+
configuration
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'chamber/commands/base'
|
2
|
+
require 'chamber/commands/heroku'
|
3
|
+
|
4
|
+
module Chamber
|
5
|
+
module Commands
|
6
|
+
module Heroku
|
7
|
+
class Pull < Chamber::Commands::Base
|
8
|
+
include Chamber::Commands::Heroku
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
super
|
12
|
+
|
13
|
+
self.target_file = options[:into]
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
if target_file
|
18
|
+
shell.create_file target_file, configuration
|
19
|
+
else
|
20
|
+
configuration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
attr_accessor :target_file
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|