Class: Inspec::InputRegistry

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Singleton
Defined in:
lib/inspec/input_registry.rb

Overview

The InputRegistry’s responsibilities include:

- maintaining a list of Input objects that are bound to profiles
- assisting in the lookup and creation of Inputs

Defined Under Namespace

Classes: Error, InputLookupError, ProfileLookupError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeInputRegistry

Returns a new instance of InputRegistry.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/inspec/input_registry.rb', line 36

def initialize
  # Keyed on String profile_name => Hash of String input_name => Input object
  @inputs_by_profile = {}

  # this is a list of optional profile name overrides set in the inspec.yml
  @profile_aliases = {}

  # Upon creation, activate all input plugins
  activators = Inspec::Plugin::V2::Registry.instance.find_activators(plugin_type: :input)

  @plugins = activators.map do |activator|
    activator.activate!
    activator.implementation_class.new
  end

  # Activate caching for inputs by default
  @cache_inputs = true
end

Instance Attribute Details

#cache_inputsObject

Returns the value of attribute cache_inputs.



34
35
36
# File 'lib/inspec/input_registry.rb', line 34

def cache_inputs
  @cache_inputs
end

#inputs_by_profileObject (readonly)

Returns the value of attribute inputs_by_profile.



27
28
29
# File 'lib/inspec/input_registry.rb', line 27

def inputs_by_profile
  @inputs_by_profile
end

#pluginsObject (readonly)

Returns the value of attribute plugins.



27
28
29
# File 'lib/inspec/input_registry.rb', line 27

def plugins
  @plugins
end

#profile_aliasesObject (readonly)

Returns the value of attribute profile_aliases.



27
28
29
# File 'lib/inspec/input_registry.rb', line 27

def profile_aliases
  @profile_aliases
end

Instance Method Details

#__resetObject

Used in testing



343
344
345
346
# File 'lib/inspec/input_registry.rb', line 343

def __reset
  @inputs_by_profile = {}
  @profile_aliases = {}
end

#bind_profile_inputs(profile_name, sources = {}) ⇒ Object

This method is called by the Profile as soon as it has enough context to allow binding inputs to it.



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/inspec/input_registry.rb', line 146

def bind_profile_inputs(profile_name, sources = {})
  inputs_by_profile[profile_name] ||= {}

  # In a more perfect world, we could let the core plugins choose
  # self-determine what to do; but as-is, the APIs that call this
  # are a bit over-constrained.
  (profile_name, sources[:profile_metadata])
  bind_inputs_from_input_files(profile_name, sources[:cli_input_files])
  bind_inputs_from_runner_api(profile_name, sources[:runner_api])
  bind_inputs_from_cli_args(profile_name, sources[:cli_input_arg])
end

#find_or_register_input(input_name, profile_name, options = {}) ⇒ Object

————————————————————-#

Support for Individual Inputs

————————————————————-#



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/inspec/input_registry.rb', line 82

def find_or_register_input(input_name, profile_name, options = {})
  input_name = input_name.to_s
  profile_name = profile_name.to_s
  options[:event].value = Thor::CoreExt::HashWithIndifferentAccess.new(options[:event].value) if options[:event]&.value.is_a?(Hash)

  if profile_alias?(profile_name) && !profile_aliases[profile_name].nil?
    alias_name = profile_name
    profile_name = profile_aliases[profile_name]
    handle_late_arriving_alias(alias_name, profile_name) if profile_known?(alias_name)
  end

  # Find or create the input
  inputs_by_profile[profile_name] ||= {}
  if inputs_by_profile[profile_name].key?(input_name) && cache_inputs
    inputs_by_profile[profile_name][input_name].update(options)
  else
    inputs_by_profile[profile_name][input_name] = Inspec::Input.new(input_name, options)
    poll_plugins_for_update(profile_name, input_name)
  end

  inputs_by_profile[profile_name][input_name]
end

#handle_late_arriving_alias(alias_name, profile_name) ⇒ Object

It is possible for a wrapper profile to create an input in metadata, referring to the child profile by an alias that has not yet been registered. The registry will then store the inputs under the alias, as if the alias were a true profile. If that happens and the child profile also mentions the input, we will need to move some things - all inputs should be stored under the true profile name, and no inputs should be stored under the alias.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/inspec/input_registry.rb', line 126

def handle_late_arriving_alias(alias_name, profile_name)
  inputs_by_profile[profile_name] ||= {}
  inputs_by_profile[alias_name].each do |input_name, input_from_alias|
    # Move the inpuut, or if it exists, merge events
    existing = inputs_by_profile[profile_name][input_name]
    if existing
      existing.events.concat(input_from_alias.events)
    else
      inputs_by_profile[profile_name][input_name] = input_from_alias
    end
  end
  # Finally, delete the (now copied-out) entry for the alias
  inputs_by_profile.delete(alias_name)
end

#list_inputs_for_profile(profile) ⇒ Object

Returns an Hash, name => Input that have actually been mentioned



64
65
66
67
# File 'lib/inspec/input_registry.rb', line 64

def list_inputs_for_profile(profile)
  inputs_by_profile[profile] = {} unless profile_known?(profile)
  inputs_by_profile[profile]
end

#list_potential_input_names_for_profile(profile_name) ⇒ Object

Returns an Array of input names. This includes input names that plugins may be able to fetch, but have not actually been mentioned in the control code.



72
73
74
75
76
# File 'lib/inspec/input_registry.rb', line 72

def list_potential_input_names_for_profile(profile_name)
  input_names_from_dsl = inputs_by_profile[profile_name].keys
  input_names_from_plugins = plugins.map { |plugin| plugin.list_inputs(profile_name) }
  (input_names_from_dsl + input_names_from_plugins).flatten.uniq
end

#poll_plugins_for_update(profile_name, input_name) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/inspec/input_registry.rb', line 105

def poll_plugins_for_update(profile_name, input_name)
  plugins.each do |plugin|
    response = plugin.fetch(profile_name, input_name)
    evt = Inspec::Input::Event.new(
      action: :fetch,
      provider: plugin.class.plugin_name,
      priority: plugin.default_priority,
      hit: !response.nil?
    )
    evt.value = response unless response.nil?
    inputs_by_profile[profile_name][input_name].events << evt
  end
end

#register_profile_alias(name, alias_name) ⇒ Object

————————————————————-#

Support for Profiles

————————————————————-#



59
60
61
# File 'lib/inspec/input_registry.rb', line 59

def register_profile_alias(name, alias_name)
  @profile_aliases[name] = alias_name
end