inspec-core 5.18.14 → 5.22.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +19 -17
- data/inspec-core.gemspec +22 -22
- data/lib/inspec/base_cli.rb +19 -17
- data/lib/inspec/cli.rb +27 -25
- data/lib/inspec/dependencies/dependency_set.rb +2 -2
- data/lib/inspec/dsl.rb +9 -5
- data/lib/inspec/enhanced_outcomes.rb +19 -0
- data/lib/inspec/env_printer.rb +1 -1
- data/lib/inspec/exceptions.rb +2 -0
- data/lib/inspec/formatters/base.rb +69 -16
- data/lib/inspec/plugin/v2/loader.rb +19 -8
- data/lib/inspec/plugin/v2/plugin_types/reporter.rb +1 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +54 -0
- data/lib/inspec/profile.rb +9 -8
- data/lib/inspec/reporters/base.rb +1 -0
- data/lib/inspec/reporters/cli.rb +94 -3
- data/lib/inspec/reporters/json.rb +3 -1
- data/lib/inspec/reporters/yaml.rb +3 -1
- data/lib/inspec/reporters.rb +2 -1
- data/lib/inspec/resources/file.rb +1 -1
- data/lib/inspec/resources/http.rb +5 -5
- data/lib/inspec/resources/lxc.rb +65 -9
- data/lib/inspec/resources/mongodb_session.rb +5 -0
- data/lib/inspec/resources/nftables.rb +251 -0
- data/lib/inspec/resources/oracledb_session.rb +13 -4
- data/lib/inspec/resources/podman.rb +353 -0
- data/lib/inspec/resources/podman_container.rb +84 -0
- data/lib/inspec/resources/podman_image.rb +108 -0
- data/lib/inspec/resources/podman_network.rb +81 -0
- data/lib/inspec/resources/podman_pod.rb +101 -0
- data/lib/inspec/resources/podman_volume.rb +87 -0
- data/lib/inspec/resources/postgres_session.rb +2 -1
- data/lib/inspec/resources/service.rb +1 -1
- data/lib/inspec/resources.rb +1 -0
- data/lib/inspec/rule.rb +54 -17
- data/lib/inspec/run_data/control.rb +6 -0
- data/lib/inspec/run_data/statistics.rb +8 -2
- data/lib/inspec/runner.rb +18 -8
- data/lib/inspec/runner_rspec.rb +3 -2
- data/lib/inspec/schema/exec_json.rb +78 -2
- data/lib/inspec/schema/output_schema.rb +4 -1
- data/lib/inspec/schema/profile_json.rb +46 -0
- data/lib/inspec/schema.rb +91 -0
- data/lib/inspec/utils/convert.rb +8 -0
- data/lib/inspec/utils/podman.rb +24 -0
- data/lib/inspec/utils/simpleconfig.rb +10 -2
- data/lib/inspec/utils/waivers/csv_file_reader.rb +34 -0
- data/lib/inspec/utils/waivers/excel_file_reader.rb +39 -0
- data/lib/inspec/utils/waivers/json_file_reader.rb +15 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +61 -0
- data/lib/matchers/matchers.rb +15 -2
- data/lib/plugins/inspec-init/templates/profiles/alicloud/README.md +27 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/controls/example.rb +10 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/inputs.yml +1 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/inspec.yml +14 -0
- data/lib/plugins/inspec-reporter-html2/README.md +1 -1
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +7 -1
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +10 -6
- data/lib/plugins/inspec-reporter-html2/templates/default.css +12 -0
- data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +7 -1
- data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +5 -2
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +39 -13
- metadata +26 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 257ccbe0a55a1779ee75f8d6e9e8e0ff612990c123e5cdb10d8cf1e19dbade54
|
4
|
+
data.tar.gz: 820f9a0ec86451f48f65f229befe175cf937648ddb5669df1c8a7c27ebfb234b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8150cdd9aca6ac14ae762dd4b6d09867dab6651f0a0705a28f7256a94683a1fd59b7841bfc69e1a362c253d6c2a847d2e9a03b901dd20118ecc1566b4496a8a9
|
7
|
+
data.tar.gz: a3469cb7fa6786e1d9416e9493fed402ccfb6c8e6ac0a2d40a0029ab63c09b09671cf6729736899ed1a039ca75e36a6a57428deba9a8c5d6dbf0975711a06d13
|
data/Gemfile
CHANGED
@@ -23,9 +23,8 @@ group :omnibus do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
group :test do
|
26
|
-
gem "chefstyle", "~> 2.
|
26
|
+
gem "chefstyle", "~> 2.2.2"
|
27
27
|
gem "concurrent-ruby", "~> 1.0"
|
28
|
-
gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
|
29
28
|
gem "json_schemer", ">= 0.2.1", "< 0.2.19"
|
30
29
|
gem "m"
|
31
30
|
gem "minitest-sprint", "~> 1.0"
|
@@ -35,30 +34,33 @@ group :test do
|
|
35
34
|
gem "pry-byebug"
|
36
35
|
gem "pry", "~> 0.10"
|
37
36
|
gem "rake", ">= 10"
|
38
|
-
gem "ruby-progressbar", "~> 1.8"
|
39
37
|
gem "simplecov", "~> 0.21"
|
40
38
|
gem "simplecov_json_formatter"
|
41
39
|
gem "webmock", "~> 3.0"
|
40
|
+
|
41
|
+
if Gem.ruby_version >= Gem::Version.new("3.0.0")
|
42
|
+
# html-proofer has a dep on io-event, which is ruby-3 only
|
43
|
+
gem "html-proofer", "~> 3.19.4", platforms: :ruby # do not attempt to run proofer on windows. Pinned to 3.19.4 as test is breaking in updated versions.
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
group :deploy do
|
45
48
|
gem "inquirer"
|
46
49
|
end
|
47
50
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
gem "
|
54
|
-
|
55
|
-
|
56
|
-
gem "
|
57
|
-
gem "kitchen-dokken", ">= 2.11"
|
58
|
-
gem "git"
|
51
|
+
group :kitchen do
|
52
|
+
gem "berkshelf"
|
53
|
+
|
54
|
+
# Chef 18 requires ruby 3
|
55
|
+
if Gem.ruby_version >= Gem::Version.new("3.0.0")
|
56
|
+
gem "chef", ">= 17.0"
|
57
|
+
else
|
58
|
+
# Ruby 2.7 presumably - TODO remove this when 2.7 is sunsetted
|
59
|
+
gem "chef", "~> 16.0"
|
59
60
|
end
|
60
|
-
end
|
61
61
|
|
62
|
-
|
63
|
-
gem "
|
62
|
+
gem "test-kitchen", ">= 2.8"
|
63
|
+
gem "kitchen-inspec", ">= 2.0"
|
64
|
+
gem "kitchen-dokken", ">= 2.11"
|
65
|
+
gem "git"
|
64
66
|
end
|
data/inspec-core.gemspec
CHANGED
@@ -18,32 +18,32 @@ Gem::Specification.new do |spec|
|
|
18
18
|
# the gemfile and gemspec are necessary for appbundler so don't remove it
|
19
19
|
spec.files =
|
20
20
|
Dir.glob("{{lib,etc}/**/*,LICENSE,Gemfile,inspec-core.gemspec}")
|
21
|
-
.grep_v(%r{(?<!inspec-init/templates/profiles/)(aws|azure|gcp)})
|
21
|
+
.grep_v(%r{(?<!inspec-init/templates/profiles/)(aws|azure|gcp|alicloud)})
|
22
22
|
.grep_v(%r{lib/plugins/.*/test/})
|
23
23
|
.reject { |f| File.directory?(f) }
|
24
24
|
|
25
25
|
# Implementation dependencies
|
26
|
-
spec.add_dependency "chef-telemetry",
|
27
|
-
spec.add_dependency "license-acceptance",
|
28
|
-
spec.add_dependency "thor",
|
29
|
-
spec.add_dependency "method_source",
|
30
|
-
spec.add_dependency "rubyzip",
|
31
|
-
spec.add_dependency "rspec",
|
32
|
-
spec.add_dependency "rspec-its",
|
33
|
-
spec.add_dependency "pry",
|
34
|
-
spec.add_dependency "hashie",
|
35
|
-
spec.add_dependency "mixlib-log",
|
36
|
-
spec.add_dependency "sslshake",
|
37
|
-
spec.add_dependency "parallel",
|
38
|
-
spec.add_dependency "faraday",
|
39
|
-
spec.add_dependency "
|
40
|
-
spec.add_dependency "tty-table",
|
41
|
-
spec.add_dependency "tty-prompt",
|
42
|
-
spec.add_dependency "tomlrb",
|
43
|
-
spec.add_dependency "addressable",
|
44
|
-
spec.add_dependency "parslet",
|
45
|
-
spec.add_dependency "semverse",
|
46
|
-
spec.add_dependency "multipart-post",
|
26
|
+
spec.add_dependency "chef-telemetry", "~> 1.0", ">= 1.0.8" # 1.0.8+ removes the http dep
|
27
|
+
spec.add_dependency "license-acceptance", ">= 0.2.13", "< 3.0"
|
28
|
+
spec.add_dependency "thor", ">= 0.20", "< 2.0"
|
29
|
+
spec.add_dependency "method_source", ">= 0.8", "< 2.0"
|
30
|
+
spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
|
31
|
+
spec.add_dependency "rspec", ">= 3.9", "<= 3.11"
|
32
|
+
spec.add_dependency "rspec-its", "~> 1.2"
|
33
|
+
spec.add_dependency "pry", "~> 0.13"
|
34
|
+
spec.add_dependency "hashie", ">= 3.4", "< 5.0"
|
35
|
+
spec.add_dependency "mixlib-log", "~> 3.0"
|
36
|
+
spec.add_dependency "sslshake", "~> 1.2"
|
37
|
+
spec.add_dependency "parallel", "~> 1.9"
|
38
|
+
spec.add_dependency "faraday", ">= 1", "< 3"
|
39
|
+
spec.add_dependency "faraday-follow_redirects", "~> 0.3"
|
40
|
+
spec.add_dependency "tty-table", "~> 0.10"
|
41
|
+
spec.add_dependency "tty-prompt", "~> 0.17"
|
42
|
+
spec.add_dependency "tomlrb", ">= 1.2", "< 2.1"
|
43
|
+
spec.add_dependency "addressable", "~> 2.4"
|
44
|
+
spec.add_dependency "parslet", ">= 1.5", "< 2.0" # Pinned < 2.0, see #5389
|
45
|
+
spec.add_dependency "semverse", "~> 3.0"
|
46
|
+
spec.add_dependency "multipart-post", "~> 2.0"
|
47
47
|
|
48
48
|
spec.add_dependency "train-core", "~> 3.10"
|
49
49
|
end
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -100,11 +100,11 @@ module Inspec
|
|
100
100
|
option :ssl, type: :boolean,
|
101
101
|
desc: "Use SSL for transport layer encryption (WinRM)."
|
102
102
|
option :ssl_peer_fingerprint, type: :string,
|
103
|
-
desc: "Specify peer fingerprint
|
103
|
+
desc: "Specify SSL peer fingerprint in place of certificates for SSL authentication (WinRM)."
|
104
104
|
option :self_signed, type: :boolean,
|
105
105
|
desc: "Allow remote scans with self-signed certificates (WinRM)."
|
106
106
|
option :ca_trust_file, type: :string,
|
107
|
-
desc: "Specify CA
|
107
|
+
desc: "Specify CA certificate required for SSL authentication (WinRM)."
|
108
108
|
option :client_cert, type: :string,
|
109
109
|
desc: "Specify client certificate for SSL authentication"
|
110
110
|
option :client_key, type: :string,
|
@@ -121,32 +121,32 @@ module Inspec
|
|
121
121
|
desc: "Read configuration from JSON file (`-` reads from stdin)."
|
122
122
|
option :json_config, type: :string, hide: true
|
123
123
|
option :proxy_command, type: :string,
|
124
|
-
desc: "Specifies the command to use to connect to the server"
|
124
|
+
desc: "Specifies the command to use to connect to the server."
|
125
125
|
option :bastion_host, type: :string,
|
126
|
-
desc: "Specifies the bastion host if applicable"
|
126
|
+
desc: "Specifies the bastion host if applicable."
|
127
127
|
option :bastion_user, type: :string,
|
128
|
-
desc: "Specifies the bastion user if applicable"
|
128
|
+
desc: "Specifies the bastion user if applicable."
|
129
129
|
option :bastion_port, type: :string,
|
130
|
-
desc: "Specifies the bastion port if applicable"
|
130
|
+
desc: "Specifies the bastion port if applicable."
|
131
131
|
option :insecure, type: :boolean, default: false,
|
132
|
-
desc: "Disable SSL verification on select targets"
|
132
|
+
desc: "Disable SSL verification on select targets."
|
133
133
|
option :target_id, type: :string,
|
134
|
-
desc: "Provide
|
134
|
+
desc: "Provide an ID which will be included on reports - deprecated"
|
135
135
|
option :winrm_shell_type, type: :string, default: "powershell",
|
136
|
-
desc: "Specify
|
136
|
+
desc: "Specify which shell type to use (powershell, elevated, or cmd), which defaults to powershell (WinRM)."
|
137
137
|
option :docker_url, type: :string,
|
138
|
-
desc: "Provides path to Docker API endpoint (Docker)"
|
138
|
+
desc: "Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows."
|
139
139
|
option :ssh_config_file, type: :array,
|
140
|
-
desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config"
|
140
|
+
desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config."
|
141
141
|
option :podman_url, type: :string,
|
142
|
-
desc: "Provides path to Podman API endpoint"
|
142
|
+
desc: "Provides the path to the Podman API endpoint. Defaults to unix:///run/user/$UID/podman/podman.sock for rootless container, unix:///run/podman/podman.sock for rootful container (for this you need to execute inspec as root user)."
|
143
143
|
end
|
144
144
|
|
145
145
|
def self.profile_options
|
146
146
|
option :profiles_path, type: :string,
|
147
147
|
desc: "Folder which contains referenced profiles."
|
148
148
|
option :vendor_cache, type: :string,
|
149
|
-
desc: "Use the given path for caching dependencies
|
149
|
+
desc: "Use the given path for caching dependencies, (default: ~/.inspec/cache)."
|
150
150
|
option :auto_install_gems, type: :boolean, default: false,
|
151
151
|
desc: "Auto installs gem dependencies of the profile or resource pack."
|
152
152
|
end
|
@@ -174,7 +174,7 @@ module Inspec
|
|
174
174
|
option :input, type: :array, banner: "name1=value1 name2=value2",
|
175
175
|
desc: "Specify one or more inputs directly on the command line, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
176
176
|
option :input_file, type: :array,
|
177
|
-
desc: "Load one or more input files, a YAML file with values for the profile to use"
|
177
|
+
desc: "Load one or more input files, a YAML file with values for the profile to use."
|
178
178
|
option :waiver_file, type: :array,
|
179
179
|
desc: "Load one or more waiver files."
|
180
180
|
option :attrs, type: :array,
|
@@ -182,14 +182,14 @@ module Inspec
|
|
182
182
|
option :create_lockfile, type: :boolean,
|
183
183
|
desc: "Write out a lockfile based on this execution (unless one already exists)"
|
184
184
|
option :backend_cache, type: :boolean,
|
185
|
-
desc: "Allow caching for backend command output. (default: true)"
|
185
|
+
desc: "Allow caching for backend command output. (default: true)."
|
186
186
|
option :show_progress, type: :boolean,
|
187
187
|
desc: "Show progress while executing tests."
|
188
188
|
option :distinct_exit, type: :boolean, default: true,
|
189
189
|
desc: "Exit with code 101 if any tests fail, and 100 if any are skipped (default). If disabled, exit 0 on skips and 1 for failures."
|
190
190
|
option :silence_deprecations, type: :array,
|
191
191
|
banner: "[all]|[GROUP GROUP...]",
|
192
|
-
desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'."
|
192
|
+
desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for a list of GROUPs or use 'all'."
|
193
193
|
option :diff, type: :boolean, default: true,
|
194
194
|
desc: "Use --no-diff to suppress 'diff' output of failed textual test results."
|
195
195
|
option :sort_results_by, type: :string, default: "file", banner: "--sort-results-by=none|control|file|random",
|
@@ -197,7 +197,7 @@ module Inspec
|
|
197
197
|
option :filter_empty_profiles, type: :boolean, default: false,
|
198
198
|
desc: "Filter empty profiles (profiles without controls) from the report."
|
199
199
|
option :filter_waived_controls, type: :boolean,
|
200
|
-
desc: "Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores `run` setting of waiver file."
|
200
|
+
desc: "Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores the `run` setting of the waiver file."
|
201
201
|
option :retain_waiver_data, type: :boolean,
|
202
202
|
desc: "EXPERIMENTAL: Only works in conjunction with --filter-waived-controls, retains waiver data about controls that were skipped"
|
203
203
|
option :command_timeout, type: :numeric,
|
@@ -205,6 +205,8 @@ module Inspec
|
|
205
205
|
long_desc: "Maximum seconds to allow commands to run during execution. A timed out command is considered an error."
|
206
206
|
option :reporter_include_source, type: :boolean, default: false,
|
207
207
|
desc: "Include full source code of controls in the CLI report"
|
208
|
+
option :enhanced_outcomes, type: :boolean,
|
209
|
+
desc: "Show enhanced outcomes in output"
|
208
210
|
end
|
209
211
|
|
210
212
|
def self.help(*args)
|
data/lib/inspec/cli.rb
CHANGED
@@ -61,9 +61,9 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
61
61
|
require "license_acceptance/cli_flags/thor"
|
62
62
|
include LicenseAcceptance::CLIFlags::Thor
|
63
63
|
|
64
|
-
desc "json PATH", "read all tests in PATH and generate a JSON summary"
|
64
|
+
desc "json PATH", "read all tests in the PATH and generate a JSON summary."
|
65
65
|
option :output, aliases: :o, type: :string,
|
66
|
-
desc: "Save the created profile to a path"
|
66
|
+
desc: "Save the created profile to a path."
|
67
67
|
option :controls, type: :array,
|
68
68
|
desc: "A list of controls to include. Ignore all other tests."
|
69
69
|
option :tags, type: :array,
|
@@ -81,7 +81,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
81
81
|
option :format, type: :string,
|
82
82
|
desc: "The output format to use: json, raw, yaml. If valid format is not provided then it will use the default for the given 'what'."
|
83
83
|
option :output, aliases: :o, type: :string,
|
84
|
-
desc: "Save the created output to a path"
|
84
|
+
desc: "Save the created output to a path."
|
85
85
|
option :controls, type: :array,
|
86
86
|
desc: "For --what=profile, a list of controls to include. Ignore all other tests."
|
87
87
|
option :tags, type: :array,
|
@@ -145,9 +145,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
145
145
|
pretty_handle_exception(e)
|
146
146
|
end
|
147
147
|
|
148
|
-
desc "check PATH", "
|
148
|
+
desc "check PATH", "Verify the metadata in the `inspec.yml` file,\
|
149
|
+
verify that control blocks have the correct fields (title, description, impact),\
|
150
|
+
and define that all controls have visible tests and the controls are not using deprecated InSpec DSL code"
|
149
151
|
option :format, type: :string,
|
150
|
-
desc: "The output format to use
|
152
|
+
desc: "The output format to use. Valid values: `json` and `doc`. Default value: `doc`."
|
151
153
|
option :with_cookstyle, type: :boolean,
|
152
154
|
desc: "Enable or disable cookstyle checks.", default: false
|
153
155
|
profile_options
|
@@ -228,10 +230,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
228
230
|
vendor_deps(path, o)
|
229
231
|
end
|
230
232
|
|
231
|
-
desc "archive PATH", "
|
233
|
+
desc "archive PATH", "Archive a profile to a tar file (default) or zip file."
|
232
234
|
profile_options
|
233
235
|
option :output, aliases: :o, type: :string,
|
234
|
-
desc: "Save the archive to a path"
|
236
|
+
desc: "Save the archive to a path."
|
235
237
|
option :zip, type: :boolean, default: false,
|
236
238
|
desc: "Generates a zip archive."
|
237
239
|
option :tar, type: :boolean, default: false,
|
@@ -275,14 +277,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
275
277
|
pretty_handle_exception(e)
|
276
278
|
end
|
277
279
|
|
278
|
-
desc "exec LOCATIONS", "Run all
|
280
|
+
desc "exec LOCATIONS", "Run all test files at the specified locations."
|
279
281
|
long_desc <<~EOT
|
280
|
-
|
281
|
-
|
282
|
-
Loads the given profile(s) and fetches their dependencies if needed. Then
|
283
|
-
connects to the target and executes any controls contained in the profiles.
|
284
|
-
One or more reporters are used to generate output.
|
285
|
-
|
282
|
+
The subcommand loads the given profiles, fetches their dependencies if needed, then connects to the target and executes any controls in the profiles.
|
283
|
+
One or more reporters are used to generate the output.
|
286
284
|
```
|
287
285
|
Exit codes:
|
288
286
|
0 Normal exit, all tests passed
|
@@ -296,7 +294,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
296
294
|
|
297
295
|
Below are some examples of using `exec` with different test LOCATIONS:
|
298
296
|
|
299
|
-
Automate:
|
297
|
+
Chef Automate:
|
300
298
|
```
|
301
299
|
#{Inspec::Dist::EXEC_NAME} automate login
|
302
300
|
#{Inspec::Dist::EXEC_NAME} exec compliance://username/linux-baseline
|
@@ -306,7 +304,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
306
304
|
#{Inspec::Dist::EXEC_NAME} compliance login
|
307
305
|
```
|
308
306
|
|
309
|
-
Supermarket:
|
307
|
+
Chef Supermarket:
|
310
308
|
```
|
311
309
|
#{Inspec::Dist::EXEC_NAME} exec supermarket://username/linux-baseline
|
312
310
|
```
|
@@ -343,12 +341,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
343
341
|
#{Inspec::Dist::EXEC_NAME} exec https://github.com/dev-sec/linux-baseline.git
|
344
342
|
```
|
345
343
|
|
346
|
-
Web hosted
|
344
|
+
Web hosted file (also supports .zip):
|
347
345
|
```
|
348
346
|
#{Inspec::Dist::EXEC_NAME} exec https://webserver/linux-baseline.tar.gz
|
349
347
|
```
|
350
348
|
|
351
|
-
Web hosted
|
349
|
+
Web hosted file with basic authentication (supports .zip):
|
352
350
|
```
|
353
351
|
#{Inspec::Dist::EXEC_NAME} exec https://username:password@webserver/linux-baseline.tar.gz
|
354
352
|
```
|
@@ -371,7 +369,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
371
369
|
pretty_handle_exception(e)
|
372
370
|
end
|
373
371
|
|
374
|
-
desc "detect", "
|
372
|
+
desc "detect", "detects the target OS."
|
375
373
|
target_options
|
376
374
|
option :format, type: :string
|
377
375
|
def detect
|
@@ -396,7 +394,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
396
394
|
pretty_handle_exception(e)
|
397
395
|
end
|
398
396
|
|
399
|
-
desc "shell", "open an interactive debugging shell"
|
397
|
+
desc "shell", "open an interactive debugging shell."
|
400
398
|
target_options
|
401
399
|
option :command, aliases: :c,
|
402
400
|
desc: "A single command string to run instead of launching the shell"
|
@@ -415,6 +413,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
415
413
|
desc: "Load one or more input files, a YAML file with values for the shell to use"
|
416
414
|
option :input, type: :array, banner: "name1=value1 name2=value2",
|
417
415
|
desc: "Specify one or more inputs directly on the command line to the shell, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
416
|
+
option :enhanced_outcomes, type: :boolean,
|
417
|
+
desc: "Show enhanced outcomes in output"
|
418
418
|
def shell_func
|
419
419
|
o = config
|
420
420
|
deprecate_target_id(config)
|
@@ -453,7 +453,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
453
453
|
pretty_handle_exception(e)
|
454
454
|
end
|
455
455
|
|
456
|
-
desc "env", "
|
456
|
+
desc "env", "Outputs shell-appropriate completion configuration."
|
457
457
|
def env(shell = nil)
|
458
458
|
p = Inspec::EnvPrinter.new(self.class, shell)
|
459
459
|
p.print_and_exit!
|
@@ -461,11 +461,13 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
461
461
|
pretty_handle_exception(e)
|
462
462
|
end
|
463
463
|
|
464
|
+
option :enhanced_outcomes, type: :boolean,
|
465
|
+
desc: "Show enhanced outcomes output"
|
464
466
|
desc "schema NAME", "print the JSON schema", hide: true
|
465
467
|
def schema(name)
|
466
468
|
require "inspec/schema/output_schema"
|
467
|
-
|
468
|
-
puts Inspec::Schema::OutputSchema.json(name)
|
469
|
+
o = config
|
470
|
+
puts Inspec::Schema::OutputSchema.json(name, o)
|
469
471
|
rescue StandardError => e
|
470
472
|
puts e
|
471
473
|
puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
|
@@ -477,7 +479,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
477
479
|
puts Inspec::Telemetry::RunContextProbe.guess_run_context
|
478
480
|
end
|
479
481
|
|
480
|
-
desc "version", "prints the version of this tool"
|
482
|
+
desc "version", "prints the version of this tool."
|
481
483
|
option :format, type: :string
|
482
484
|
def version
|
483
485
|
if config["format"] == "json"
|
@@ -491,7 +493,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
491
493
|
|
492
494
|
desc "clear_cache", "clears the InSpec cache. Useful for debugging."
|
493
495
|
option :vendor_cache, type: :string,
|
494
|
-
desc: "Use the given path for caching dependencies
|
496
|
+
desc: "Use the given path for caching dependencies, (default: `~/.inspec/cache`)."
|
495
497
|
def clear_cache
|
496
498
|
o = config
|
497
499
|
configure_logger(o)
|
@@ -26,7 +26,7 @@ module Inspec
|
|
26
26
|
dep_list = {}
|
27
27
|
dependencies.each do |d|
|
28
28
|
# if depedent profile does not have a source version then only name is used in dependency hash
|
29
|
-
key_name = (d.source_version ? "#{d.name}
|
29
|
+
key_name = (d.source_version.blank? ? "#{d.name}" : "#{d.name}-#{d.source_version}") rescue "#{d.name}"
|
30
30
|
dep_list[key_name] = d
|
31
31
|
end
|
32
32
|
new(cwd, cache, dep_list, backend)
|
@@ -42,7 +42,7 @@ module Inspec
|
|
42
42
|
dep_list = {}
|
43
43
|
dep_tree.each do |d|
|
44
44
|
# if depedent profile does not have a source version then only name is used in dependency hash
|
45
|
-
key_name = (d.source_version ? "#{d.name}
|
45
|
+
key_name = (d.source_version.blank? ? "#{d.name}" : "#{d.name}-#{d.source_version}") rescue "#{d.name}"
|
46
46
|
dep_list[key_name] = d
|
47
47
|
dep_list.merge!(flatten_dep_tree(d.dependencies))
|
48
48
|
end
|
data/lib/inspec/dsl.rb
CHANGED
@@ -91,13 +91,17 @@ module Inspec::DSL
|
|
91
91
|
if profile_version
|
92
92
|
new_profile_id = "#{profile_id}-#{profile_version}"
|
93
93
|
else
|
94
|
-
dependencies.list.
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
dependencies.list.each do |key, value|
|
95
|
+
# 1. Fetching VERSION from a profile dependency name which is in a format NAME-VERSION.
|
96
|
+
# 2. Matching original profile dependency name with profile name used with include or require control DSL.
|
97
|
+
source_version = value.source_version
|
98
|
+
unless source_version.blank?
|
99
|
+
profile_id_key = key.split("-#{source_version}")[0]
|
100
|
+
new_profile_id = key if profile_id_key == profile_id
|
101
|
+
end
|
99
102
|
end
|
100
103
|
end
|
104
|
+
# If dep profile does not contain a source version, key does not contain a version as well. In that case new_profile_id will be always nil and instead profile_id would be used to fetch profile from dependency list.
|
101
105
|
dep_entry = new_profile_id ? dependencies.list[new_profile_id] : dependencies.list[profile_id]
|
102
106
|
|
103
107
|
if dep_entry.nil?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Inspec
|
2
|
+
module EnhancedOutcomes
|
3
|
+
|
4
|
+
def self.determine_status(results, impact)
|
5
|
+
# No-op exception occurs in case of not_applicable_if
|
6
|
+
if results.any? { |r| !r[:exception].nil? && !r[:backtrace].nil? && r[:resource_class] != "noop" }
|
7
|
+
"error"
|
8
|
+
elsif !impact.nil? && impact.to_f == 0.0
|
9
|
+
"not_applicable"
|
10
|
+
elsif results.all? { |r| r[:status] == "skipped" }
|
11
|
+
"not_reviewed"
|
12
|
+
elsif results.any? { |r| r[:status] == "failed" }
|
13
|
+
"failed"
|
14
|
+
else
|
15
|
+
"passed"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/inspec/env_printer.rb
CHANGED
@@ -35,7 +35,7 @@ module Inspec
|
|
35
35
|
private
|
36
36
|
|
37
37
|
def print_completion_for_shell
|
38
|
-
erb = ERB.new(File.read(completion_template_path),
|
38
|
+
erb = ERB.new(File.read(completion_template_path), trim_mode: "-")
|
39
39
|
puts erb.result(TemplateContext.new(@command_class).get_bindings)
|
40
40
|
end
|
41
41
|
|
data/lib/inspec/exceptions.rb
CHANGED
@@ -10,5 +10,7 @@ module Inspec
|
|
10
10
|
class SecretsBackendNotFound < ArgumentError; end
|
11
11
|
class ProfileValidationKeyNotFound < ArgumentError; end
|
12
12
|
class ProfileSigningKeyNotFound < ArgumentError; end
|
13
|
+
class WaiversFileNotReadable < ArgumentError; end
|
14
|
+
class WaiversFileDoesNotExist < ArgumentError; end
|
13
15
|
end
|
14
16
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
require "rspec/core"
|
2
2
|
require "rspec/core/formatters/base_formatter"
|
3
3
|
require "set" unless defined?(Set)
|
4
|
+
require "inspec/enhanced_outcomes"
|
4
5
|
|
5
6
|
module Inspec::Formatters
|
6
7
|
class Base < RSpec::Core::Formatters::BaseFormatter
|
7
8
|
RSpec::Core::Formatters.register self, :close, :dump_summary, :stop
|
8
9
|
|
9
|
-
attr_accessor :backend, :run_data
|
10
|
+
attr_accessor :backend, :run_data, :enhanced_outcomes
|
10
11
|
|
11
12
|
def initialize(output)
|
12
13
|
super(output)
|
@@ -17,6 +18,7 @@ module Inspec::Formatters
|
|
17
18
|
@backend = nil
|
18
19
|
@all_controls_count = nil
|
19
20
|
@control_checks_count_map = {}
|
21
|
+
@enhanced_outcomes = nil
|
20
22
|
end
|
21
23
|
|
22
24
|
# RSpec Override: #dump_summary
|
@@ -50,7 +52,6 @@ module Inspec::Formatters
|
|
50
52
|
else
|
51
53
|
hash[:message] = exception_message(e)
|
52
54
|
end
|
53
|
-
|
54
55
|
next if e.is_a? RSpec::Expectations::ExpectationNotMetError
|
55
56
|
|
56
57
|
hash[:exception] = e.class.name
|
@@ -68,6 +69,8 @@ module Inspec::Formatters
|
|
68
69
|
# flesh out the profiles key with additional profile information
|
69
70
|
run_data[:profiles] = profiles_info
|
70
71
|
|
72
|
+
add_enhanced_outcomes_to_controls if enhanced_outcomes
|
73
|
+
|
71
74
|
# add the platform information for this particular target
|
72
75
|
run_data[:platform] = {
|
73
76
|
name: platform(:name),
|
@@ -110,6 +113,20 @@ module Inspec::Formatters
|
|
110
113
|
|
111
114
|
private
|
112
115
|
|
116
|
+
def add_enhanced_outcomes_to_controls
|
117
|
+
all_unique_controls.each do |control|
|
118
|
+
control[:status] = determine_control_enhanced_outcome(control)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def determine_control_enhanced_outcome(control)
|
123
|
+
if control[:results]
|
124
|
+
Inspec::EnhancedOutcomes.determine_status(control[:results], control[:impact])
|
125
|
+
else
|
126
|
+
"passed"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
113
130
|
def all_unique_controls
|
114
131
|
unique_controls = Set.new
|
115
132
|
run_data[:profiles].each do |profile|
|
@@ -120,25 +137,59 @@ module Inspec::Formatters
|
|
120
137
|
end
|
121
138
|
|
122
139
|
def statistics
|
140
|
+
error = 0
|
141
|
+
not_applicable = 0
|
142
|
+
not_reviewed = 0
|
123
143
|
failed = 0
|
124
|
-
skipped = 0
|
125
144
|
passed = 0
|
145
|
+
skipped = 0
|
146
|
+
enhanced_outcomes_summary = {}
|
147
|
+
if enhanced_outcomes
|
148
|
+
all_unique_controls.each do |control|
|
149
|
+
|
150
|
+
if control[:status] == "error"
|
151
|
+
error += 1
|
152
|
+
elsif control[:status] == "not_applicable"
|
153
|
+
not_applicable += 1
|
154
|
+
elsif control[:status] == "not_reviewed"
|
155
|
+
not_reviewed += 1
|
156
|
+
elsif control[:status] == "failed"
|
157
|
+
failed += 1
|
158
|
+
elsif control[:status] == "passed"
|
159
|
+
passed += 1
|
160
|
+
end
|
126
161
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
if control[:results].any? { |r| r[:status] == "failed" }
|
131
|
-
failed += 1
|
132
|
-
elsif control[:results].any? { |r| r[:status] == "skipped" }
|
133
|
-
skipped += 1
|
134
|
-
else
|
135
|
-
passed += 1
|
136
|
-
end
|
137
|
-
end
|
162
|
+
# added this additionally because stats summary is also used for determining exit code in runner rspec
|
163
|
+
skipped += 1 if control[:results].any? { |r| r[:status] == "skipped" }
|
138
164
|
|
139
|
-
|
165
|
+
end
|
166
|
+
total = error + not_applicable + not_reviewed + failed + passed
|
167
|
+
enhanced_outcomes_summary = {
|
168
|
+
not_applicable: {
|
169
|
+
total: not_applicable,
|
170
|
+
},
|
171
|
+
not_reviewed: {
|
172
|
+
total: not_reviewed,
|
173
|
+
},
|
174
|
+
error: {
|
175
|
+
total: error,
|
176
|
+
},
|
177
|
+
}
|
178
|
+
else
|
179
|
+
all_unique_controls.each do |control|
|
180
|
+
next unless control[:results]
|
140
181
|
|
141
|
-
|
182
|
+
if control[:results].any? { |r| r[:status] == "failed" }
|
183
|
+
failed += 1
|
184
|
+
elsif control[:results].any? { |r| r[:status] == "skipped" }
|
185
|
+
skipped += 1
|
186
|
+
else
|
187
|
+
passed += 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
total = failed + passed + skipped
|
191
|
+
end
|
192
|
+
final_summary = {
|
142
193
|
total: total,
|
143
194
|
passed: {
|
144
195
|
total: passed,
|
@@ -150,6 +201,8 @@ module Inspec::Formatters
|
|
150
201
|
total: failed,
|
151
202
|
},
|
152
203
|
}
|
204
|
+
|
205
|
+
final_summary.merge!(enhanced_outcomes_summary)
|
153
206
|
end
|
154
207
|
|
155
208
|
def exception_message(exception)
|