inspec-core 3.0.52 → 3.0.61

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 792ec0ed85e8c7f56b0f1756fe68ee6930cdec48752f160c4dd65e25886ca6be
4
- data.tar.gz: f93bbe45badce127b6b32cdf701f894bcc6ddb213f1eb900295271417e4cd095
3
+ metadata.gz: d789972e56d9edede66194f64a2539d91ceb4d5df71067d22d0f3a8a3a772d95
4
+ data.tar.gz: b0d96149a8d311b9e6926286f7369da1b944eb47d915a33a06fc0dad2aa046ac
5
5
  SHA512:
6
- metadata.gz: 7bec79ae8ede29a52874c4cfbeba2b3a181c4823130a226542ee5070c2733ffd9b24c8167331c48233250f0f5ce6aa40f4b18139979acc7806e9571f980b312c
7
- data.tar.gz: 7d30ee1df7bd9b78406541d1adae0ae2e19f746cf4dbc788f26c912346aab9f8417da54fb37bfbc6b2605be45675e83112e991fd8f0f05be20bcd2cf3bee8585
6
+ metadata.gz: aa9bc42927433d0ba2d7e30f03bce48bf2b79031706e8ab72659d509d78ac7342402d59c3782596e01b86b0ef71c4d227856b85b52d06025ea3295eb829677e6
7
+ data.tar.gz: d66ac71b3d480127c66ae14999c6e66f5b680a5b87e0e8beda105f1c08edb198df987a827553676c30dd3d2289517aa20d92499fed599993920a28349e434d42
data/CHANGELOG.md CHANGED
@@ -1,27 +1,47 @@
1
1
  # Change Log
2
2
  <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
3
- <!-- latest_release 3.0.52 -->
4
- ## [v3.0.52](https://github.com/inspec/inspec/tree/v3.0.52) (2018-11-15)
3
+ <!-- latest_release 3.0.61 -->
4
+ ## [v3.0.61](https://github.com/inspec/inspec/tree/v3.0.61) (2018-11-29)
5
5
 
6
- #### Merged Pull Requests
7
- - Load the compliance plugin when the fetcher is needed [#3609](https://github.com/inspec/inspec/pull/3609) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
6
+ #### New Features
7
+ - Plugin Type: DSLs [#3557](https://github.com/inspec/inspec/pull/3557) ([clintoncwolfe](https://github.com/clintoncwolfe))
8
8
  <!-- latest_release -->
9
9
 
10
- <!-- release_rollup since=3.0.46 -->
11
- ### Changes since 3.0.46 release
10
+ <!-- release_rollup since=3.0.52 -->
11
+ ### Changes since 3.0.52 release
12
12
 
13
- #### Merged Pull Requests
14
- - Load the compliance plugin when the fetcher is needed [#3609](https://github.com/inspec/inspec/pull/3609) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 3.0.52 -->
13
+ #### New Features
14
+ - Plugin Type: DSLs [#3557](https://github.com/inspec/inspec/pull/3557) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 3.0.61 -->
15
15
 
16
16
  #### Bug Fixes
17
- - Adds protection against zipslip vulnerability [#3604](https://github.com/inspec/inspec/pull/3604) ([hdost](https://github.com/hdost)) <!-- 3.0.51 -->
17
+ - package: fix package detection on windows [#3607](https://github.com/inspec/inspec/pull/3607) ([mhackethal](https://github.com/mhackethal)) <!-- 3.0.58 -->
18
+ - www: remove jquery sticky on the sidebar [#3623](https://github.com/inspec/inspec/pull/3623) ([arlimus](https://github.com/arlimus)) <!-- 3.0.57 -->
18
19
 
19
20
  #### Enhancements
20
- - Adding --no-pager to service checks [#3592](https://github.com/inspec/inspec/pull/3592) ([fernandoalex](https://github.com/fernandoalex)) <!-- 3.0.50 -->
21
- - aws_security_group: Query against other security group ids in allow_* matchers [#3576](https://github.com/inspec/inspec/pull/3576) ([j00p34](https://github.com/j00p34)) <!-- 3.0.49 -->
21
+ - filesystem: improve Windows support [#3606](https://github.com/inspec/inspec/pull/3606) ([mhackethal](https://github.com/mhackethal)) <!-- 3.0.56 -->
22
+
23
+ #### Merged Pull Requests
24
+ - Add SQLcl to Oracledb_session Doc [#3632](https://github.com/inspec/inspec/pull/3632) ([ibsavage](https://github.com/ibsavage)) <!-- 3.0.60 -->
25
+ - lc/add-aws-platform-template [#3622](https://github.com/inspec/inspec/pull/3622) ([Caprowni](https://github.com/Caprowni)) <!-- 3.0.59 -->
26
+ - Revert setting RSpec expectation syntax to &#39;should&#39; mode [#3620](https://github.com/inspec/inspec/pull/3620) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 3.0.55 -->
27
+ - Improvements to the functional helper run_inspec_process [#3603](https://github.com/inspec/inspec/pull/3603) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 3.0.54 -->
28
+ - Create a class to handle the plugins.json file [#3575](https://github.com/inspec/inspec/pull/3575) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 3.0.53 -->
22
29
  <!-- release_rollup -->
23
30
 
24
31
  <!-- latest_stable_release -->
32
+ ## [v3.0.52](https://github.com/inspec/inspec/tree/v3.0.52) (2018-11-15)
33
+
34
+ #### Enhancements
35
+ - aws_security_group: Query against other security group ids in allow_* matchers [#3576](https://github.com/inspec/inspec/pull/3576) ([j00p34](https://github.com/j00p34))
36
+ - Adding --no-pager to service checks [#3592](https://github.com/inspec/inspec/pull/3592) ([fernandoalex](https://github.com/fernandoalex))
37
+
38
+ #### Bug Fixes
39
+ - Adds protection against zipslip vulnerability [#3604](https://github.com/inspec/inspec/pull/3604) ([hdost](https://github.com/hdost))
40
+
41
+ #### Merged Pull Requests
42
+ - Load the compliance plugin when the fetcher is needed [#3609](https://github.com/inspec/inspec/pull/3609) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
43
+ <!-- latest_stable_release -->
44
+
25
45
  ## [v3.0.46](https://github.com/inspec/inspec/tree/v3.0.46) (2018-11-08)
26
46
 
27
47
  #### New Features
@@ -42,7 +62,6 @@
42
62
  - Fix functional tests issues with vendoring [#3572](https://github.com/inspec/inspec/pull/3572) ([jquick](https://github.com/jquick))
43
63
  - Fixes (some) ruby warnings related to functional tests [#3561](https://github.com/inspec/inspec/pull/3561) ([TheLonelyGhost](https://github.com/TheLonelyGhost))
44
64
  - Fixes broken link in documentation [#3588](https://github.com/inspec/inspec/pull/3588) ([dmccown](https://github.com/dmccown))
45
- <!-- latest_stable_release -->
46
65
 
47
66
  ## [v3.0.25](https://github.com/inspec/inspec/tree/v3.0.25) (2018-11-01)
48
67
 
@@ -29,6 +29,32 @@ module Inspec
29
29
  define_method :attribute do |name|
30
30
  Inspec::AttributeRegistry.find_attribute(name, profile_id).value
31
31
  end
32
+
33
+ # Support for Control DSL plugins.
34
+ # This is called when an unknown method is encountered
35
+ # within a control block.
36
+ def method_missing(method_name, *arguments, &block)
37
+ # Check to see if there is a control_dsl plugin activator hook with the method name
38
+ registry = Inspec::Plugin::V2::Registry.instance
39
+ hook = registry.find_activators(plugin_type: :control_dsl, activator_name: method_name).first
40
+ if hook
41
+ # OK, load the hook if it hasn't been already. We'll then know a module,
42
+ # which we can then inject into the context
43
+ registry.activate(:control_dsl, method_name) unless hook.activated?
44
+ # Inject the module's methods into the context.
45
+ # implementation_class is the field name, but this is actually a module.
46
+ self.class.include(hook.implementation_class)
47
+ # Now that the module is loaded, it defined one or more methods
48
+ # (presumably the one we were looking for.)
49
+ # We still haven't called it, so do so now.
50
+ send(method_name, *arguments, &block)
51
+ else
52
+ # If we couldn't find a plugin to match, maybe something up above has it,
53
+ # or maybe it is just a unknown method error.
54
+ super
55
+ end
56
+ end
57
+
32
58
  end
33
59
  end
34
60
 
@@ -44,7 +70,6 @@ module Inspec
44
70
  profile_context_owner = profile_context
45
71
  profile_id = profile_context.profile_id
46
72
  rule_class = rule_context(resources_dsl, profile_id)
47
-
48
73
  Class.new do # rubocop:disable Metrics/BlockLength
49
74
  include Inspec::DSL
50
75
  include Inspec::DSL::RequireOverride
data/lib/inspec/dsl.rb CHANGED
@@ -27,6 +27,29 @@ module Inspec::DSL
27
27
  add_resource(target_name, res)
28
28
  end
29
29
 
30
+ # Support for Outer Profile DSL plugins
31
+ # This is called when an unknown method is encountered
32
+ # "bare" in a control file - outside of a control or describe block.
33
+ def method_missing(method_name, *arguments, &block)
34
+ # Check to see if there is a outer_profile_dsl plugin activator hook with the method name
35
+ registry = Inspec::Plugin::V2::Registry.instance
36
+ hook = registry.find_activators(plugin_type: :outer_profile_dsl, activator_name: method_name).first
37
+ if hook
38
+ # OK, load the hook if it hasn't been already. We'll then know a module,
39
+ # which we can then inject into the context
40
+ registry.activate(:outer_profile_dsl, method_name) unless hook.activated?
41
+ # Inject the module's methods into the context
42
+ # implementation_class is the field name, but this is actually a module.
43
+ self.class.include(hook.implementation_class)
44
+ # Now that the module is loaded, it defined one or more methods
45
+ # (presumably the one we were looking for.)
46
+ # We still haven't called it, so do so now.
47
+ send(method_name, *arguments, &block)
48
+ else
49
+ super
50
+ end
51
+ end
52
+
30
53
  def self.load_spec_files_for_profile(bind_context, opts, &block)
31
54
  dependencies = opts[:dependencies]
32
55
  profile_id = opts[:profile_id]
@@ -39,6 +39,34 @@ module Inspec
39
39
  __resource_registry[@name].example(example)
40
40
  end
41
41
 
42
+ # Support for Resource DSL plugins.
43
+ # This is called when an unknown method is encountered
44
+ # within a resource class definition.
45
+ # Even tho this is defined as an instance method, it gets added to
46
+ # Inspec::Plugins::Resource via `extend`, so this is actually a class defintion.
47
+ def method_missing(method_name, *arguments, &block)
48
+ require 'inspec/plugin/v2'
49
+ # Check to see if there is a resource_dsl plugin activator hook with the method name
50
+ registry = Inspec::Plugin::V2::Registry.instance
51
+ hook = registry.find_activators(plugin_type: :resource_dsl, activator_name: method_name).first
52
+ if hook
53
+ # OK, load the hook if it hasn't been already. We'll then know a module,
54
+ # which we can then inject into the resource
55
+ registry.activate(:resource_dsl, method_name) unless hook.activated?
56
+ # Inject the module's methods into the resource as class methods.
57
+ # implementation_class is the field name, but this is actually a module.
58
+ extend(hook.implementation_class)
59
+ # Now that the module is loaded, it defined one or more methods
60
+ # (presumably the one we were looking for.)
61
+ # We still haven't called it, so do so now.
62
+ send(method_name, *arguments, &block)
63
+ else
64
+ # If we couldn't find a plugin to match, maybe something up above has it,
65
+ # or maybe it is just a unknown method error.
66
+ super
67
+ end
68
+ end
69
+
42
70
  def __resource_registry
43
71
  Inspec::Resource.registry
44
72
  end
@@ -24,6 +24,7 @@ module Inspec
24
24
  end
25
25
 
26
26
  require 'inspec/globals'
27
+ require 'inspec/plugin/v2/config_file'
27
28
  require 'inspec/plugin/v2/registry'
28
29
  require 'inspec/plugin/v2/loader'
29
30
  require 'inspec/plugin/v2/plugin_base'
@@ -0,0 +1,148 @@
1
+ require 'json'
2
+
3
+ module Inspec::Plugin::V2
4
+ # Represents the plugin config file on disk.
5
+ class ConfigFile
6
+ include Enumerable
7
+
8
+ attr_reader :path
9
+
10
+ def initialize(path = nil)
11
+ @path = path || self.class.default_path
12
+ @data = blank_structure
13
+
14
+ read_and_validate_file if File.exist?(@path)
15
+ end
16
+
17
+ # Returns the defaut path for a config file.
18
+ # This respects ENV['INSPEC_CONFIG_DIR'].
19
+ def self.default_path
20
+ File.join(Inspec.config_dir, 'plugins.json')
21
+ end
22
+
23
+ # Implement Enumerable. All Enumerable methds act
24
+ # on the plugins list, and yield Hashes that represent
25
+ # an entry.
26
+ def each(&block)
27
+ @data[:plugins].each(&block)
28
+ end
29
+
30
+ # Look for a plugin by name.
31
+ def plugin_by_name(name)
32
+ detect { |entry| entry[:name] == name.to_sym }
33
+ end
34
+
35
+ # Check for a plugin
36
+ def existing_entry?(name)
37
+ !plugin_by_name(name).nil?
38
+ end
39
+
40
+ # Add an entry with full validation.
41
+ def add_entry(proposed_entry)
42
+ unless proposed_entry.keys.all? { |field| field.is_a? Symbol }
43
+ raise Inspec::Plugin::V2::ConfigError, 'All keys to ConfigFile#add_entry must be symbols'
44
+ end
45
+
46
+ validate_entry(proposed_entry)
47
+
48
+ if existing_entry?(proposed_entry[:name])
49
+ raise Inspec::Plugin::V2::ConfigError, "Duplicate plugin name in call to ConfigFile#add_entry: '#{proposed_entry[:name]}'"
50
+ end
51
+
52
+ @data[:plugins] << proposed_entry
53
+ end
54
+
55
+ # Removes an entry specified by plugin name.
56
+ def remove_entry(name)
57
+ unless existing_entry?(name)
58
+ raise Inspec::Plugin::V2::ConfigError, "No such entry with plugin name '#{name}'"
59
+ end
60
+ @data[:plugins].delete_if { |entry| entry[:name] == name.to_sym }
61
+ end
62
+
63
+ # Save the file to disk as a JSON structure at the path.
64
+ def save
65
+ dir = File.dirname(path)
66
+ FileUtils.mkdir_p(dir)
67
+ File.write(path, JSON.pretty_generate(@data))
68
+ end
69
+
70
+ private
71
+
72
+ def blank_structure
73
+ {
74
+ plugins_config_version: '1.0.0',
75
+ plugins: [],
76
+ }
77
+ end
78
+
79
+ def read_and_validate_file
80
+ @data = JSON.parse(File.read(path), symbolize_names: true)
81
+ validate_file
82
+ rescue JSON::ParserError => e
83
+ raise Inspec::Plugin::V2::ConfigError, "Failed to load plugins JSON configuration from #{path}:\n#{e}"
84
+ end
85
+
86
+ def validate_file # rubocop: disable Metrics/AbcSize
87
+ unless @data[:plugins_config_version]
88
+ raise Inspec::Plugin::V2::ConfigError, "Missing 'plugins_config_version' entry at #{path} - currently support versions: 1.0.0"
89
+ end
90
+
91
+ unless @data[:plugins_config_version] == '1.0.0'
92
+ raise Inspec::Plugin::V2::ConfigError, "Unsupported plugins.json file version #{@data[:plugins_config_version]} at #{path} - currently support versions: 1.0.0"
93
+ end
94
+
95
+ plugin_entries = @data[:plugins]
96
+ if plugin_entries.nil?
97
+ raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file at #{path} - missing top-level key named 'plugins', whose value should be an array"
98
+ end
99
+
100
+ unless plugin_entries.is_a?(Array)
101
+ raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file at #{path} - top-level key named 'plugins' should be an array"
102
+ end
103
+
104
+ plugin_entries.each_with_index do |plugin_entry, idx|
105
+ begin
106
+ validate_entry(plugin_entry)
107
+ rescue Inspec::Plugin::V2::ConfigError => ex
108
+ # append some context to the message
109
+ raise Inspec::Plugin::V2::ConfigError, 'Malformed plugins.json file - ' + ex.message + " at index #{idx}"
110
+ end
111
+
112
+ # Check for duplicates
113
+ plugin_entries.each_with_index do |other_entry, other_idx|
114
+ next if idx == other_idx
115
+ next unless other_entry.is_a? Hash # We'll catch that invalid entry later
116
+ next if plugin_entry[:name] != other_entry[:name]
117
+ indices = [idx, other_idx].sort
118
+ raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - duplicate plugin entry '#{plugin_entry[:name]}' detected at index #{indices[0]} and #{indices[1]}"
119
+ end
120
+ end
121
+ end
122
+
123
+ def validate_entry(plugin_entry)
124
+ unless plugin_entry.is_a? Hash
125
+ raise Inspec::Plugin::V2::ConfigError, "each 'plugins' entry should be a Hash / JSON object"
126
+ end
127
+
128
+ unless plugin_entry.key? :name
129
+ raise Inspec::Plugin::V2::ConfigError, "'plugins' entry missing 'name' field"
130
+ end
131
+
132
+ # Symbolize the name.
133
+ plugin_entry[:name] = plugin_entry[:name].to_sym
134
+
135
+ if plugin_entry.key? :installation_type
136
+ seen_type = plugin_entry[:installation_type]
137
+ unless [:gem, :path].include? seen_type.to_sym
138
+ raise Inspec::Plugin::V2::ConfigError, "'plugins' entry with unrecognized installation_type (must be one of 'gem' or 'path')"
139
+ end
140
+ plugin_entry[:installation_type] = seen_type.to_sym
141
+
142
+ if plugin_entry[:installation_type] == :path && !plugin_entry.key?(:installation_path)
143
+ raise Inspec::Plugin::V2::ConfigError, "'plugins' entry with a 'path' installation_type missing installation path"
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -24,7 +24,7 @@ module Inspec::Plugin::V2
24
24
 
25
25
  Gem.configuration['verbose'] = false
26
26
 
27
- attr_reader :loader, :registry
27
+ attr_reader :conf_file, :loader, :registry
28
28
  def_delegator :loader, :plugin_gem_path, :gem_path
29
29
  def_delegator :loader, :plugin_conf_file_path
30
30
  def_delegator :loader, :list_managed_gems
@@ -459,45 +459,25 @@ module Inspec::Plugin::V2
459
459
  #===================================================================#
460
460
  # plugins.json Maintenance Methods #
461
461
  #===================================================================#
462
-
463
- # TODO: refactor the plugin.json file to have its own class, which Installer consumes
464
462
  def update_plugin_config_file(plugin_name, opts)
465
- config = update_plugin_config_data(plugin_name, opts)
466
- FileUtils.mkdir_p(Inspec.config_dir)
467
- File.write(plugin_conf_file_path, JSON.pretty_generate(config))
468
- end
469
-
470
- # TODO: refactor the plugin.json file to have its own class, which Installer consumes
471
- def update_plugin_config_data(plugin_name, opts)
472
- config = read_or_init_config_data
473
- config['plugins'].delete_if { |entry| entry['name'] == plugin_name }
474
- return config if opts[:action] == :uninstall
475
-
476
- entry = { 'name' => plugin_name }
477
-
478
- # Parsing by Requirement handles lot of awkward formattoes
479
- entry['version'] = Gem::Requirement.new(opts[:version]).to_s if opts.key?(:version)
480
-
481
- if opts.key?(:path)
482
- entry['installation_type'] = 'path'
483
- entry['installation_path'] = opts[:path]
463
+ # Be careful no to initialize this until just before we write.
464
+ # Under testing, ENV['INSPEC_CONFIG_DIR'] may have changed.
465
+ @conf_file = Inspec::Plugin::V2::ConfigFile.new
466
+
467
+ # Remove, then optionally rebuild, the entry for the plugin being modified.
468
+ conf_file.remove_entry(plugin_name) if conf_file.existing_entry?(plugin_name)
469
+ unless opts[:action] == :uninstall
470
+ entry = { name: plugin_name }
471
+ # Parsing by Requirement handles lot of awkward formattoes
472
+ entry[:version] = Gem::Requirement.new(opts[:version]).to_s if opts.key?(:version)
473
+ if opts.key?(:path)
474
+ entry[:installation_type] = :path
475
+ entry[:installation_path] = opts[:path]
476
+ end
477
+ conf_file.add_entry(entry)
484
478
  end
485
479
 
486
- config['plugins'] << entry
487
- config
488
- end
489
-
490
- # TODO: check for validity
491
- # TODO: refactor the plugin.json file to have its own class, which Installer consumes
492
- def read_or_init_config_data
493
- if File.exist?(plugin_conf_file_path)
494
- JSON.parse(File.read(plugin_conf_file_path))
495
- else
496
- {
497
- 'plugins_config_version' => '1.0.0',
498
- 'plugins' => [],
499
- }
500
- end
480
+ conf_file.save
501
481
  end
502
482
  end
503
483
  end
@@ -1,5 +1,5 @@
1
- require 'json'
2
1
  require 'inspec/log'
2
+ require 'inspec/plugin/v2/config_file'
3
3
 
4
4
  # Add the current directory of the process to the load path
5
5
  $LOAD_PATH.unshift('.') unless $LOAD_PATH.include?('.')
@@ -9,13 +9,13 @@ $LOAD_PATH.unshift(folder) unless $LOAD_PATH.include?('folder')
9
9
 
10
10
  module Inspec::Plugin::V2
11
11
  class Loader
12
- attr_reader :registry, :options
12
+ attr_reader :conf_file, :registry, :options
13
13
 
14
14
  def initialize(options = {})
15
15
  @options = options
16
16
  @registry = Inspec::Plugin::V2::Registry.instance
17
- read_conf_file
18
- unpack_conf_file
17
+ @conf_file = Inspec::Plugin::V2::ConfigFile.new
18
+ read_conf_file_into_registry
19
19
 
20
20
  # Old-style (v0, v1) co-distributed plugins were called 'bundles'
21
21
  # and were located in lib/bundles
@@ -104,27 +104,12 @@ module Inspec::Plugin::V2
104
104
 
105
105
  # OK, activate.
106
106
  if activate_me
107
- activate(:cli_command, act.activator_name)
107
+ registry.activate(:cli_command, act.activator_name)
108
108
  act.implementation_class.register_with_thor
109
109
  end
110
110
  end
111
111
  end
112
112
 
113
- def activate(plugin_type, hook_name)
114
- activator = registry.find_activators(plugin_type: plugin_type, activator_name: hook_name).first
115
- # We want to capture literally any possible exception here, since we are storing them.
116
- # rubocop: disable Lint/RescueException
117
- begin
118
- impl_class = activator.activation_proc.call
119
- activator.activated?(true)
120
- activator.implementation_class = impl_class
121
- rescue Exception => ex
122
- activator.exception = ex
123
- Inspec::Log.error "Could not activate #{activator.plugin_type} hook named '#{activator.activator_name}' for plugin #{plugin_name}"
124
- end
125
- # rubocop: enable Lint/RescueException
126
- end
127
-
128
113
  def plugin_gem_path
129
114
  self.class.plugin_gem_path
130
115
  end
@@ -157,16 +142,6 @@ module Inspec::Plugin::V2
157
142
  self.class.list_managed_gems
158
143
  end
159
144
 
160
- # TODO: refactor the plugin.json file to have its own class, which Loader consumes
161
- def plugin_conf_file_path
162
- self.class.plugin_conf_file_path
163
- end
164
-
165
- # TODO: refactor the plugin.json file to have its own class, which Loader consumes
166
- def self.plugin_conf_file_path
167
- File.join(Inspec.config_dir, 'plugins.json')
168
- end
169
-
170
145
  private
171
146
 
172
147
  # 'Activating' a gem adds it to the load path, so 'require "gemname"' will work.
@@ -271,71 +246,22 @@ module Inspec::Plugin::V2
271
246
  end
272
247
  end
273
248
 
274
- # TODO: DRY up re: Installer read_or_init_config_file
275
- # TODO: refactor the plugin.json file to have its own class, which Loader consumes
276
- def read_conf_file
277
- if File.exist?(plugin_conf_file_path)
278
- @plugin_file_contents = JSON.parse(File.read(plugin_conf_file_path))
279
- else
280
- @plugin_file_contents = {
281
- 'plugins_config_version' => '1.0.0',
282
- 'plugins' => [],
283
- }
284
- end
285
- rescue JSON::ParserError => e
286
- raise Inspec::Plugin::V2::ConfigError, "Failed to load plugins JSON configuration from #{plugin_conf_file_path}:\n#{e}"
287
- end
288
-
289
- # TODO: refactor the plugin.json file to have its own class, which Loader consumes
290
- def unpack_conf_file
291
- validate_conf_file
292
- @plugin_file_contents['plugins'].each do |plugin_json|
249
+ def read_conf_file_into_registry
250
+ conf_file.each do |plugin_entry|
293
251
  status = Inspec::Plugin::V2::Status.new
294
- status.name = plugin_json['name'].to_sym
252
+ status.name = plugin_entry[:name]
295
253
  status.loaded = false
296
- status.installation_type = (plugin_json['installation_type'] || :gem).to_sym
254
+ status.installation_type = (plugin_entry[:installation_type] || :gem)
297
255
  case status.installation_type
298
256
  when :gem
299
257
  status.entry_point = status.name.to_s
300
- status.version = plugin_json['version']
258
+ status.version = plugin_entry[:version]
301
259
  when :path
302
- status.entry_point = plugin_json['installation_path']
260
+ status.entry_point = plugin_entry[:installation_path]
303
261
  end
304
262
 
305
263
  registry[status.name] = status
306
264
  end
307
265
  end
308
-
309
- # TODO: refactor the plugin.json file to have its own class, which Loader consumes
310
- def validate_conf_file
311
- unless @plugin_file_contents['plugins_config_version'] == '1.0.0'
312
- raise Inspec::Plugin::V2::ConfigError, "Unsupported plugins.json file version #{@plugin_file_contents['plugins_config_version']} at #{plugin_conf_file_path} - currently support versions: 1.0.0"
313
- end
314
-
315
- plugin_entries = @plugin_file_contents['plugins']
316
- unless plugin_entries.is_a?(Array)
317
- raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - should have a top-level key named 'plugins', whose value is an array"
318
- end
319
-
320
- plugin_entries.each do |plugin_entry|
321
- unless plugin_entry.is_a? Hash
322
- raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - each 'plugins' entry should be a Hash / JSON object"
323
- end
324
-
325
- unless plugin_entry.key? 'name'
326
- raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - each 'plugins' entry must have a 'name' field"
327
- end
328
-
329
- next unless plugin_entry.key?('installation_type')
330
- unless %w{gem path}.include? plugin_entry['installation_type']
331
- raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - each 'installation_type' must be one of 'gem' or 'path'"
332
- end
333
-
334
- next unless plugin_entry['installation_type'] == 'path'
335
- unless plugin_entry.key?('installation_path')
336
- raise Inspec::Plugin::V2::ConfigError, "Malformed plugins.json file - each 'plugins' entry with a 'path' installation_type must provide an 'installation_path' field"
337
- end
338
- end
339
- end
340
266
  end
341
267
  end
@@ -0,0 +1,11 @@
1
+ # All DSL plugin types are defined here.
2
+
3
+ module Inspec::Plugin::V2::PluginType
4
+ class Dsl < Inspec::Plugin::V2::PluginBase
5
+ register_plugin_type(:outer_profile_dsl)
6
+ register_plugin_type(:control_dsl)
7
+ register_plugin_type(:describe_dsl)
8
+ register_plugin_type(:test_dsl)
9
+ register_plugin_type(:resource_dsl)
10
+ end
11
+ end
@@ -67,6 +67,21 @@ module Inspec::Plugin::V2
67
67
  end
68
68
  end
69
69
 
70
+ def activate(plugin_type, hook_name)
71
+ activator = find_activators(plugin_type: plugin_type, activator_name: hook_name).first
72
+ # We want to capture literally any possible exception here, since we are storing them.
73
+ # rubocop: disable Lint/RescueException
74
+ begin
75
+ impl_class = activator.activation_proc.call
76
+ activator.activated?(true)
77
+ activator.implementation_class = impl_class
78
+ rescue Exception => ex
79
+ activator.exception = ex
80
+ Inspec::Log.error "Could not activate #{activator.plugin_type} hook named '#{activator.activator_name}' for plugin #{plugin_name}"
81
+ end
82
+ # rubocop: enable Lint/RescueException
83
+ end
84
+
70
85
  def register(name, status)
71
86
  if known_plugin? name
72
87
  Inspec::Log.debug "PluginLoader: refusing to re-register plugin '#{name}': an existing plugin with that name was loaded via #{registry[name].installation_type}-loading from #{registry[name].entry_point}"
@@ -1,20 +1,84 @@
1
1
  require 'inspec/attribute_registry'
2
- require 'rspec/core'
2
+ require 'inspec/plugin/v2'
3
3
  require 'rspec/core/example_group'
4
4
 
5
- # Setup RSpec to allow use of `should` syntax without warnings
6
- RSpec.configure do |config|
7
- config.expect_with(:rspec) do |rspec_expectations_config|
8
- rspec_expectations_config.syntax = :should
5
+ # Any additions to RSpec::Core::ExampleGroup (the RSpec class behind describe blocks) should go here.
6
+
7
+ module Inspec
8
+ # This module exists to intercept the method_missing *class* method on RSpec::Core::ExampleGroup
9
+ # and is part of support for DSL plugintypes
10
+ module DescribeDslLazyLoader
11
+ # Support for Describe DSL plugins
12
+ def method_missing(method_name, *arguments, &block)
13
+ # Check to see if there is a describe_dsl plugin activator hook with the method name
14
+ registry = Inspec::Plugin::V2::Registry.instance
15
+ hook = registry.find_activators(plugin_type: :describe_dsl, activator_name: method_name).first
16
+
17
+ if hook
18
+ # OK, load the hook if it hasn't been already. We'll then know a module,
19
+ # which we can then inject into the context
20
+ registry.activate(:describe_dsl, method_name) unless hook.activated?
21
+
22
+ # Inject the module's methods into the example group contexts.
23
+ # implementation_class is the field name, but this is actually a module.
24
+ # RSpec works by having these helper methods defined as class methods
25
+ # (see the definition of `let` as an example)
26
+ # So, we use extend to inject the new DSL methods.
27
+ RSpec::Core::ExampleGroup.extend(hook.implementation_class)
28
+
29
+ # We still haven't called the method we were looking for, so do so now.
30
+ send(method_name, *arguments, &block)
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
36
+
37
+ # This module exists to intercept the method_missing *instance* method on RSpec::Core::ExampleGroup
38
+ # and is part of support for DSL plugintypes
39
+ module TestDslLazyLoader
40
+ # Support for test DSL plugins
41
+ def method_missing(method_name, *arguments, &block)
42
+ # Check to see if there is a test_dsl plugin activator hook with the method name
43
+ registry = Inspec::Plugin::V2::Registry.instance
44
+ hook = registry.find_activators(plugin_type: :test_dsl, activator_name: method_name).first
45
+
46
+ if hook
47
+ # OK, load the hook if it hasn't been already. We'll then know a module,
48
+ # which we can then inject into the context
49
+ registry.activate(:test_dsl, method_name) unless hook.activated?
50
+
51
+ # Inject the module's methods into the example group contexts.
52
+ # implementation_class is the field name, but this is actually a module.
53
+ # RSpec works by having these helper methods defined as instance methods.
54
+ # So, we use include to inject the new DSL methods.
55
+ RSpec::Core::ExampleGroup.include(hook.implementation_class)
56
+
57
+ # We still haven't called the method we were looking for, so do so now.
58
+ send(method_name, *arguments, &block)
59
+ else
60
+ super
61
+ end
62
+ end
9
63
  end
10
64
  end
11
65
 
12
- # This file allows you to add ExampleGroups to be used in rspec tests
13
- #
14
66
  class RSpec::Core::ExampleGroup
15
67
  # This DSL method allows us to access the values of attributes within InSpec tests
16
68
  def attribute(name)
17
69
  Inspec::AttributeRegistry.find_attribute(name, self.class.metadata[:profile_id]).value
18
70
  end
19
71
  define_example_method :attribute
72
+
73
+ # Here, we have to ensure our method_missing gets called prior
74
+ # to RSpec::Core::ExampleGroup.method_missing (the class method).
75
+ # So, we use prepend.
76
+ # Because it is a class method we're attempting to prepend, we must
77
+ # prepend against the singleton class.
78
+ singleton_class.prepend Inspec::DescribeDslLazyLoader
79
+
80
+ # Here, we have to ensure our method_missing gets called prior
81
+ # to RSpec::Core::ExampleGroup#method_missing (the instance method).
82
+ # So, we use prepend.
83
+ prepend Inspec::TestDslLazyLoader
20
84
  end
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '3.0.52'
7
+ VERSION = '3.0.61'
8
8
  end
@@ -61,4 +61,16 @@ class InitCli < MiniTest::Test
61
61
  assert_includes Dir.entries(profile).join, 'README.md'
62
62
  end
63
63
  end
64
- end
64
+
65
+ def test_generating_inspec_profile_aws
66
+ Dir.mktmpdir do |dir|
67
+ profile = File.join(dir,'test-aws-profile')
68
+ out = run_inspec_process("init profile --platform aws test-aws-profile", prefix: "cd #{dir} &&")
69
+ assert_equal 0, out.exit_status
70
+ assert_includes out.stdout, 'Create new profile at'
71
+ assert_includes out.stdout, profile
72
+ assert_includes Dir.entries(profile).join, 'inspec.yml'
73
+ assert_includes Dir.entries(profile).join, 'README.md'
74
+ end
75
+ end
76
+ end
@@ -2,30 +2,103 @@ module Inspec::Resources
2
2
  class FileSystemResource < Inspec.resource(1)
3
3
  name 'filesystem'
4
4
  supports platform: 'linux'
5
+ supports platform: 'windows'
5
6
  desc 'Use the filesystem InSpec resource to test file system'
6
7
  example "
7
8
  describe filesystem('/') do
8
9
  its('size') { should be >= 32000 }
10
+ its('type') { should eq false }
11
+ end
12
+ describe filesystem('c:') do
13
+ its('size') { should be >= 90 }
14
+ its('type') { should eq 'NTFS' }
9
15
  end
10
16
  "
11
17
  attr_reader :partition
12
18
 
13
19
  def initialize(partition)
14
20
  @partition = partition
21
+ @cache = nil
22
+ # select file system manager
23
+ @fsman = nil
24
+
25
+ os = inspec.os
26
+ if os.linux?
27
+ @fsman = LinuxFileSystemResource.new(inspec)
28
+ elsif os.windows?
29
+ @fsman = WindowsFileSystemResource.new(inspec)
30
+ else
31
+ raise Inspec::Exceptions::ResourceSkipped, 'The `filesystem` resource is not supported on your OS yet.'
32
+ end
33
+ end
34
+
35
+ def info
36
+ return @cache if !@cache.nil?
37
+ return {} if @fsman.nil?
38
+ @cache = @fsman.info(@partition)
39
+ end
40
+
41
+ def to_s
42
+ "FileSystem #{@partition}"
15
43
  end
16
44
 
17
45
  def size
18
- @size ||= begin
19
- cmd = inspec.command("df #{partition} --output=size")
20
- raise Inspec::Exceptions::ResourceFailed, "Unable to get available space for partition #{partition}" if cmd.stdout.nil? || cmd.stdout.empty? || !cmd.exit_status.zero?
46
+ info = @fsman.info(@partition)
47
+ info[:size]
48
+ end
21
49
 
22
- value = cmd.stdout.gsub(/\dK-blocks[\r\n]/, '').strip
23
- value.to_i
24
- end
50
+ def type
51
+ info = @fsman.info(@partition)
52
+ info[:type]
25
53
  end
26
54
 
27
- def to_s
28
- "Filesystem #{partition}"
55
+ def name
56
+ info = @fsman.info(@partition)
57
+ info[:name]
58
+ end
59
+ end
60
+
61
+ class FsManagement
62
+ attr_reader :inspec
63
+ def initialize(inspec)
64
+ @inspec = inspec
65
+ end
66
+ end
67
+
68
+ class LinuxFileSystemResource < FsManagement
69
+ def info(partition)
70
+ cmd = inspec.command("df #{partition} --output=size")
71
+ raise Inspec::Exceptions::ResourceFailed, "Unable to get available space for partition #{partition}" if cmd.stdout.nil? || cmd.stdout.empty? || !cmd.exit_status.zero?
72
+ value = cmd.stdout.gsub(/\dK-blocks[\r\n]/, '').strip
73
+ {
74
+ name: partition,
75
+ size: value.to_i,
76
+ type: false,
77
+ }
78
+ end
79
+ end
80
+
81
+ class WindowsFileSystemResource < FsManagement
82
+ def info(partition)
83
+ cmd = inspec.command <<-EOF.gsub(/^\s*/, '')
84
+ $disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='#{partition}'"
85
+ $disk.Size = $disk.Size / 1GB
86
+ $disk | select -property DeviceID,Size,FileSystem | ConvertTo-Json
87
+ EOF
88
+
89
+ raise Inspec::Exceptions::ResourceSkipped, "Unable to get available space for partition #{partition}" if cmd.stdout == '' || cmd.exit_status.to_i != 0
90
+ begin
91
+ fs = JSON.parse(cmd.stdout)
92
+ rescue JSON::ParserError => e
93
+ raise Inspec::Exceptions::ResourceFailed,
94
+ 'Failed to parse JSON from Powershell. ' \
95
+ "Error: #{e}"
96
+ end
97
+ {
98
+ name: fs['DeviceID'],
99
+ size: fs['Size'].to_i,
100
+ type: fs['FileSystem'],
101
+ }
29
102
  end
30
103
  end
31
104
  end
@@ -288,7 +288,7 @@ module Inspec::Resources
288
288
  # Find the package
289
289
  cmd = inspec.command <<-EOF.gsub(/^\s*/, '')
290
290
  Get-ItemProperty (@("#{search_paths.join('", "')}") | Where-Object { Test-Path $_ }) |
291
- Where-Object { $_.DisplayName -match "^\\s*#{package_name.shellescape}\\s*$" -or $_.PSChildName -match "^\\s*#{package_name.shellescape}\\s*$" } |
291
+ Where-Object { $_.DisplayName -match "^\s*#{package_name.shellescape}\.*" -or $_.PSChildName -match "^\s*#{package_name.shellescape}\.*" } |
292
292
  Select-Object -Property DisplayName,DisplayVersion | ConvertTo-Json
293
293
  EOF
294
294
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.52
4
+ version: 3.0.61
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-11-15 00:00:00.000000000 Z
11
+ date: 2018-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train-core
@@ -377,11 +377,13 @@ files:
377
377
  - lib/inspec/plugin/v1/registry.rb
378
378
  - lib/inspec/plugin/v2.rb
379
379
  - lib/inspec/plugin/v2/activator.rb
380
+ - lib/inspec/plugin/v2/config_file.rb
380
381
  - lib/inspec/plugin/v2/filter.rb
381
382
  - lib/inspec/plugin/v2/installer.rb
382
383
  - lib/inspec/plugin/v2/loader.rb
383
384
  - lib/inspec/plugin/v2/plugin_base.rb
384
385
  - lib/inspec/plugin/v2/plugin_types/cli.rb
386
+ - lib/inspec/plugin/v2/plugin_types/dsl.rb
385
387
  - lib/inspec/plugin/v2/plugin_types/mock.rb
386
388
  - lib/inspec/plugin/v2/registry.rb
387
389
  - lib/inspec/plugin/v2/status.rb