inspec 2.2.61 → 2.2.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -15
  3. data/README.md +0 -1
  4. data/docs/dev/plugins.md +321 -0
  5. data/docs/profiles.md +20 -18
  6. data/lib/bundles/inspec-artifact/cli.rb +1 -0
  7. data/lib/bundles/inspec-compliance/cli.rb +1 -0
  8. data/lib/bundles/inspec-habitat/cli.rb +1 -0
  9. data/lib/bundles/inspec-init/cli.rb +1 -0
  10. data/lib/bundles/inspec-supermarket/cli.rb +1 -0
  11. data/lib/inspec.rb +4 -2
  12. data/lib/inspec/base_cli.rb +1 -0
  13. data/lib/inspec/cli.rb +35 -16
  14. data/lib/inspec/control_eval_context.rb +7 -6
  15. data/lib/inspec/dependencies/requirement.rb +0 -1
  16. data/lib/inspec/fetcher.rb +1 -2
  17. data/lib/inspec/library_eval_context.rb +1 -1
  18. data/lib/inspec/plugin/v1.rb +2 -0
  19. data/lib/inspec/{plugins → plugin/v1/plugin_types}/cli.rb +2 -0
  20. data/lib/inspec/{plugins → plugin/v1/plugin_types}/fetcher.rb +1 -1
  21. data/lib/inspec/{plugins → plugin/v1/plugin_types}/resource.rb +0 -0
  22. data/lib/inspec/{plugins → plugin/v1/plugin_types}/secret.rb +1 -1
  23. data/lib/inspec/{plugins → plugin/v1/plugin_types}/source_reader.rb +1 -1
  24. data/lib/inspec/{plugins.rb → plugin/v1/plugins.rb} +7 -5
  25. data/lib/{utils/plugin_registry.rb → inspec/plugin/v1/registry.rb} +0 -0
  26. data/lib/inspec/plugin/v2.rb +30 -0
  27. data/lib/inspec/plugin/v2/activator.rb +16 -0
  28. data/lib/inspec/plugin/v2/loader.rb +204 -0
  29. data/lib/inspec/plugin/v2/plugin_base.rb +98 -0
  30. data/lib/inspec/plugin/v2/plugin_types/cli.rb +27 -0
  31. data/lib/inspec/plugin/v2/plugin_types/mock.rb +12 -0
  32. data/lib/inspec/plugin/v2/registry.rb +76 -0
  33. data/lib/inspec/plugin/v2/status.rb +29 -0
  34. data/lib/inspec/reporters.rb +5 -1
  35. data/lib/inspec/reporters/automate.rb +1 -1
  36. data/lib/inspec/reporters/{json_merged.rb → json_automate.rb} +1 -1
  37. data/lib/inspec/resource.rb +1 -1
  38. data/lib/inspec/rule.rb +14 -8
  39. data/lib/inspec/secrets.rb +1 -2
  40. data/lib/inspec/source_reader.rb +1 -2
  41. data/lib/inspec/version.rb +1 -1
  42. data/lib/resources/apache_conf.rb +1 -1
  43. metadata +20 -10
@@ -0,0 +1,98 @@
1
+ module Inspec::Plugin::V2
2
+ # Base class for all plugins. Specific plugin types *may* inherit from this; but they must register with it.
3
+ class PluginBase
4
+ # rubocop: disable Style/ClassVars
5
+ @@plugin_type_classes = {}
6
+ # rubocop: enable Style/ClassVars
7
+
8
+ #=====================================================================#
9
+ # Management Methods
10
+ #=====================================================================#
11
+
12
+ # The global registry.
13
+ # @returns [Inspec::Plugin::V2::Registry] the singleton Plugin Registry object.
14
+ def self.registry
15
+ Inspec::Plugin::V2::Registry.instance
16
+ end
17
+
18
+ # Inform the plugin system of a new plgin type.
19
+ # This has the following effects:
20
+ # * enables Inspec.plugin(2, :your_type_here) to return the plugin
21
+ # type base class
22
+ # * defines the DSL method with the same name as the plugin type.
23
+ #
24
+ # @param [Symbol] plugin_type_name
25
+ # @param [Class] the plugin type class, defaults to assuming inheritance
26
+ def self.register_plugin_type(plugin_type_name, new_plugin_type_base_class = self)
27
+ new_dsl_method_name = plugin_type_name
28
+
29
+ # This lets the Inspec.plugin(2,:your_plugin_type) work
30
+ @@plugin_type_classes[plugin_type_name] = new_plugin_type_base_class
31
+
32
+ # This part defines the DSL command to register a concrete plugin's implementation of a plugin type
33
+ Inspec::Plugin::V2::PluginBase.define_singleton_method(new_dsl_method_name) do |hook_name, &hook_body|
34
+ plugin_concrete_class = self
35
+
36
+ # Verify class is registered (i.e. plugin_name has been called)
37
+ status = registry.find_status_by_class(plugin_concrete_class)
38
+ if status.nil?
39
+ raise Inspec::Plugin::V2::LoadError, "You must call 'plugin_name' prior to calling #{plugin_type_name} for plugin class #{plugin_concrete_class}"
40
+ end
41
+
42
+ # Construct the Activator record
43
+ activator = Inspec::Plugin::V2::Activator.new
44
+ activator.plugin_name = plugin_concrete_class.plugin_name
45
+ activator.plugin_type = plugin_type_name
46
+ activator.activator_name = hook_name.to_sym
47
+ activator.activation_proc = hook_body
48
+
49
+ status.activators << activator
50
+ end
51
+ end
52
+
53
+ # Determine the base class for a given plugin type
54
+ # @param [Symbol] plugin_type_name
55
+ # @returns [Class] the plugin type base class
56
+ def self.base_class_for_type(plugin_type_name)
57
+ @@plugin_type_classes[plugin_type_name]
58
+ end
59
+
60
+ #=====================================================================#
61
+ # DSL Methods
62
+ #=====================================================================#
63
+
64
+ # If no name provided, looks up a known plugin by class and returns the name.
65
+ #
66
+ # DSL method to declare a plugin. Once this has been called, the plugin will certainly be
67
+ # registered (known) with the Registry, and is eligible to be activated.
68
+ # This mainly handles status annotation.
69
+ #
70
+ # @param [Symbol] Name of the plugin. If a string is provided, it is converted to a Symbol.
71
+ # @returns [Symbol] Name of the plugin
72
+ def self.plugin_name(name = nil)
73
+ reg = Inspec::Plugin::V2::Registry.instance
74
+ return reg.find_status_by_class(self).name if name.nil?
75
+
76
+ name = name.to_sym
77
+
78
+ # Typically our status will already exist in the registry, from loading the
79
+ # plugin.json. If we're being loaded, presumably entry_point,
80
+ # installation_type, version
81
+ # are known.
82
+ unless reg.known_plugin?(name)
83
+ # Under some testing situations, we may not pre-exist.
84
+ status = Inspec::Plugin::V2::Status.new
85
+ reg.register(name, status)
86
+ status.entry_point = 'inline'
87
+ status.installation_type = :mock_inline
88
+ end
89
+
90
+ status = reg[name]
91
+ status.api_generation = 2
92
+ status.plugin_class = self
93
+ status.name = name
94
+
95
+ name
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ require 'inspec/base_cli'
2
+
3
+ module Inspec::Plugin::V2::PluginType
4
+ class CliCommand < Inspec::BaseCLI
5
+ # This class MUST inherit from Thor, which makes it a bit awkward to register the plugin subtype
6
+ # Since we can't inherit from PluginBase, we use the two-arg form of register_plugin_type
7
+ Inspec::Plugin::V2::PluginBase.register_plugin_type(:cli_command, self)
8
+
9
+ # Provide a description for the command group.
10
+ def self.subcommand_desc(usage_msg, desc_msg)
11
+ @usage_msg = usage_msg
12
+ @desc_msg = desc_msg
13
+ end
14
+
15
+ # Register the command group with Thor. This must be called on the implementation class AFTER
16
+ # the the cli_command activator has been called
17
+ def self.register_with_thor
18
+ # Figure out my activator name (= subcommand group name)
19
+ subcommand_name = Inspec::Plugin::V2::Registry.instance \
20
+ .find_activators(plugin_type: :cli_command, implementation_class: self) \
21
+ .first.activator_name.to_s
22
+
23
+ # Register with Thor
24
+ Inspec::InspecCLI.register(self, subcommand_name, @usage_msg, @desc_msg, {})
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ module Inspec::Plugin::V2::PluginType
2
+ # Test plugin type
3
+ class Mock < Inspec::Plugin::V2::PluginBase
4
+ register_plugin_type(:mock_plugin_type)
5
+
6
+ # This is the API for the mock plugin type: when a mock plugin is
7
+ # activated, it is expected to be able to respond to this, and "do something"
8
+ def mock_hook
9
+ raise NotImplementedError, 'Mock plugins must implement mock_hook'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,76 @@
1
+ require 'forwardable'
2
+ require 'singleton'
3
+ require_relative 'status'
4
+ require_relative 'activator'
5
+
6
+ module Inspec::Plugin::V2
7
+ class Registry
8
+ include Singleton
9
+ extend Forwardable
10
+
11
+ attr_reader :registry
12
+ def_delegator :registry, :each
13
+ def_delegator :registry, :[]
14
+ def_delegator :registry, :key?, :known_plugin?
15
+ def_delegator :registry, :keys, :plugin_names
16
+ def_delegator :registry, :values, :plugin_statuses
17
+ def_delegator :registry, :select
18
+
19
+ def initialize
20
+ @registry = {}
21
+ end
22
+
23
+ def any_load_failures?
24
+ !plugin_statuses.select(&:load_exception).empty?
25
+ end
26
+
27
+ def loaded_plugin?(name)
28
+ registry.dig(name, :loaded)
29
+ end
30
+
31
+ def loaded_count
32
+ registry.values.select(&:loaded).count
33
+ end
34
+
35
+ def known_count
36
+ registry.values.count
37
+ end
38
+
39
+ def loaded_plugin_names
40
+ registry.values.select(&:loaded).map(&:name)
41
+ end
42
+
43
+ def find_status_by_class(klass)
44
+ registry.values.detect { |status| status.plugin_class == klass }
45
+ end
46
+
47
+ # Finds Activators matching criteria (all optional) you specify as a Hash.
48
+ # @param [Symbol] plugin_name Restricts the search to the given plugin
49
+ # @param [Symbol] plugin_type Restricts the search to the given plugin type
50
+ # @param [Symbol] activator_name Name of the activator
51
+ # @param [Class] implementation_class Implementation class returned by an already-actived plugin type
52
+ # @returns [Array] Possibly empty array of Activators
53
+ def find_activators(filters = {})
54
+ plugin_statuses.map(&:activators).flatten.select do |act|
55
+ [:plugin_name, :plugin_type, :activator_name, :implementation_class].all? do |criteria|
56
+ !filters.key?(criteria) || act[criteria] == filters[criteria]
57
+ end
58
+ end
59
+ end
60
+
61
+ def register(name, status)
62
+ if known_plugin? name
63
+ Inspec::Log.warn "PluginLoader: refusing to re-register plugin '#{name}': an existing plugin with that name was loaded via #{existing.installation_type}-loading from #{existing.entry_point}"
64
+ else
65
+ registry[name.to_sym] = status
66
+ end
67
+ end
68
+
69
+ alias []= register
70
+
71
+ # Provided for test support. Purges the registry.
72
+ def __reset
73
+ @registry.clear
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,29 @@
1
+ module Inspec::Plugin::V2
2
+ # Track loading status of each plugin. These are the elements of the Registry.
3
+ #
4
+ # Lifecycle of an installed plugin:
5
+ # If present in the config file, bundled, or core, it is "known"
6
+ # All known plugins are loaded. v1 plugins auto-activate. All loaded plugins know their version.
7
+ # v2 plugins activate when they are used. All activated plugins know their implementation class.
8
+ Status = Struct.new(
9
+ :activators, # Array of Activators - where plugin_type info gets stored
10
+ :api_generation, # 0,1,2 # TODO: convert all bundled (v0) to v2
11
+ :plugin_class, # Plugin class
12
+ :entry_point, # a gem name or filesystem path
13
+ :installation_type, # :gem, :path, :core, bundle # TODO: combine core and bundle
14
+ :loaded, # true, false False could mean not attempted or failed
15
+ :load_exception, # Exception class if it failed to load
16
+ :name, # String name
17
+ :version, # three-digit version. Core / bundled plugins use InSpec version here.
18
+ ) do
19
+ def initialize(*)
20
+ super
21
+ self[:activators] = []
22
+ self[:loaded] = false
23
+ end
24
+
25
+ def plugin_types
26
+ activators.map(&:plugin_type).uniq.sort
27
+ end
28
+ end
29
+ end
@@ -1,7 +1,7 @@
1
1
  require 'inspec/reporters/base'
2
2
  require 'inspec/reporters/cli'
3
3
  require 'inspec/reporters/json'
4
- require 'inspec/reporters/json_merged'
4
+ require 'inspec/reporters/json_automate'
5
5
  require 'inspec/reporters/json_min'
6
6
  require 'inspec/reporters/junit'
7
7
  require 'inspec/reporters/automate'
@@ -17,6 +17,10 @@ module Inspec::Reporters
17
17
  reporter = Inspec::Reporters::CLI.new(config)
18
18
  when 'json'
19
19
  reporter = Inspec::Reporters::Json.new(config)
20
+ # This reporter is only used for Chef internal. We reserve the
21
+ # right to introduce breaking changes to this reporter at any time.
22
+ when 'json-automate'
23
+ reporter = Inspec::Reporters::JsonAutomate.new(config)
20
24
  when 'json-min'
21
25
  reporter = Inspec::Reporters::JsonMin.new(config)
22
26
  when 'junit'
@@ -4,7 +4,7 @@ require 'json'
4
4
  require 'net/http'
5
5
 
6
6
  module Inspec::Reporters
7
- class Automate < JsonMerged
7
+ class Automate < JsonAutomate
8
8
  def initialize(config)
9
9
  super(config)
10
10
 
@@ -3,7 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  module Inspec::Reporters
6
- class JsonMerged < Json
6
+ class JsonAutomate < Json
7
7
  def initialize(config)
8
8
  super(config)
9
9
  @profiles = []
@@ -2,7 +2,7 @@
2
2
  # copyright: 2015, Vulcano Security GmbH
3
3
  # author: Dominik Richter
4
4
  # author: Christoph Hartmann
5
- require 'inspec/plugins'
5
+ require 'inspec/plugin/v1'
6
6
 
7
7
  module Inspec
8
8
  class ProfileNotFound < StandardError; end
@@ -42,7 +42,7 @@ module Inspec
42
42
  @__rule_id = id
43
43
  @__profile_id = profile_id
44
44
  @__checks = []
45
- @__skip_rule = nil
45
+ @__skip_rule = {}
46
46
  @__merge_count = 0
47
47
  @__merge_changes = []
48
48
  @__skip_only_if_eval = opts[:skip_only_if_eval]
@@ -118,11 +118,12 @@ module Inspec
118
118
  #
119
119
  # @param [Type] &block returns true if tests are added, false otherwise
120
120
  # @return [nil]
121
- def only_if
121
+ def only_if(message = nil)
122
122
  return unless block_given?
123
123
  return if @__skip_only_if_eval == true
124
124
 
125
- @__skip_rule ||= !yield
125
+ @__skip_rule[:result] ||= !yield
126
+ @__skip_rule[:message] = message
126
127
  end
127
128
 
128
129
  # Describe will add one or more tests to this control. There is 2 ways
@@ -174,8 +175,9 @@ module Inspec
174
175
  rule.instance_variable_get(:@__skip_rule)
175
176
  end
176
177
 
177
- def self.set_skip_rule(rule, value)
178
- rule.instance_variable_set(:@__skip_rule, value)
178
+ def self.set_skip_rule(rule, value, message = nil)
179
+ rule.instance_variable_set(:@__skip_rule,
180
+ { result: value, message: message })
179
181
  end
180
182
 
181
183
  def self.merge_count(rule)
@@ -187,9 +189,13 @@ module Inspec
187
189
  end
188
190
 
189
191
  def self.prepare_checks(rule)
190
- msg = skip_status(rule)
191
- return checks(rule) unless msg
192
- msg = 'Skipped control due to only_if condition.' if msg == true
192
+ skip_check = skip_status(rule)
193
+ return checks(rule) unless skip_check[:result].eql?(true)
194
+ if skip_check[:message]
195
+ msg = "Skipped control due to only_if condition: #{skip_check[:message]}"
196
+ else
197
+ msg = 'Skipped control due to only_if condition.'
198
+ end
193
199
 
194
200
  # TODO: we use os as the carrier here, but should consider
195
201
  # a separate resource to do skipping
@@ -2,8 +2,7 @@
2
2
  # author: Christoph Hartmann
3
3
  # author: Dominik Richter
4
4
 
5
- require 'inspec/plugins'
6
- require 'utils/plugin_registry'
5
+ require 'inspec/plugin/v1'
7
6
 
8
7
  module Inspec
9
8
  SecretsBackend = PluginRegistry.new
@@ -2,8 +2,7 @@
2
2
  # author: Dominik Richter
3
3
  # author: Christoph Hartmann
4
4
 
5
- require 'inspec/plugins'
6
- require 'utils/plugin_registry'
5
+ require 'inspec/plugin/v1'
7
6
 
8
7
  module Inspec
9
8
  # Pre-checking of target resolution. Make sure that SourceReader plugins
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '2.2.61'
7
+ VERSION = '2.2.64'
8
8
  end
@@ -125,7 +125,7 @@ module Inspec::Resources
125
125
  end
126
126
 
127
127
  def read_file(path)
128
- @files_contents[path] ||= read_file_content(path)
128
+ @files_contents[path] ||= read_file_content(path, true)
129
129
  end
130
130
 
131
131
  def conf_dir
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.61
4
+ version: 2.2.64
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-09 00:00:00.000000000 Z
11
+ date: 2018-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train
@@ -313,6 +313,7 @@ files:
313
313
  - docs/dev/control-eval.md
314
314
  - docs/dev/filtertable-internals.md
315
315
  - docs/dev/filtertable-usage.md
316
+ - docs/dev/plugins.md
316
317
  - docs/dsl_inspec.md
317
318
  - docs/dsl_resource.md
318
319
  - docs/glossary.md
@@ -619,12 +620,22 @@ files:
619
620
  - lib/inspec/objects/tag.rb
620
621
  - lib/inspec/objects/test.rb
621
622
  - lib/inspec/objects/value.rb
622
- - lib/inspec/plugins.rb
623
- - lib/inspec/plugins/cli.rb
624
- - lib/inspec/plugins/fetcher.rb
625
- - lib/inspec/plugins/resource.rb
626
- - lib/inspec/plugins/secret.rb
627
- - lib/inspec/plugins/source_reader.rb
623
+ - lib/inspec/plugin/v1.rb
624
+ - lib/inspec/plugin/v1/plugin_types/cli.rb
625
+ - lib/inspec/plugin/v1/plugin_types/fetcher.rb
626
+ - lib/inspec/plugin/v1/plugin_types/resource.rb
627
+ - lib/inspec/plugin/v1/plugin_types/secret.rb
628
+ - lib/inspec/plugin/v1/plugin_types/source_reader.rb
629
+ - lib/inspec/plugin/v1/plugins.rb
630
+ - lib/inspec/plugin/v1/registry.rb
631
+ - lib/inspec/plugin/v2.rb
632
+ - lib/inspec/plugin/v2/activator.rb
633
+ - lib/inspec/plugin/v2/loader.rb
634
+ - lib/inspec/plugin/v2/plugin_base.rb
635
+ - lib/inspec/plugin/v2/plugin_types/cli.rb
636
+ - lib/inspec/plugin/v2/plugin_types/mock.rb
637
+ - lib/inspec/plugin/v2/registry.rb
638
+ - lib/inspec/plugin/v2/status.rb
628
639
  - lib/inspec/polyfill.rb
629
640
  - lib/inspec/profile.rb
630
641
  - lib/inspec/profile_context.rb
@@ -634,7 +645,7 @@ files:
634
645
  - lib/inspec/reporters/base.rb
635
646
  - lib/inspec/reporters/cli.rb
636
647
  - lib/inspec/reporters/json.rb
637
- - lib/inspec/reporters/json_merged.rb
648
+ - lib/inspec/reporters/json_automate.rb
638
649
  - lib/inspec/reporters/json_min.rb
639
650
  - lib/inspec/reporters/junit.rb
640
651
  - lib/inspec/reporters/yaml.rb
@@ -823,7 +834,6 @@ files:
823
834
  - lib/utils/object_traversal.rb
824
835
  - lib/utils/parser.rb
825
836
  - lib/utils/pkey_reader.rb
826
- - lib/utils/plugin_registry.rb
827
837
  - lib/utils/simpleconfig.rb
828
838
  - lib/utils/spdx.rb
829
839
  - lib/utils/spdx.txt