inspec-core 3.0.52 → 3.0.61
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -12
- data/lib/inspec/control_eval_context.rb +26 -1
- data/lib/inspec/dsl.rb +23 -0
- data/lib/inspec/plugin/v1/plugin_types/resource.rb +28 -0
- data/lib/inspec/plugin/v2.rb +1 -0
- data/lib/inspec/plugin/v2/config_file.rb +148 -0
- data/lib/inspec/plugin/v2/installer.rb +17 -37
- data/lib/inspec/plugin/v2/loader.rb +11 -85
- data/lib/inspec/plugin/v2/plugin_types/dsl.rb +11 -0
- data/lib/inspec/plugin/v2/registry.rb +15 -0
- data/lib/inspec/rspec_extensions.rb +71 -7
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-init/test/functional/inspec_init_test.rb +13 -1
- data/lib/resources/filesystem.rb +81 -8
- data/lib/resources/package.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d789972e56d9edede66194f64a2539d91ceb4d5df71067d22d0f3a8a3a772d95
|
4
|
+
data.tar.gz: b0d96149a8d311b9e6926286f7369da1b944eb47d915a33a06fc0dad2aa046ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
4
|
-
## [v3.0.
|
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
|
-
####
|
7
|
-
-
|
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.
|
11
|
-
### Changes since 3.0.
|
10
|
+
<!-- release_rollup since=3.0.52 -->
|
11
|
+
### Changes since 3.0.52 release
|
12
12
|
|
13
|
-
####
|
14
|
-
-
|
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
|
-
-
|
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
|
-
-
|
21
|
-
|
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 'should' 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
|
data/lib/inspec/plugin/v2.rb
CHANGED
@@ -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
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
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
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
275
|
-
|
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 =
|
252
|
+
status.name = plugin_entry[:name]
|
295
253
|
status.loaded = false
|
296
|
-
status.installation_type = (
|
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 =
|
258
|
+
status.version = plugin_entry[:version]
|
301
259
|
when :path
|
302
|
-
status.entry_point =
|
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 '
|
2
|
+
require 'inspec/plugin/v2'
|
3
3
|
require 'rspec/core/example_group'
|
4
4
|
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
data/lib/inspec/version.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/resources/filesystem.rb
CHANGED
@@ -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
|
-
|
19
|
-
|
20
|
-
|
46
|
+
info = @fsman.info(@partition)
|
47
|
+
info[:size]
|
48
|
+
end
|
21
49
|
|
22
|
-
|
23
|
-
|
24
|
-
|
50
|
+
def type
|
51
|
+
info = @fsman.info(@partition)
|
52
|
+
info[:type]
|
25
53
|
end
|
26
54
|
|
27
|
-
def
|
28
|
-
|
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
|
data/lib/resources/package.rb
CHANGED
@@ -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 "
|
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.
|
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-
|
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
|