Class: Ironclad::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/ironclad/config.rb

Overview

Project configuration, read from config/ironclad.yml so both the CLI (no Rails boot) and the Railtie can load it. Any environment names work — they only have to match the keys you define here.

account: my_app   # optional
keys:
  default:    op://VAULT/my_app/master.key
  production: op://VAULT/my_app/production.key

‘app` (the OS-keystore cache namespace) is optional; it defaults to the Rails app name read from config/application.rb.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, root: nil) ⇒ Config

Returns a new instance of Config.



47
48
49
50
51
52
53
54
# File 'lib/ironclad/config.rb', line 47

def initialize(data, root: nil)
  @app = data['app'] || self.class.app_namespace(root)
  @account = data['account']
  @keys = data.fetch('keys') { raise Error, 'ironclad.yml is missing `keys`' }
  unless @keys.is_a?(Hash)
    raise Error, 'ironclad.yml `keys` must be a mapping of environment => secret reference'
  end
end

Instance Attribute Details

#accountObject (readonly)

Returns the value of attribute account.



18
19
20
# File 'lib/ironclad/config.rb', line 18

def 
  @account
end

#appObject (readonly)

Returns the value of attribute app.



18
19
20
# File 'lib/ironclad/config.rb', line 18

def app
  @app
end

#keysObject (readonly)

Returns the value of attribute keys.



18
19
20
# File 'lib/ironclad/config.rb', line 18

def keys
  @keys
end

Class Method Details

.app_namespace(root) ⇒ Object

Cache namespace, derived from the app’s module name in config/application.rb (falling back to the directory name) so the railtie and the no-Rails CLI agree on one OS-keystore entry per app.



38
39
40
41
42
43
44
45
# File 'lib/ironclad/config.rb', line 38

def self.app_namespace(root)
  return 'ironclad' unless root

  app_rb = File.join(root, 'config', 'application.rb')
  name = File.file?(app_rb) ? File.read(app_rb)[/^\s*module\s+([A-Za-z]\w*)/, 1] : nil
  name ||= File.basename(root)
  name.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
end

.load(path) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/ironclad/config.rb', line 20

def self.load(path)
  unless File.exist?(path)
    raise Error, "Ironclad config not found at #{path}. " \
                 'Run `rails generate ironclad:install` to create it.'
  end

  root = File.dirname(path, 2)
  data = YAML.safe_load_file(path)
  unless data.is_a?(Hash)
    raise Error, "#{path} is empty or not a YAML mapping"
  end

  new(data, root: root)
end

Instance Method Details

#cache_key(environment) ⇒ Object

OS keystore service name for an environment’s cached key.



80
81
82
# File 'lib/ironclad/config.rb', line 80

def cache_key(environment)
  "#{app}-credentials-#{environment}"
end

#environmentsObject



63
64
65
# File 'lib/ironclad/config.rb', line 63

def environments
  keys.keys
end

#key?(environment) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/ironclad/config.rb', line 67

def key?(environment)
  keys.key?(environment)
end

#key_for(environment) ⇒ Object

The config key to use for a Rails environment: its own if defined, otherwise ‘default` (the master key). Nil if neither exists.



73
74
75
76
77
# File 'lib/ironclad/config.rb', line 73

def key_for(environment)
  return environment if key?(environment)

  'default' if key?('default')
end

#reference(environment) ⇒ Object



56
57
58
59
60
61
# File 'lib/ironclad/config.rb', line 56

def reference(environment)
  keys.fetch(environment) do
    raise Error, "No secret reference for `#{environment}`. " \
                 "Known environments: #{keys.keys.join(', ')}."
  end
end