inspec-core 5.22.72 → 6.6.0
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/Chef-EULA +9 -0
- data/Gemfile +24 -38
- data/etc/features.sig +6 -0
- data/etc/features.yaml +94 -0
- data/inspec-core.gemspec +16 -15
- data/lib/inspec/backend.rb +2 -0
- data/lib/inspec/base_cli.rb +80 -4
- data/lib/inspec/cached_fetcher.rb +24 -3
- data/lib/inspec/cli.rb +292 -235
- data/lib/inspec/config.rb +24 -11
- data/lib/inspec/dependencies/cache.rb +33 -0
- data/lib/inspec/dependencies/dependency_set.rb +2 -2
- data/lib/inspec/dsl.rb +1 -1
- data/lib/inspec/enhanced_outcomes.rb +1 -0
- data/lib/inspec/errors.rb +5 -0
- data/lib/inspec/exceptions.rb +2 -0
- data/lib/inspec/feature/config.rb +75 -0
- data/lib/inspec/feature/runner.rb +26 -0
- data/lib/inspec/feature.rb +34 -0
- data/lib/inspec/fetcher/git.rb +5 -0
- data/lib/inspec/fetcher/url.rb +7 -29
- data/lib/inspec/globals.rb +6 -0
- data/lib/inspec/input_registry.rb +1 -5
- data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +7 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +30 -2
- data/lib/inspec/profile.rb +46 -3
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters.rb +67 -54
- data/lib/inspec/resources/groups.rb +0 -52
- data/lib/inspec/resources/nftables.rb +1 -14
- data/lib/inspec/resources/oracledb_session.rb +3 -9
- data/lib/inspec/resources/postgres_session.rb +5 -9
- data/lib/inspec/resources/sybase_session.rb +2 -11
- data/lib/inspec/resources/virtualization.rb +1 -1
- data/lib/inspec/rule.rb +9 -14
- data/lib/inspec/run_data.rb +7 -5
- data/lib/inspec/runner.rb +35 -6
- data/lib/inspec/runner_rspec.rb +12 -9
- data/lib/inspec/secrets/yaml.rb +9 -3
- data/lib/inspec/shell.rb +10 -0
- data/lib/inspec/ui.rb +4 -0
- data/lib/inspec/utils/licensing_config.rb +9 -0
- data/lib/inspec/utils/profile_ast_helpers.rb +2 -1
- data/lib/inspec/utils/waivers/csv_file_reader.rb +1 -1
- data/lib/inspec/utils/waivers/excel_file_reader.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +68 -27
- data/lib/inspec.rb +2 -1
- data/lib/matchers/matchers.rb +3 -3
- data/lib/plugins/inspec-compliance/README.md +1 -11
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +189 -170
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +10 -3
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +23 -21
- data/lib/plugins/inspec-init/lib/inspec-init/cli_profile.rb +15 -13
- data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +15 -13
- data/lib/plugins/inspec-license/README.md +16 -0
- data/lib/plugins/inspec-license/inspec-license.gemspec +6 -0
- data/lib/plugins/inspec-license/lib/inspec-license/cli.rb +26 -0
- data/lib/plugins/inspec-license/lib/inspec-license.rb +14 -0
- data/lib/plugins/inspec-parallel/README.md +27 -0
- data/lib/plugins/inspec-parallel/inspec-parallel.gemspec +6 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/child_status_reporter.rb +61 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/cli.rb +39 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/command.rb +219 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/runner.rb +265 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/base.rb +24 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/silent.rb +7 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/status.rb +124 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/text.rb +23 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/validator.rb +170 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel.rb +18 -0
- data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +10 -11
- data/lib/plugins/inspec-sign/lib/inspec-sign/cli.rb +11 -4
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +6 -13
- data/lib/source_readers/inspec.rb +1 -1
- metadata +45 -25
@@ -27,33 +27,35 @@ module InspecPlugins
|
|
27
27
|
option :copyright, type: :string, default: nil, desc: "A copyright statement, to be added to LICENSE"
|
28
28
|
|
29
29
|
def plugin(plugin_name)
|
30
|
-
|
31
|
-
|
30
|
+
Inspec.with_feature("inspec-cli-init-plugin") {
|
31
|
+
plugin_type = determine_plugin_type(plugin_name)
|
32
|
+
snake_case = plugin_name.tr("-", "_")
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
# Handle deprecation of option --hook
|
35
|
+
unless options[:hook].nil?
|
36
|
+
Inspec.deprecate "cli_option_hook"
|
37
|
+
options[:activator] = options.delete(:hook)
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
template_vars = {
|
41
|
+
name: plugin_name,
|
42
|
+
plugin_name: plugin_name,
|
43
|
+
snake_case: snake_case,
|
44
|
+
}.merge(plugin_vars_from_opts)
|
44
45
|
|
45
|
-
|
46
|
+
template_path = File.join("plugins", plugin_type + "-plugin-template")
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
render_opts = {
|
49
|
+
templates_path: TEMPLATES_PATH,
|
50
|
+
overwrite: options[:overwrite],
|
51
|
+
file_rename_map: make_rename_map(plugin_type, plugin_name, snake_case),
|
52
|
+
skip_files: make_skip_list(template_vars["activators"].keys),
|
53
|
+
}
|
53
54
|
|
54
|
-
|
55
|
+
renderer = InspecPlugins::Init::Renderer.new(ui, render_opts)
|
55
56
|
|
56
|
-
|
57
|
+
renderer.render_with_values(template_path, plugin_type + " plugin", template_vars)
|
58
|
+
}
|
57
59
|
end
|
58
60
|
|
59
61
|
private
|
@@ -25,22 +25,24 @@ module InspecPlugins
|
|
25
25
|
option :overwrite, type: :boolean, default: false,
|
26
26
|
desc: "Overwrites existing directory"
|
27
27
|
def profile(new_profile_name)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
Inspec.with_feature("inspec-cli-init-profile") {
|
29
|
+
unless valid_profile_platforms.include?(options[:platform])
|
30
|
+
ui.error "Unable to generate profile: No template available for platform '#{options[:platform]}' (expected one of: #{valid_profile_platforms.join(", ")})"
|
31
|
+
ui.exit(:usage_error)
|
32
|
+
end
|
33
|
+
template_path = File.join("profiles", options[:platform])
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
render_opts = {
|
36
|
+
templates_path: TEMPLATES_PATH,
|
37
|
+
overwrite: options[:overwrite],
|
38
|
+
}
|
39
|
+
renderer = InspecPlugins::Init::Renderer.new(ui, render_opts)
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
vars = {
|
42
|
+
name: new_profile_name,
|
43
|
+
}
|
44
|
+
renderer.render_with_values(template_path, "profile", vars)
|
42
45
|
}
|
43
|
-
renderer.render_with_values(template_path, "profile", vars)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -35,21 +35,23 @@ module InspecPlugins
|
|
35
35
|
# + Add --overwrite option
|
36
36
|
|
37
37
|
def resource(resource_name)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
Inspec.with_feature("inspec-cli-init-resource") {
|
39
|
+
resource_vars_from_opts_resource
|
40
|
+
template_vars = {
|
41
|
+
name: options[:path], # This is used for the path prefix
|
42
|
+
resource_name: resource_name,
|
43
|
+
}
|
44
|
+
template_vars.merge!(options)
|
45
|
+
template_path = File.join("resources", template_vars["template"])
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
render_opts = {
|
48
|
+
templates_path: TEMPLATES_PATH,
|
49
|
+
overwrite: options[:overwrite],
|
50
|
+
file_rename_map: make_rename_map_resource(template_vars),
|
51
|
+
}
|
52
|
+
renderer = InspecPlugins::Init::Renderer.new(ui, render_opts)
|
53
|
+
renderer.render_with_values(template_path, "resource", template_vars)
|
50
54
|
}
|
51
|
-
renderer = InspecPlugins::Init::Renderer.new(ui, render_opts)
|
52
|
-
renderer.render_with_values(template_path, "resource", template_vars)
|
53
55
|
end
|
54
56
|
|
55
57
|
private
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# License Plugin
|
2
|
+
|
3
|
+
## license list
|
4
|
+
|
5
|
+
Implements the `inspec license list` CLI command.
|
6
|
+
|
7
|
+
## license add
|
8
|
+
|
9
|
+
Implements the `inspec license add` CLI command.
|
10
|
+
|
11
|
+
### What This Plugin Does
|
12
|
+
|
13
|
+
This plugin consists of the following subcommands:
|
14
|
+
|
15
|
+
1. `add`: helps to add a new license
|
16
|
+
2. `list`: helps to list all the licenses for the current user
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "chef-licensing"
|
2
|
+
module InspecPlugins::License
|
3
|
+
class CLI < Inspec.plugin(2, :cli_command)
|
4
|
+
include Inspec::Dist
|
5
|
+
|
6
|
+
subcommand_desc "license SUBCOMMAND [options]", "Manage #{PRODUCT_NAME} license"
|
7
|
+
desc "list", "List licenses (not applicable to local licensing service)"
|
8
|
+
def list
|
9
|
+
ChefLicensing.list_license_keys_info
|
10
|
+
rescue ChefLicensing::Error => e
|
11
|
+
Inspec::Log.error e.message
|
12
|
+
Inspec::UI.new.exit(Inspec::UI::EXIT_LICENSE_NOT_SET)
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "add", "Add a new license (not applicable to local licensing service)"
|
16
|
+
def add
|
17
|
+
ChefLicensing.add_license
|
18
|
+
rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyAddNotAllowed => e
|
19
|
+
Inspec::Log.error e.message
|
20
|
+
Inspec::UI.new.exit(Inspec::UI::EXIT_LICENSE_NOT_SET)
|
21
|
+
rescue ChefLicensing::Error => e
|
22
|
+
Inspec::Log.error e.message
|
23
|
+
Inspec::UI.new.exit(Inspec::UI::EXIT_LICENSE_NOT_SET)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module InspecPlugins
|
2
|
+
module License
|
3
|
+
class Plugin < ::Inspec.plugin(2)
|
4
|
+
plugin_name :"inspec-license"
|
5
|
+
|
6
|
+
if Inspec::Dist::EXEC_NAME == "inspec"
|
7
|
+
cli_command :license do
|
8
|
+
require_relative "inspec-license/cli"
|
9
|
+
InspecPlugins::License::CLI
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Parallel Plugin
|
2
|
+
|
3
|
+
Plugin to handle parallel InSpec scan operations over multiple targets.
|
4
|
+
|
5
|
+
## parallel cli_command
|
6
|
+
|
7
|
+
Implements the `inspec parallel exec` CLI command.
|
8
|
+
|
9
|
+
## child-status Plugin
|
10
|
+
|
11
|
+
This reporter is an InSpec Streaming Reporter. It is used internally by inspec parallel to provide status updates on child processes.
|
12
|
+
|
13
|
+
### What This Plugin Does
|
14
|
+
|
15
|
+
For each control executed, after it is complete, the plugin emits a line to STDOUT like:
|
16
|
+
```
|
17
|
+
12/P/24/Control Title Here
|
18
|
+
```
|
19
|
+
When the run is complete, the single line 'EOF_MARKER' is emitted.
|
20
|
+
|
21
|
+
Where:
|
22
|
+
|
23
|
+
- 12 is the number of the control (12th seen out of all controls in all profiles)
|
24
|
+
- P indicates that it Passed (Also F = Failed, S = Skipped, E = Errored)
|
25
|
+
- 24 is the total number of controls in the run
|
26
|
+
- "Control Title Here" is the title (or if title is missing, id) of the last executed control
|
27
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module InspecPlugins::Parallelism
|
2
|
+
class StreamingReporter < Inspec.plugin(2, :streaming_reporter)
|
3
|
+
# Registering these methods with RSpec::Core::Formatters class is mandatory
|
4
|
+
RSpec::Core::Formatters.register self, :example_passed, :example_failed, :example_pending, :close
|
5
|
+
|
6
|
+
def initialize(output)
|
7
|
+
@status_mapping = {}
|
8
|
+
@control_counter = 0
|
9
|
+
initialize_streaming_reporter
|
10
|
+
end
|
11
|
+
|
12
|
+
def example_passed(notification)
|
13
|
+
set_example(notification, "passed")
|
14
|
+
end
|
15
|
+
|
16
|
+
def example_failed(notification)
|
17
|
+
set_example(notification, "failed")
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_pending(notification)
|
21
|
+
set_example(notification, "skipped")
|
22
|
+
end
|
23
|
+
|
24
|
+
def close(notification)
|
25
|
+
# HACK: if we've reached the end of the execution, send a special marker, to ease EOF detection on Windows
|
26
|
+
puts "EOF_MARKER"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def set_example(notification, status)
|
32
|
+
control_id = notification.example.metadata[:id]
|
33
|
+
title = notification.example.metadata[:title]
|
34
|
+
set_status_mapping(control_id, status)
|
35
|
+
output_status(control_id, title) if control_ended?(notification, control_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
def output_status(control_id, title)
|
39
|
+
@control_counter += 1
|
40
|
+
stat = @status_mapping[control_id]
|
41
|
+
stat = if stat.include?("failed")
|
42
|
+
"F"
|
43
|
+
else
|
44
|
+
if stat.include?("skipped")
|
45
|
+
"S"
|
46
|
+
else
|
47
|
+
stat.include?("passed") ? "P" : "E"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
display_name = title.gsub(/\n*\s+/, " ").to_s.force_encoding(Encoding::UTF_8) if title
|
51
|
+
display_name = control_id.to_s.lstrip.force_encoding(Encoding::UTF_8) unless title
|
52
|
+
|
53
|
+
puts "#{@control_counter}/#{stat}/#{controls_count}/#{display_name}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_status_mapping(control_id, status)
|
57
|
+
@status_mapping[control_id] ||= []
|
58
|
+
@status_mapping[control_id].push(status)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "command"
|
2
|
+
require "inspec/dist"
|
3
|
+
require "inspec/base_cli"
|
4
|
+
require "inspec/feature"
|
5
|
+
|
6
|
+
module InspecPlugins::Parallelism
|
7
|
+
class CLI < Inspec.plugin(2, :cli_command)
|
8
|
+
include Inspec::Dist
|
9
|
+
|
10
|
+
subcommand_desc "parallel SUBCOMMAND [options]", "Runs #{PRODUCT_NAME} operations parallely"
|
11
|
+
|
12
|
+
desc "exec", "Executes profile parallely"
|
13
|
+
option :option_file, aliases: :o, type: :string, required: true,
|
14
|
+
desc: "File that contains list of option strings"
|
15
|
+
option :dry_run, type: :boolean,
|
16
|
+
desc: "Print commands that will run"
|
17
|
+
option :verbose, type: :boolean,
|
18
|
+
desc: "Prints all thor options on dry run"
|
19
|
+
option :jobs, aliases: :j, type: :numeric,
|
20
|
+
desc: "Number of jobs to run parallely"
|
21
|
+
option :ui, type: :string, default: "status",
|
22
|
+
desc: "Which UI to use: status, text, silent"
|
23
|
+
option :bg, type: :boolean,
|
24
|
+
desc: "Runs parallel processes in background"
|
25
|
+
option :log_path, type: :string,
|
26
|
+
desc: "Path to the runner and error logs"
|
27
|
+
exec_options
|
28
|
+
def exec(default_profile = nil)
|
29
|
+
Inspec.with_feature("inspec-cli-parallel-exec") {
|
30
|
+
parallel_cmd = InspecPlugins::Parallelism::Command.new(options, default_profile)
|
31
|
+
if options[:dry_run]
|
32
|
+
parallel_cmd.dry_run
|
33
|
+
else
|
34
|
+
parallel_cmd.run
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
require_relative "runner"
|
2
|
+
require_relative "validator"
|
3
|
+
require "erb" unless defined?(Erb)
|
4
|
+
|
5
|
+
module InspecPlugins
|
6
|
+
module Parallelism
|
7
|
+
|
8
|
+
class OptionFileNotReadable < RuntimeError
|
9
|
+
end
|
10
|
+
|
11
|
+
class Command
|
12
|
+
attr_accessor :cli_options_to_parallel_cmd, :default_profile, :sub_cmd, :invocations, :run_in_background
|
13
|
+
|
14
|
+
def initialize(cli_options_to_parallel_cmd, default_profile, sub_cmd = "exec")
|
15
|
+
@default_profile = default_profile
|
16
|
+
@cli_options_to_parallel_cmd = cli_options_to_parallel_cmd
|
17
|
+
@sub_cmd = sub_cmd
|
18
|
+
@logger = Inspec::Log
|
19
|
+
@invocations = read_options_file
|
20
|
+
@run_in_background = cli_options_to_parallel_cmd["bg"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
validate_thor_options
|
25
|
+
validate_invocations!
|
26
|
+
runner = Runner.new(invocations, cli_options_to_parallel_cmd, sub_cmd)
|
27
|
+
catch_ctl_c_and_exit(runner) unless run_in_background
|
28
|
+
runner.run
|
29
|
+
end
|
30
|
+
|
31
|
+
def dry_run
|
32
|
+
validate_invocations!
|
33
|
+
dry_run_commands
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def catch_ctl_c_and_exit(runner)
|
39
|
+
puts "Press CTL+C to stop\n"
|
40
|
+
trap("SIGINT") do
|
41
|
+
puts "\n"
|
42
|
+
puts "Shutting down jobs..."
|
43
|
+
if Inspec.locally_windows?
|
44
|
+
runner.kill_child_processes
|
45
|
+
sleep 1
|
46
|
+
puts "Renaming error log files..."
|
47
|
+
runner.rename_error_log_files
|
48
|
+
end
|
49
|
+
exit Inspec::UI::EXIT_TERMINATED_BY_CTL_C
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate_thor_options
|
54
|
+
# only log path validation needed for now
|
55
|
+
validate_log_path
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_log_path
|
59
|
+
error, message = Validator.new(invocations, cli_options_to_parallel_cmd, sub_cmd).validate_log_path
|
60
|
+
if error
|
61
|
+
@logger.error message
|
62
|
+
Inspec::UI.new.exit(:usage_error)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_invocations!
|
67
|
+
# Validation logic stays in Validator class...
|
68
|
+
Validator.new(invocations, cli_options_to_parallel_cmd, sub_cmd).validate
|
69
|
+
# UI logic stays in Command class.
|
70
|
+
valid = true
|
71
|
+
invocations.each do |invocation_data|
|
72
|
+
invocation_data[:validation_errors].each do |error_message|
|
73
|
+
valid = false
|
74
|
+
@logger.error "Line #{invocation_data[:line_no]}: " + error_message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
unless valid
|
78
|
+
@logger.error "Please fix the options to proceed further."
|
79
|
+
Inspec::UI.new.exit(:usage_error)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def dry_run_commands
|
84
|
+
invocations.each do |invocation_data|
|
85
|
+
puts "inspec #{sub_cmd} #{invocation_data[:value]}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
## Utility functions
|
90
|
+
|
91
|
+
def read_options_file
|
92
|
+
opts = []
|
93
|
+
begin
|
94
|
+
content = content_from_file(cli_options_to_parallel_cmd[:option_file])
|
95
|
+
rescue OptionFileNotReadable => e
|
96
|
+
@logger.error "Cannot read options file: #{e.message}"
|
97
|
+
Inspec::UI.new.exit(:usage_error)
|
98
|
+
end
|
99
|
+
content.each.with_index(1) do |str, index|
|
100
|
+
data_hash = { line_no: index }
|
101
|
+
str = ERB.new(str).result_with_hash(pid: "CHILD_PID").strip
|
102
|
+
str_has_comment = str.start_with?("#")
|
103
|
+
next if str.empty? || str_has_comment
|
104
|
+
|
105
|
+
default_options = fetch_default_options(str.split(" ")).lstrip
|
106
|
+
if str.start_with?("-")
|
107
|
+
data_hash[:value] = "#{default_profile} #{str} #{default_options}"
|
108
|
+
else
|
109
|
+
data_hash[:value] = "#{str} #{default_options}"
|
110
|
+
end
|
111
|
+
opts << data_hash
|
112
|
+
end
|
113
|
+
opts
|
114
|
+
end
|
115
|
+
|
116
|
+
def content_from_file(option_file)
|
117
|
+
if File.exist?(option_file)
|
118
|
+
unless [".sh", ".csh", ".ps1"].include? File.extname(option_file)
|
119
|
+
File.readlines(option_file)
|
120
|
+
else
|
121
|
+
if Inspec.locally_windows? && (File.extname(option_file) == ".ps1")
|
122
|
+
begin
|
123
|
+
output = `powershell -File "#{option_file}"`
|
124
|
+
output.split("\n")
|
125
|
+
rescue StandardError => e
|
126
|
+
raise OptionFileNotReadable.new("Error reading powershell file #{option_file}: #{e.message}")
|
127
|
+
end
|
128
|
+
elsif [".sh", ".csh"].include? File.extname(option_file)
|
129
|
+
begin
|
130
|
+
output = `bash "#{option_file}"`
|
131
|
+
output.split("\n")
|
132
|
+
rescue StandardError => e
|
133
|
+
raise OptionFileNotReadable.new("Error reading shell file #{option_file}: #{e.message}")
|
134
|
+
end
|
135
|
+
else
|
136
|
+
raise OptionFileNotReadable.new("Powershell not supported in your system.")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
raise OptionFileNotReadable.new("Option file not found.")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# this must return empty string or default option string which are not part of option file
|
145
|
+
def fetch_default_options(option_line)
|
146
|
+
option_line = option_line.select { |word| word.start_with?("-") }
|
147
|
+
|
148
|
+
# remove prefixes from the options to compare with default options
|
149
|
+
option_line.map! do |option_key|
|
150
|
+
option_key.gsub(options_prefix(option_key), "").gsub("-", "_")
|
151
|
+
end
|
152
|
+
|
153
|
+
default_opts = ""
|
154
|
+
# iterate through the parallel cli default options and append the option and value which are not present in option file
|
155
|
+
parallel_cmd_default_cli_options.each do |cmd|
|
156
|
+
if cmd.is_a? String
|
157
|
+
append_default_value(default_opts, cmd) unless option_line.include?(cmd)
|
158
|
+
elsif cmd.is_a? Array
|
159
|
+
if !option_line.include?(cmd[0]) && !option_line.include?(cmd[1])
|
160
|
+
append_default_value(default_opts, cmd[0])
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
default_opts
|
165
|
+
end
|
166
|
+
|
167
|
+
# returns array of default options of the subcommand
|
168
|
+
def parallel_cmd_default_cli_options
|
169
|
+
sub_cmd_opts = Inspec::InspecCLI.commands[sub_cmd].options
|
170
|
+
parallel_cmd_default_opts = cli_options_to_parallel_cmd.keys & sub_cmd_opts.keys.map(&:to_s)
|
171
|
+
options_to_append = parallel_cmd_default_opts
|
172
|
+
|
173
|
+
if cli_options_to_parallel_cmd["dry_run"] && !cli_options_to_parallel_cmd["verbose"]
|
174
|
+
# to not show thor default options of inspec commands in dry run
|
175
|
+
sub_cmd_opts_with_defaults = fetch_sub_cmd_default_options(sub_cmd_opts)
|
176
|
+
options_to_append -= sub_cmd_opts_with_defaults
|
177
|
+
end
|
178
|
+
|
179
|
+
default_opts_to_append = []
|
180
|
+
|
181
|
+
# append the options and its aliases if available.
|
182
|
+
options_to_append.each do |option_name|
|
183
|
+
opt_alias = sub_cmd_opts[option_name.to_sym].aliases
|
184
|
+
if opt_alias.empty?
|
185
|
+
default_opts_to_append << option_name
|
186
|
+
else
|
187
|
+
default_opts_to_append << [option_name, opt_alias[0].to_s]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
default_opts_to_append
|
191
|
+
end
|
192
|
+
|
193
|
+
def append_default_value(default_opts, command_name)
|
194
|
+
default_value = cli_options_to_parallel_cmd[command_name.to_sym]
|
195
|
+
default_value = default_value.join(" ") if default_value.is_a? Array
|
196
|
+
default_opts << " --#{command_name.gsub("_", "-")} #{default_value}"
|
197
|
+
end
|
198
|
+
|
199
|
+
def options_prefix(option_name)
|
200
|
+
if option_name.start_with?("--")
|
201
|
+
option_name.start_with?("--no-") ? "--no-" : "--"
|
202
|
+
else
|
203
|
+
"-"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def fetch_sub_cmd_default_options(sub_cmd_opts)
|
208
|
+
default_options_to_remove = []
|
209
|
+
sub_cmd_opts_with_defaults = sub_cmd_opts.select { |_, c| !c.default.nil? }.keys.map(&:to_s)
|
210
|
+
sub_cmd_opts_with_defaults.each do |default_opt_name|
|
211
|
+
if sub_cmd_opts[default_opt_name.to_sym].default == cli_options_to_parallel_cmd[default_opt_name]
|
212
|
+
default_options_to_remove << default_opt_name
|
213
|
+
end
|
214
|
+
end
|
215
|
+
default_options_to_remove
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|