container_config 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +35 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +28 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +21 -0
- data/README.md +116 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/container_config.gemspec +37 -0
- data/lib/container_config.rb +185 -0
- data/lib/container_config/coercer.rb +61 -0
- data/lib/container_config/coercer/base.rb +39 -0
- data/lib/container_config/coercer/boolean.rb +34 -0
- data/lib/container_config/coercer/float.rb +33 -0
- data/lib/container_config/coercer/integer.rb +33 -0
- data/lib/container_config/coercer/ssl_certificate.rb +47 -0
- data/lib/container_config/coercer/ssl_key.rb +45 -0
- data/lib/container_config/coercer/ssl_verify_mode.rb +42 -0
- data/lib/container_config/coercer/string.rb +31 -0
- data/lib/container_config/coercer/symbol.rb +33 -0
- data/lib/container_config/logger.rb +9 -0
- data/lib/container_config/provider.rb +66 -0
- data/lib/container_config/provider/base.rb +39 -0
- data/lib/container_config/provider/default.rb +30 -0
- data/lib/container_config/provider/env.rb +29 -0
- data/lib/container_config/provider/rails_credential.rb +31 -0
- data/lib/container_config/provider/secret_volume.rb +58 -0
- data/lib/container_config/rails.rb +10 -0
- data/lib/container_config/rails/mailer.rb +81 -0
- data/lib/container_config/redis.rb +95 -0
- data/lib/container_config/version.rb +6 -0
- metadata +167 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config"
|
4
|
+
require "container_config/coercer/base"
|
5
|
+
require "container_config/coercer/boolean"
|
6
|
+
require "container_config/coercer/float"
|
7
|
+
require "container_config/coercer/integer"
|
8
|
+
require "container_config/coercer/string"
|
9
|
+
require "container_config/coercer/symbol"
|
10
|
+
require "container_config/coercer/ssl_verify_mode"
|
11
|
+
require "container_config/coercer/ssl_certificate"
|
12
|
+
require "container_config/coercer/ssl_key"
|
13
|
+
|
14
|
+
module ContainerConfig
|
15
|
+
# Contains classes and methods for type coercion
|
16
|
+
module Coercer
|
17
|
+
#
|
18
|
+
# Coerces a given value into a requested type
|
19
|
+
#
|
20
|
+
# @param [Object] value value to coerce
|
21
|
+
# @param [Symbol] value_type requested type such as :boolean, :integer, :string, :symbol,
|
22
|
+
# :ssl_verify_mode, :ssl_certificate, or :ssl_key
|
23
|
+
# @param [Hash] options Options Hash
|
24
|
+
# @option options [Boolean] :coerce_nil where to coerce nil values (defaults to true)
|
25
|
+
#
|
26
|
+
# @return [Object] coerced value
|
27
|
+
#
|
28
|
+
def self.coerce_value(value, value_type = nil, options = {})
|
29
|
+
return value unless value_type
|
30
|
+
|
31
|
+
return value if options[:coerce_nil] == false && value.nil?
|
32
|
+
|
33
|
+
value_type = value_type.to_sym
|
34
|
+
|
35
|
+
ContainerConfig.coercers.each do |coercer|
|
36
|
+
return coercer.coerce(value) if coercer.type == value_type
|
37
|
+
end
|
38
|
+
|
39
|
+
ContainerConfig.logger.warn { "Could not find valid coercion type for #{value_type}" }
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Array of default coercers
|
45
|
+
#
|
46
|
+
# @return [Array<ContainerConfig::Coercer::Base>] default coercers
|
47
|
+
#
|
48
|
+
def self.default_coercers
|
49
|
+
[
|
50
|
+
ContainerConfig::Coercer::Boolean.new,
|
51
|
+
ContainerConfig::Coercer::Float.new,
|
52
|
+
ContainerConfig::Coercer::Integer.new,
|
53
|
+
ContainerConfig::Coercer::SslCertificate.new,
|
54
|
+
ContainerConfig::Coercer::SslKey.new,
|
55
|
+
ContainerConfig::Coercer::SslVerifyMode.new,
|
56
|
+
ContainerConfig::Coercer::String.new,
|
57
|
+
ContainerConfig::Coercer::Symbol.new
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ContainerConfig
|
4
|
+
module Coercer
|
5
|
+
# Base type coercer
|
6
|
+
class Base
|
7
|
+
#
|
8
|
+
# Returns name of the coercer
|
9
|
+
#
|
10
|
+
# @return [String] coercer name
|
11
|
+
#
|
12
|
+
def name
|
13
|
+
raise ContainerConfig::MissingOverride, "Must override name method in derived class #{self.class}"
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Returns the type of the coercer
|
18
|
+
# This is used by the ContainerConfig::Coercer.coerce_value method to determine
|
19
|
+
# whether this coercer should be used for a given type
|
20
|
+
#
|
21
|
+
# @return [Symbol] coercer type
|
22
|
+
#
|
23
|
+
def type
|
24
|
+
raise ContainerConfig::MissingOverride, "Must override type method in derived class #{self.class}"
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Coerces the given value into the coercer type
|
29
|
+
#
|
30
|
+
# @param [Object] _value given value
|
31
|
+
#
|
32
|
+
# @return [Object] coerced value
|
33
|
+
#
|
34
|
+
def coerce(_value)
|
35
|
+
raise ContainerConfig::MissingOverride, "Must override coerce method in derived class #{self.class}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config/coercer/base"
|
4
|
+
|
5
|
+
module ContainerConfig
|
6
|
+
module Coercer
|
7
|
+
# Boolean type coercer
|
8
|
+
class Boolean < Base
|
9
|
+
# @see ContainerConfig::Coercer::Base#name
|
10
|
+
def name
|
11
|
+
"Boolean"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#type
|
15
|
+
def type
|
16
|
+
:boolean
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Coerces the given value into a boolean
|
21
|
+
#
|
22
|
+
# @param [Object] value given value
|
23
|
+
#
|
24
|
+
# @return [Boolean] coerced value
|
25
|
+
#
|
26
|
+
def coerce(value)
|
27
|
+
# If a digit is passed, check if it is non-zero and return true for non-zero values
|
28
|
+
return value.to_i != 0 if value.respond_to?(:to_i) && value.to_i.to_s == value.to_s
|
29
|
+
|
30
|
+
value.to_s.casecmp?("true")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config/coercer/base"
|
4
|
+
|
5
|
+
module ContainerConfig
|
6
|
+
module Coercer
|
7
|
+
# Float type coercer
|
8
|
+
class Float < Base
|
9
|
+
# @see ContainerConfig::Coercer::Base#name
|
10
|
+
def name
|
11
|
+
"Float"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#type
|
15
|
+
def type
|
16
|
+
:float
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Coerces the given value into a float
|
21
|
+
#
|
22
|
+
# @param [Object] value given value
|
23
|
+
#
|
24
|
+
# @return [Float] coerced value
|
25
|
+
#
|
26
|
+
def coerce(value)
|
27
|
+
return 0.0 unless value.respond_to?(:to_f)
|
28
|
+
|
29
|
+
value.to_f
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config/coercer/base"
|
4
|
+
|
5
|
+
module ContainerConfig
|
6
|
+
module Coercer
|
7
|
+
# Integer type coercer
|
8
|
+
class Integer < Base
|
9
|
+
# @see ContainerConfig::Coercer::Base#name
|
10
|
+
def name
|
11
|
+
"Integer"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#type
|
15
|
+
def type
|
16
|
+
:integer
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Coerces the given value into an integer
|
21
|
+
#
|
22
|
+
# @param [Object] value given value
|
23
|
+
#
|
24
|
+
# @return [Integer] coerced value
|
25
|
+
#
|
26
|
+
def coerce(value)
|
27
|
+
return 0 unless value.respond_to?(:to_i)
|
28
|
+
|
29
|
+
value.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config"
|
4
|
+
require "container_config/coercer/base"
|
5
|
+
require "openssl"
|
6
|
+
|
7
|
+
module ContainerConfig
|
8
|
+
module Coercer
|
9
|
+
# SSL certificate type coercer
|
10
|
+
class SslCertificate < Base
|
11
|
+
# @see ContainerConfig::Coercer::Base#name
|
12
|
+
def name
|
13
|
+
"SSL Certificate"
|
14
|
+
end
|
15
|
+
|
16
|
+
# @see ContainerConfig::Coercer::Base#type
|
17
|
+
def type
|
18
|
+
:ssl_certificate
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Coerces the given value into an SSL certificate
|
23
|
+
#
|
24
|
+
# @param [Object] value SSL certificate path
|
25
|
+
#
|
26
|
+
# @return [OpenSSL::X509::Certificate] coerced value
|
27
|
+
#
|
28
|
+
def coerce(value)
|
29
|
+
return if value.nil?
|
30
|
+
|
31
|
+
return value if value.is_a?(OpenSSL::X509::Certificate)
|
32
|
+
|
33
|
+
cert_path = value.to_s
|
34
|
+
|
35
|
+
unless File.exist?(cert_path)
|
36
|
+
ContainerConfig.logger.warn { "Could not find SSL certificate at #{cert_path}" }
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
OpenSSL::X509::Certificate.new(File.read(cert_path))
|
41
|
+
rescue OpenSSL::X509::CertificateError => e
|
42
|
+
ContainerConfig.logger.warn { "Could not parse SSL certificate #{cert_path} successfully: #{e}" }
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config"
|
4
|
+
require "container_config/coercer/base"
|
5
|
+
require "openssl"
|
6
|
+
|
7
|
+
module ContainerConfig
|
8
|
+
module Coercer
|
9
|
+
# SSL key type coercer
|
10
|
+
class SslKey < Base
|
11
|
+
# @see ContainerConfig::Coercer::Base#name
|
12
|
+
def name
|
13
|
+
"SSL Private Key"
|
14
|
+
end
|
15
|
+
|
16
|
+
# @see ContainerConfig::Coercer::Base#type
|
17
|
+
def type
|
18
|
+
:ssl_key
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Coerces the given value into an SSL key
|
23
|
+
#
|
24
|
+
# @param [Object] value SSL key path
|
25
|
+
#
|
26
|
+
# @return [OpenSSL::PKey::RSA] coerced value
|
27
|
+
#
|
28
|
+
def coerce(value)
|
29
|
+
return if value.nil?
|
30
|
+
|
31
|
+
key_path = value.to_s
|
32
|
+
|
33
|
+
unless File.exist?(key_path)
|
34
|
+
ContainerConfig.logger.warn { "Could not find SSL key at #{key_path}" }
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
OpenSSL::PKey::RSA.new(File.read(key_path))
|
39
|
+
rescue OpenSSL::PKey::RSAError => e
|
40
|
+
ContainerConfig.logger.warn { "Could not parse SSL key #{key_path} successfully: #{e}" }
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config"
|
4
|
+
require "container_config/coercer/base"
|
5
|
+
require "openssl"
|
6
|
+
|
7
|
+
module ContainerConfig
|
8
|
+
module Coercer
|
9
|
+
# SSL verification mode type coercer
|
10
|
+
class SslVerifyMode < Base
|
11
|
+
# Array of valid SSL verification modes
|
12
|
+
VALID_MODES = OpenSSL::SSL.constants.select { |c| c.to_s.start_with?("VERIFY") }.map(&:to_s)
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#name
|
15
|
+
def name
|
16
|
+
"SSL Verification Mode"
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see ContainerConfig::Coercer::Base#type
|
20
|
+
def type
|
21
|
+
:ssl_verify_mode
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Coerces the given value into an SSL verification mode
|
26
|
+
#
|
27
|
+
# @param [Object] value SSL verification mode string ("VERIFY_NONE", "VERIFY_PEER", etc.)
|
28
|
+
#
|
29
|
+
# @return [Integer] coerced value
|
30
|
+
#
|
31
|
+
def coerce(value)
|
32
|
+
value = value.to_s
|
33
|
+
return Object.const_get("OpenSSL::SSL::#{value}") if VALID_MODES.include?(value)
|
34
|
+
|
35
|
+
ContainerConfig.logger.warn do
|
36
|
+
"Could not convert #{value.inspect} into a valid OpenSSL verification mode.\nValid modes: #{VALID_MODES.join(", ")}"
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config/coercer/base"
|
4
|
+
|
5
|
+
module ContainerConfig
|
6
|
+
module Coercer
|
7
|
+
# String type coercer
|
8
|
+
class String < Base
|
9
|
+
# @see ContainerConfig::Coercer::Base#name
|
10
|
+
def name
|
11
|
+
"String"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#type
|
15
|
+
def type
|
16
|
+
:string
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Coerces the given value into a string
|
21
|
+
#
|
22
|
+
# @param [Object] value given value
|
23
|
+
#
|
24
|
+
# @return [String] coerced value
|
25
|
+
#
|
26
|
+
def coerce(value)
|
27
|
+
value.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config/coercer/base"
|
4
|
+
|
5
|
+
module ContainerConfig
|
6
|
+
module Coercer
|
7
|
+
# Symbol type coercer
|
8
|
+
class Symbol < Base
|
9
|
+
# @see ContainerConfig::Coercer::Base#name
|
10
|
+
def name
|
11
|
+
"Symbol"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see ContainerConfig::Coercer::Base#type
|
15
|
+
def type
|
16
|
+
:symbol
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Coerces the given value into a symbol
|
21
|
+
#
|
22
|
+
# @param [Object] value given value
|
23
|
+
#
|
24
|
+
# @return [Symbol] coerced value
|
25
|
+
#
|
26
|
+
def coerce(value)
|
27
|
+
return if value.nil?
|
28
|
+
|
29
|
+
value.to_s.to_sym
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "container_config"
|
4
|
+
require "container_config/provider/base"
|
5
|
+
require "container_config/provider/default"
|
6
|
+
require "container_config/provider/env"
|
7
|
+
require "container_config/provider/rails_credential"
|
8
|
+
require "container_config/provider/secret_volume"
|
9
|
+
|
10
|
+
module ContainerConfig
|
11
|
+
# Contains classes and methods for config value providers
|
12
|
+
module Provider
|
13
|
+
#
|
14
|
+
# Loads a value from the config value providers
|
15
|
+
#
|
16
|
+
# @param [String] key Configuration key to load
|
17
|
+
# @param [Array] dig_keys Variable keys to use to load from providers that accept a dig structure
|
18
|
+
# defaults to the lowercase key split by underscores
|
19
|
+
# "MY_PASSWORD" => ["my", "password"]
|
20
|
+
# @param [Hash] options Options Hash
|
21
|
+
# @option options [String] :default default value if the configuration setting cannot be found
|
22
|
+
# @option options [String] :secret_mount_directory directory where secret files are mounted
|
23
|
+
# @option options [Symbol] :type type to use such as :boolean, :integer, :string, :symbol,
|
24
|
+
# :ssl_verify_mode, :ssl_certificate, or :ssl_key
|
25
|
+
#
|
26
|
+
# @return [Object] configuration setting value
|
27
|
+
#
|
28
|
+
def self.load_value(key, *dig_keys, **options)
|
29
|
+
value = nil
|
30
|
+
ContainerConfig.providers.each do |p|
|
31
|
+
value = p.load(key, *dig_keys, **options)
|
32
|
+
break unless value.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
value
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Array of default providers
|
40
|
+
#
|
41
|
+
# @return [Array<ContainerConfig::Provider::Base>] default providers
|
42
|
+
#
|
43
|
+
def self.default_providers
|
44
|
+
defaults = [
|
45
|
+
ContainerConfig::Provider::Env.new,
|
46
|
+
ContainerConfig::Provider::SecretVolume.new
|
47
|
+
]
|
48
|
+
|
49
|
+
defaults |= rails_providers if ContainerConfig.rails_app?
|
50
|
+
defaults << ContainerConfig::Provider::Default.new
|
51
|
+
|
52
|
+
defaults
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Array of Rails providers
|
57
|
+
# These are only included in the default providers when this gem is included
|
58
|
+
# as part of a rails application
|
59
|
+
#
|
60
|
+
# @return [Array<ContainerConfig::Provider::Base>] default providers
|
61
|
+
#
|
62
|
+
def self.rails_providers
|
63
|
+
[ContainerConfig::Provider::RailsCredential.new]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|