class Inspec::ControlEvalContext

ControlEvalContext constructs an anonymous class that control files will be instance_exec'd against.

The anonymous class includes the given passed resource_dsl as well as the basic DSL of the control files (describe, control, title, etc).

Attributes

profile_context[RW]
profile_context_owner[RW]
resources_dsl[RW]
skip_file[RW]

Public Class Methods

new(profile_context, resources_dsl, backend, conf, dependencies, require_loader, skip_only_if_eval) click to toggle source
# File lib/inspec/control_eval_context.rb, line 22
def initialize(profile_context, resources_dsl, backend, conf, dependencies, require_loader, skip_only_if_eval)
  @profile_context = profile_context
  @resources_dsl = resources_dsl
  @backend = backend
  @conf = conf
  @dependencies = dependencies
  @require_loader = require_loader
  @skip_file_message = nil
  @skip_file = false
  @skip_only_if_eval = skip_only_if_eval

  extend resources_dsl # TODO: remove? push to method_missing?
end

Public Instance Methods

add_resource(name, new_res) click to toggle source
# File lib/inspec/control_eval_context.rb, line 102
def add_resource(name, new_res)
  resources_dsl.module_exec do
    define_method name.to_sym do |*args|
      new_res.new(@backend, name.to_s, *args)
    end
  end
end
add_resources(context) click to toggle source
# File lib/inspec/control_eval_context.rb, line 110
def add_resources(context)
  # # TODO: write real unit tests for this and then make this change:
  # dsl = context.to_resources_dsl
  # self.class.include dsl
  # Inspec::Rule.include dsl

  self.class.class_eval do
    include context.to_resources_dsl
  end

  # TODO: seriously consider getting rid of the NPM model
  extend context.to_resources_dsl
end
add_subcontext(context) click to toggle source
# File lib/inspec/control_eval_context.rb, line 124
def add_subcontext(context)
  profile_context_owner.add_subcontext(context)
end
attribute(name, options = {}) click to toggle source
# File lib/inspec/control_eval_context.rb, line 165
def attribute(name, options = {})
  Inspec.deprecate(:attrs_dsl, "Input name: #{name}, Profile: #{profile_id}")
  input(name, options)
end
control(id, opts = {}, &block) click to toggle source
# File lib/inspec/control_eval_context.rb, line 54
def control(id, opts = {}, &block)
  opts[:skip_only_if_eval] = @skip_only_if_eval
  if (controls_list_empty? && tags_list_empty?) || control_exist_in_controls_list?(id)
    register_control(Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block))
  elsif !tags_list_empty?
    # Inside elsif rule is initialised before registering it because it enables fetching of control tags
    # This condition is only true when --tags option is used
    inspec_rule = Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block)
    tag_ids = control_tags(inspec_rule)
    register_control(inspec_rule) if tag_exist_in_control_tags?(tag_ids)
  end
end
Also aliased as: rule
control_tags(inspec_rule) click to toggle source
# File lib/inspec/control_eval_context.rb, line 69
def control_tags(inspec_rule)
  all_tags = []
  inspec_rule.tag.each do |key, value|
    all_tags.push(key)
    all_tags.push(value) unless value.nil?
  end
  all_tags.flatten.compact.uniq.map(&:to_s)
rescue
  []
end
describe(*args, &block) click to toggle source

Describe allows users to write rspec-like bare describe blocks without declaring an inclosing control. Here, we generate a control for them automatically and then execute the describe block in the context of that control.

# File lib/inspec/control_eval_context.rb, line 85
def describe(*args, &block)
  loc = block_location(block, caller(1..1).first)
  id = "(generated from #{loc} #{SecureRandom.hex})"

  res = nil

  rule = Inspec::Rule.new(id, profile_id, resources_dsl, {}) do
    res = describe(*args, &block)
  end

  if controls_list_empty? || control_exist_in_controls_list?(id)
    register_control(rule, &block)
  end

  res
end
input(input_name, options = {}) click to toggle source
# File lib/inspec/control_eval_context.rb, line 147
def input(input_name, options = {})
  if options.empty?
    # Simply an access, no event here
    Inspec::InputRegistry.find_or_register_input(input_name, profile_id).value
  else
    options[:priority] ||= 20
    options[:provider] = :inline_control_code
    evt = Inspec::Input.infer_event(options)
    Inspec::InputRegistry.find_or_register_input(input_name, profile_id, event: evt).value
  end
end
input_object(input_name) click to toggle source

Find the Input object, but don't collapse to a value. Will return nil on a miss.

# File lib/inspec/control_eval_context.rb, line 161
def input_object(input_name)
  Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
end
only_if(message = nil, &block) click to toggle source
# File lib/inspec/control_eval_context.rb, line 175
def only_if(message = nil, &block)
  return unless block
  return if @skip_file == true
  return if @skip_only_if_eval == true

  return if block.yield == true

  # Apply `set_skip_rule` for other rules in the same file
  profile_context_owner.rules.values.each do |r|
    sources_match = r.source_file == block.source_location[0]
    Inspec::Rule.set_skip_rule(r, true, message) if sources_match
  end

  @skip_file_message = message
  @skip_file = true
end
profile_id() click to toggle source
# File lib/inspec/control_eval_context.rb, line 38
def profile_id
  profile_context.profile_id
end
profile_name() click to toggle source
# File lib/inspec/control_eval_context.rb, line 50
def profile_name
  profile_id
end
register_control(control, &block) click to toggle source
# File lib/inspec/control_eval_context.rb, line 128
def register_control(control, &block)
  if @skip_file
    ::Inspec::Rule.set_skip_rule(control, true, @skip_file_message)
  end

  unless profile_context_owner.profile_supports_platform?
    platform = inspec.platform
    msg = "Profile `#{profile_id}` is not supported on platform #{platform.name}/#{platform.release}."
    ::Inspec::Rule.set_skip_rule(control, true, msg)
  end

  unless profile_context_owner.profile_supports_inspec_version?
    msg = "Profile `#{profile_id}` is not supported on InSpec version (#{Inspec::VERSION})."
    ::Inspec::Rule.set_skip_rule(control, true, msg)
  end

  profile_context_owner.register_rule(control, &block) unless control.nil?
end
rule(id, opts = {}, &block)
Alias for: control
skip_control(id) click to toggle source
# File lib/inspec/control_eval_context.rb, line 170
def skip_control(id)
  profile_context_owner.unregister_rule(id)
end
Also aliased as: skip_rule
skip_rule(id)
Alias for: skip_control
title(arg) click to toggle source
# File lib/inspec/control_eval_context.rb, line 46
def title(arg)
  profile_context_owner.set_header(:title, arg)
end
to_s() click to toggle source
# File lib/inspec/control_eval_context.rb, line 42
def to_s
  "Control Evaluation Context (#{profile_name})"
end

Private Instance Methods

block_location(block, alternate_caller) click to toggle source
# File lib/inspec/control_eval_context.rb, line 194
def block_location(block, alternate_caller)
  if block.nil?
    alternate_caller[/^(.+:\d+):in .+$/, 1] || "unknown"
  else
    path, line = block.source_location
    "#{File.basename(path)}:#{line}"
  end
end
control_exist_in_controls_list?(id) click to toggle source

Check if the given control exist in the –controls option

# File lib/inspec/control_eval_context.rb, line 222
def control_exist_in_controls_list?(id)
  id_exist_in_list = false
  if profile_config_exist?
    id_exist_in_list = @conf["profile"].include_controls_list.any? do |inclusion|
      # Try to see if the inclusion is a regex, and if it matches
      inclusion == id || (inclusion.is_a?(Regexp) && inclusion =~ id)
    end
  end
  id_exist_in_list
end
controls_list_empty?() click to toggle source

Returns true if configuration hash is empty or configuration hash does not have the list of controls that needs to be included

# File lib/inspec/control_eval_context.rb, line 213
def controls_list_empty?
  !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_controls_list.empty? || @conf.empty?
end
profile_config_exist?() click to toggle source

Returns true if configuration hash is not empty and it contains the list of controls is not empty

# File lib/inspec/control_eval_context.rb, line 204
def profile_config_exist?
  !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_controls_list.empty?
end
profile_tag_config_exist?() click to toggle source
# File lib/inspec/control_eval_context.rb, line 208
def profile_tag_config_exist?
  !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_tags_list.empty?
end
tag_exist_in_control_tags?(tag_ids) click to toggle source

Check if the given control exist in the –tags option

# File lib/inspec/control_eval_context.rb, line 234
def tag_exist_in_control_tags?(tag_ids)
  tag_option_matches_with_list = false
  if !tag_ids.empty? && !tag_ids.nil? && profile_tag_config_exist?
    tag_option_matches_with_list = !(tag_ids & @conf["profile"].include_tags_list).empty?
    unless tag_option_matches_with_list
      @conf["profile"].include_tags_list.any? do |inclusion|
        # Try to see if the inclusion is a regex, and if it matches
        if inclusion.is_a?(Regexp)
          tag_ids.each do |id|
            tag_option_matches_with_list = (inclusion =~ id)
            break if tag_option_matches_with_list
          end
        end
      end
    end
  end
  tag_option_matches_with_list
end
tags_list_empty?() click to toggle source
# File lib/inspec/control_eval_context.rb, line 217
def tags_list_empty?
  !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_tags_list.empty? || @conf.empty?
end