Class: Inspec::ControlEvalContext

Inherits:
Object
  • Object
show all
Includes:
DSL, DSL::RequireOverride
Defined in:
lib/inspec/control_eval_context.rb

Overview

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).

Instance Attribute Summary collapse

Attributes included from DSL

#backend

Instance Method Summary collapse

Methods included from DSL::RequireOverride

#__ruby_require, #require

Methods included from DSL

filter_included_controls, #include_controls, load_spec_files_for_profile, #method_missing, method_missing_resource, #require_controls, #require_resource

Constructor Details

#initialize(profile_context, resources_dsl, backend, conf, dependencies, require_loader, skip_only_if_eval) ⇒ ControlEvalContext

Returns a new instance of ControlEvalContext.



22
23
24
25
26
27
28
29
30
31
32
33
34
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Inspec::DSL

Instance Attribute Details

#profile_contextObject Also known as: profile_context_owner

Returns the value of attribute profile_context.



19
20
21
# File 'lib/inspec/control_eval_context.rb', line 19

def profile_context
  @profile_context
end

#resources_dslObject

Returns the value of attribute resources_dsl.



20
21
22
# File 'lib/inspec/control_eval_context.rb', line 20

def resources_dsl
  @resources_dsl
end

#skip_fileObject

Returns the value of attribute skip_file.



18
19
20
# File 'lib/inspec/control_eval_context.rb', line 18

def skip_file
  @skip_file
end

Instance Method Details

#add_resource(name, new_res) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/inspec/control_eval_context.rb', line 95

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) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/inspec/control_eval_context.rb', line 103

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) ⇒ Object



117
118
119
# File 'lib/inspec/control_eval_context.rb', line 117

def add_subcontext(context)
  profile_context_owner.add_subcontext(context)
end

#attribute(name, options = {}) ⇒ Object



158
159
160
161
# File 'lib/inspec/control_eval_context.rb', line 158

def attribute(name, options = {})
  Inspec.deprecate(:attrs_dsl, "Input name: #{name}, Profile: #{profile_id}")
  input(name, options)
end

#control(id, opts = {}, &block) ⇒ Object Also known as: rule



54
55
56
57
58
59
60
# File 'lib/inspec/control_eval_context.rb', line 54

def control(id, opts = {}, &block)
  opts[:skip_only_if_eval] = @skip_only_if_eval
  tag_ids = control_tags(&block)
  if (controls_list_empty? && tags_list_empty?) || control_exist_in_controls_list?(id) || tag_exist_in_control_tags?(tag_ids)
    register_control(Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block))
  end
end

#control_tags(&block) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/inspec/control_eval_context.rb', line 64

def control_tags(&block)
  tag_source = block.source.split("\n").select { |src| src.split.first.eql?("tag") }
  tag_source = tag_source.map { |src| src.sub("tag", "").strip }.map { |src| src.split(",").map { |final_src| final_src.sub(/([^:]*):/, "") } }.flatten
  output = tag_source.map { |src| src.sub(/\[|\]/, "") }.map { |src| instance_eval(src) }
  output.compact.uniq
rescue
  []
end

#describe(*args, &block) ⇒ Object

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.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/inspec/control_eval_context.rb', line 78

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 = {}) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/inspec/control_eval_context.rb', line 140

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) ⇒ Object

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



154
155
156
# File 'lib/inspec/control_eval_context.rb', line 154

def input_object(input_name)
  Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
end

#only_if(message = nil, &block) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/inspec/control_eval_context.rb', line 168

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_idObject



38
39
40
# File 'lib/inspec/control_eval_context.rb', line 38

def profile_id
  profile_context.profile_id
end

#profile_nameObject



50
51
52
# File 'lib/inspec/control_eval_context.rb', line 50

def profile_name
  profile_id
end

#register_control(control, &block) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/inspec/control_eval_context.rb', line 121

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

#skip_control(id) ⇒ Object Also known as: skip_rule



163
164
165
# File 'lib/inspec/control_eval_context.rb', line 163

def skip_control(id)
  profile_context_owner.unregister_rule(id)
end

#title(arg) ⇒ Object



46
47
48
# File 'lib/inspec/control_eval_context.rb', line 46

def title(arg)
  profile_context_owner.set_header(:title, arg)
end

#to_sObject



42
43
44
# File 'lib/inspec/control_eval_context.rb', line 42

def to_s
  "Control Evaluation Context (#{profile_name})"
end