inspec-core 4.19.2 → 4.21.3
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/Gemfile +2 -1
- data/inspec-core.gemspec +1 -1
- data/lib/inspec/base_cli.rb +5 -2
- data/lib/inspec/cli.rb +6 -5
- data/lib/inspec/config.rb +0 -1
- data/lib/inspec/input_registry.rb +33 -1
- data/lib/inspec/reporters.rb +12 -7
- data/lib/inspec/resources/interface.rb +55 -0
- data/lib/inspec/resources/interfaces.rb +119 -0
- data/lib/inspec/run_data.rb +9 -2
- data/lib/inspec/utils/deprecation/config_file.rb +21 -0
- data/lib/inspec/utils/telemetry/run_context_probe.rb +48 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-reporter-html2/README.md +53 -0
- data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2.rb +18 -0
- data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/reporter.rb +24 -0
- data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/version.rb +8 -0
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +46 -0
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +77 -0
- data/lib/plugins/inspec-reporter-html2/templates/default.css +107 -0
- data/lib/plugins/inspec-reporter-html2/templates/default.js +79 -0
- data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +20 -0
- data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +15 -0
- data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +8 -0
- data/lib/plugins/inspec-reporter-json-min/README.md +10 -0
- data/lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min.rb +13 -0
- data/lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/reporter.rb +50 -0
- data/lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/version.rb +5 -0
- metadata +21 -5
- data/lib/inspec/reporters/json_min.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cefaf29ca67cbd5cdc90ac2bc3a41e990f38f966761d324489d46f8c9a32fdc5
|
4
|
+
data.tar.gz: 933e72e1021a81bffac47c3de56378ea0945682c6ed8f51b0e9751bd42859398
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b4919f052f1f9f7bccdbf4116c2d33fded92f508f6c3057bed3a56a8214c7fa20754e281e3f50f04a5807be4c8693740e2952a0441f96447c44d2bc43059c67
|
7
|
+
data.tar.gz: 1c6b5778d3fe67831b7bd680dd1475f1ca7ddbb1becc24fbbeb1d245e8f6698f2c36d94d5f565564572039a87a94a6f82e9d7ddd50b70475a45c280f43766eca
|
data/Gemfile
CHANGED
@@ -9,7 +9,7 @@ gem "inspec", path: "."
|
|
9
9
|
# in it in order to package the executable. Hence the odd backwards dependency.
|
10
10
|
gem "inspec-bin", path: "./inspec-bin"
|
11
11
|
|
12
|
-
gem "ffi",
|
12
|
+
gem "ffi", ">= 1.9.14", "!= 1.13.0"
|
13
13
|
|
14
14
|
group :omnibus do
|
15
15
|
gem "rb-readline"
|
@@ -31,6 +31,7 @@ group :test do
|
|
31
31
|
gem "m"
|
32
32
|
gem "pry", "~> 0.10"
|
33
33
|
gem "pry-byebug"
|
34
|
+
gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
|
34
35
|
end
|
35
36
|
|
36
37
|
group :integration do
|
data/inspec-core.gemspec
CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
|
|
39
39
|
spec.add_dependency "faraday", ">= 0.9.0"
|
40
40
|
spec.add_dependency "tty-table", "~> 0.10"
|
41
41
|
spec.add_dependency "tty-prompt", "~> 0.17"
|
42
|
-
spec.add_dependency "tomlrb", "~> 1.2"
|
42
|
+
spec.add_dependency "tomlrb", "~> 1.2.0"
|
43
43
|
spec.add_dependency "addressable", "~> 2.4"
|
44
44
|
spec.add_dependency "parslet", "~> 1.5"
|
45
45
|
spec.add_dependency "semverse", "~> 3.0"
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -140,7 +140,7 @@ module Inspec
|
|
140
140
|
option :reporter_backtrace_inclusion, type: :boolean,
|
141
141
|
desc: "Include a code backtrace in report data (default: true)"
|
142
142
|
option :input, type: :array, banner: "name1=value1 name2=value2",
|
143
|
-
desc: "Specify one or more inputs directly on the command line, as --input NAME=VALUE"
|
143
|
+
desc: "Specify one or more inputs directly on the command line, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
144
144
|
option :input_file, type: :array,
|
145
145
|
desc: "Load one or more input files, a YAML file with values for the profile to use"
|
146
146
|
option :waiver_file, type: :array,
|
@@ -155,6 +155,9 @@ module Inspec
|
|
155
155
|
desc: "Show progress while executing tests."
|
156
156
|
option :distinct_exit, type: :boolean, default: true,
|
157
157
|
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."
|
158
|
+
option :silence_deprecations, type: :array,
|
159
|
+
banner: "[all]|[GROUP GROUP...]",
|
160
|
+
desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'."
|
158
161
|
end
|
159
162
|
|
160
163
|
def self.format_platform_info(params: {}, indent: 0, color: 39)
|
@@ -228,7 +231,7 @@ module Inspec
|
|
228
231
|
|
229
232
|
private
|
230
233
|
|
231
|
-
ALL_OF_OUR_REPORTERS = %w{json json-min json-rspec json-automate junit html yaml documentation progress}.freeze # BUT WHY?!?!
|
234
|
+
ALL_OF_OUR_REPORTERS = %w{json json-min json-rspec json-automate junit html html2 yaml documentation progress}.freeze # BUT WHY?!?!
|
232
235
|
|
233
236
|
def suppress_log_output?(opts)
|
234
237
|
return false if opts["reporter"].nil?
|
data/lib/inspec/cli.rb
CHANGED
@@ -375,6 +375,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
375
375
|
puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
|
376
376
|
end
|
377
377
|
|
378
|
+
desc "run_context", "used to test run-context detection", hide: true
|
379
|
+
def run_context
|
380
|
+
require "inspec/utils/telemetry/run_context_probe"
|
381
|
+
puts Inspec::Telemetry::RunContextProbe.guess_run_context
|
382
|
+
end
|
383
|
+
|
378
384
|
desc "version", "prints the version of this tool"
|
379
385
|
option :format, type: :string
|
380
386
|
def version
|
@@ -387,11 +393,6 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
387
393
|
end
|
388
394
|
map %w{-v --version} => :version
|
389
395
|
|
390
|
-
desc "nothing", "does nothing"
|
391
|
-
def nothing
|
392
|
-
puts "you did nothing"
|
393
|
-
end
|
394
|
-
|
395
396
|
private
|
396
397
|
|
397
398
|
def run_command(opts)
|
data/lib/inspec/config.rb
CHANGED
@@ -166,8 +166,9 @@ module Inspec
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
input_name, input_value = pair.split("=")
|
169
|
+
input_value = parse_cli_input_value(input_name, input_value)
|
169
170
|
evt = Inspec::Input::Event.new(
|
170
|
-
value: input_value
|
171
|
+
value: input_value,
|
171
172
|
provider: :cli,
|
172
173
|
priority: 50
|
173
174
|
)
|
@@ -175,6 +176,37 @@ module Inspec
|
|
175
176
|
end
|
176
177
|
end
|
177
178
|
|
179
|
+
# Remove trailing commas, resolve type.
|
180
|
+
def parse_cli_input_value(input_name, given_value)
|
181
|
+
value = given_value.chomp(",") # Trim trailing comma if any
|
182
|
+
case value
|
183
|
+
when /^true|false$/i
|
184
|
+
value = !!(value =~ /true/i)
|
185
|
+
when /^-?\d+$/
|
186
|
+
value = value.to_i
|
187
|
+
when /^-?\d+\.\d+$/
|
188
|
+
value = value.to_f
|
189
|
+
when /^(\[|\{).*(\]|\})$/
|
190
|
+
# Look for complex values and try to parse them.
|
191
|
+
require "yaml"
|
192
|
+
begin
|
193
|
+
value = YAML.load(value)
|
194
|
+
rescue Psych::SyntaxError => yaml_error
|
195
|
+
# It could be that we just tried to run JSON through the YAML parser.
|
196
|
+
require "json"
|
197
|
+
begin
|
198
|
+
value = JSON.parse(value)
|
199
|
+
rescue JSON::ParserError => json_error
|
200
|
+
msg = "Unparseable value '#{value}' for --input #{input_name}.\n"
|
201
|
+
msg += "When treated as YAML, error: #{yaml_error.message}\n"
|
202
|
+
msg += "When treated as JSON, error: #{json_error.message}"
|
203
|
+
Inspec::Log.warn msg
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
value
|
208
|
+
end
|
209
|
+
|
178
210
|
def bind_inputs_from_runner_api(profile_name, input_hash)
|
179
211
|
# TODO: move this into a core plugin
|
180
212
|
|
data/lib/inspec/reporters.rb
CHANGED
@@ -2,7 +2,6 @@ require "inspec/reporters/base"
|
|
2
2
|
require "inspec/reporters/cli"
|
3
3
|
require "inspec/reporters/json"
|
4
4
|
require "inspec/reporters/json_automate"
|
5
|
-
require "inspec/reporters/json_min"
|
6
5
|
require "inspec/reporters/junit"
|
7
6
|
require "inspec/reporters/automate"
|
8
7
|
require "inspec/reporters/yaml"
|
@@ -21,8 +20,6 @@ module Inspec::Reporters
|
|
21
20
|
# right to introduce breaking changes to this reporter at any time.
|
22
21
|
when "json-automate"
|
23
22
|
reporter = Inspec::Reporters::JsonAutomate.new(config)
|
24
|
-
when "json-min"
|
25
|
-
reporter = Inspec::Reporters::JsonMin.new(config)
|
26
23
|
when "junit"
|
27
24
|
reporter = Inspec::Reporters::Junit.new(config)
|
28
25
|
when "automate"
|
@@ -60,15 +57,23 @@ module Inspec::Reporters
|
|
60
57
|
case name
|
61
58
|
when "json"
|
62
59
|
reporter = Inspec::Reporters::Json.new(config)
|
63
|
-
when "json-min"
|
64
|
-
reporter = Inspec::Reporters::JsonMin.new(config)
|
65
60
|
when "json-automate"
|
66
61
|
reporter = Inspec::Reporters::JsonAutomate.new(config)
|
67
62
|
when "yaml"
|
68
63
|
reporter = Inspec::Reporters::Yaml.new(config)
|
69
64
|
else
|
70
|
-
#
|
71
|
-
|
65
|
+
# If we made it here, it might be a plugin
|
66
|
+
begin
|
67
|
+
activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
|
68
|
+
activator.activate!
|
69
|
+
reporter = activator.implementation_class.new(config)
|
70
|
+
unless reporter.respond_to(:report?)
|
71
|
+
return run_data
|
72
|
+
end
|
73
|
+
rescue Inspec::Plugin::V2::LoadError
|
74
|
+
# Must not have been a plugin - just return the run_data
|
75
|
+
return run_data
|
76
|
+
end
|
72
77
|
end
|
73
78
|
|
74
79
|
reporter.report
|
@@ -47,10 +47,18 @@ module Inspec::Resources
|
|
47
47
|
ipv6_addresses && !ipv6_addresses.empty?
|
48
48
|
end
|
49
49
|
|
50
|
+
def ipv4_address
|
51
|
+
ipv4_addresses.first
|
52
|
+
end
|
53
|
+
|
50
54
|
def ipv4_addresses
|
51
55
|
ipv4_cidrs.map { |i| i.split("/")[0] }
|
52
56
|
end
|
53
57
|
|
58
|
+
def ipv6_address
|
59
|
+
ipv6_addresses.first
|
60
|
+
end
|
61
|
+
|
54
62
|
def ipv6_addresses
|
55
63
|
ipv6_cidrs.map { |i| i.split("/")[0] }
|
56
64
|
end
|
@@ -85,6 +93,7 @@ module Inspec::Resources
|
|
85
93
|
@cache ||= begin
|
86
94
|
provider = LinuxInterface.new(inspec) if inspec.os.linux?
|
87
95
|
provider = WindowsInterface.new(inspec) if inspec.os.windows?
|
96
|
+
provider = BsdInterface.new(inspec) if inspec.os.bsd? # includes macOS
|
88
97
|
Hash(provider && provider.interface_info(@iface))
|
89
98
|
end
|
90
99
|
end
|
@@ -98,6 +107,52 @@ module Inspec::Resources
|
|
98
107
|
end
|
99
108
|
end
|
100
109
|
|
110
|
+
class BsdInterface < InterfaceInfo
|
111
|
+
def interface_info(iface)
|
112
|
+
cmd = inspec.command("ifconfig #{iface}")
|
113
|
+
return nil if cmd.exit_status.to_i != 0
|
114
|
+
|
115
|
+
lines = cmd.stdout.split("\n")
|
116
|
+
iface_info = {
|
117
|
+
name: iface,
|
118
|
+
ipv4_addresses: [], # Actually CIDRs
|
119
|
+
ipv6_addresses: [], # are expected to go here
|
120
|
+
}
|
121
|
+
|
122
|
+
iface_info[:up] = lines[0].include?("UP")
|
123
|
+
lines.each do |line|
|
124
|
+
# IPv4 case
|
125
|
+
m = line.match(/^\s+inet\s+((?:\d{1,3}\.){3}\d{1,3})\s+netmask\s+(0x[a-f0-9]{8})/)
|
126
|
+
if m
|
127
|
+
ip = m[1]
|
128
|
+
hex_mask = m[2]
|
129
|
+
cidr = hex_mask.to_i(16).to_s(2).count("1")
|
130
|
+
iface_info[:ipv4_addresses] << "#{ip}/#{cidr}"
|
131
|
+
next
|
132
|
+
end
|
133
|
+
|
134
|
+
# IPv6 case
|
135
|
+
m = line.match(/^\s+inet6\s+([a-f0-9:]+)%#{iface}\s+prefixlen\s+(\d+)/)
|
136
|
+
if m
|
137
|
+
ip = m[1]
|
138
|
+
cidr = m[2]
|
139
|
+
iface_info[:ipv6_addresses] << "#{ip}/#{cidr}"
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
# Speed detect, crummy - can't detect wifi, finds any number in the string
|
144
|
+
# Ethernet autoselect (1000baseT <full-duplex>)
|
145
|
+
m = line.match(/^\s+media:\D+(\d+)/)
|
146
|
+
if m
|
147
|
+
iface_info[:speed] = m[1].to_i
|
148
|
+
next
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
iface_info
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
101
156
|
class LinuxInterface < InterfaceInfo
|
102
157
|
def interface_info(iface)
|
103
158
|
# will return "[mtu]\n1500\n[type]\n1"
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "inspec/utils/filter"
|
2
|
+
require "inspec/resources/command"
|
3
|
+
|
4
|
+
module Inspec::Resources
|
5
|
+
class Interfaces < Inspec.resource(1)
|
6
|
+
name "interfaces"
|
7
|
+
supports platform: "unix"
|
8
|
+
supports platform: "windows"
|
9
|
+
desc "Use the interfaces InSpec audit resource to test properties for multiple network interfaces installed on the system"
|
10
|
+
example <<~EXAMPLE
|
11
|
+
describe interfaces do
|
12
|
+
its('names') { should include 'eth0' }
|
13
|
+
end
|
14
|
+
EXAMPLE
|
15
|
+
|
16
|
+
attr_reader :iface_data
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"Interfaces"
|
20
|
+
end
|
21
|
+
|
22
|
+
filter = FilterTable.create
|
23
|
+
filter.register_column(:names, field: "name")
|
24
|
+
.install_filter_methods_on_resource(self, :scan_interfaces)
|
25
|
+
|
26
|
+
def ipv4_address
|
27
|
+
require "ipaddr"
|
28
|
+
|
29
|
+
# Loop over interface names
|
30
|
+
# Select those that are up and have an ipv4 address
|
31
|
+
interfaces = names.map { |n| inspec.interface(n) }.select do |i|
|
32
|
+
i.ipv4_address? && i.up?
|
33
|
+
end
|
34
|
+
|
35
|
+
addrs = interfaces.map(&:ipv4_addresses).flatten.map { |a| IPAddr.new(a) }
|
36
|
+
|
37
|
+
# Look for progressively "better" IP addresses
|
38
|
+
[
|
39
|
+
# Loopback and private IP ranges
|
40
|
+
IPAddr.new("127.0.0.0/8"),
|
41
|
+
IPAddr.new("192.168.0.0/16"),
|
42
|
+
IPAddr.new("172.16.0.0/12"),
|
43
|
+
IPAddr.new("10.0.0.0/8"),
|
44
|
+
].each do |private_range|
|
45
|
+
filtered_addrs = addrs.reject { |a| private_range.include?(a) }
|
46
|
+
if filtered_addrs.empty?
|
47
|
+
# Everything we had was a private or loopback IP. Return the "best" thing we were left with.
|
48
|
+
return addrs.first.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
addrs = filtered_addrs
|
52
|
+
end
|
53
|
+
addrs.first.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def scan_interfaces
|
59
|
+
@iface_data ||= begin
|
60
|
+
provider = LinuxInterfaceLister.new(inspec) if inspec.os.linux?
|
61
|
+
provider = WindowsInterfaceLister.new(inspec) if inspec.os.windows?
|
62
|
+
provider = BsdInterfaceLister.new(inspec) if inspec.os.bsd? # includes macOS
|
63
|
+
Array(provider && provider.scan_interfaces)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class InterfaceLister
|
68
|
+
attr_reader :inspec
|
69
|
+
def initialize(inspec)
|
70
|
+
@inspec = inspec
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class BsdInterfaceLister < InterfaceLister
|
75
|
+
def scan_interfaces
|
76
|
+
iface_data = []
|
77
|
+
cmd = inspec.command("ifconfig -a")
|
78
|
+
cmd.stdout.split("\n").each do |line|
|
79
|
+
# lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
|
80
|
+
m = line.match(/^(\S+):/)
|
81
|
+
if m
|
82
|
+
iface_data << { "name" => m[1] }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
iface_data
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class LinuxInterfaceLister < InterfaceLister
|
90
|
+
def scan_interfaces
|
91
|
+
iface_data = []
|
92
|
+
cmd = inspec.command("ls /sys/class/net")
|
93
|
+
cmd.stdout.split("\n").each do |iface|
|
94
|
+
iface_data << { "name" => iface }
|
95
|
+
end
|
96
|
+
iface_data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class WindowsInterfaceLister < InterfaceLister
|
101
|
+
def scan_interfaces
|
102
|
+
iface_data = []
|
103
|
+
cmd = inspec.command("Get-NetAdapter | Select-Object -Property Name | ConvertTo-Json")
|
104
|
+
begin
|
105
|
+
adapter_info = JSON.parse(cmd.stdout)
|
106
|
+
# May be a Hash if only one, or Array if multiple - normalize to Array
|
107
|
+
adapter_info = [ adapter_info ] if adapter_info.is_a? Hash
|
108
|
+
rescue JSON::ParserError => _e
|
109
|
+
return nil
|
110
|
+
end
|
111
|
+
adapter_info.each do |info|
|
112
|
+
iface_data << { "name" => info["Name"] }
|
113
|
+
end
|
114
|
+
iface_data
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
data/lib/inspec/run_data.rb
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
|
2
2
|
module Inspec
|
3
3
|
module HashLikeStruct
|
4
|
+
# Only list keys whose value are non-nil
|
4
5
|
def keys
|
5
|
-
members
|
6
|
+
members.reject { |k| self[k].nil? }
|
6
7
|
end
|
7
8
|
|
9
|
+
# Only list non-nil members for backwards compatibility
|
8
10
|
def key?(item)
|
9
|
-
members.include?(item)
|
11
|
+
members.include?(item) && non_nil?(item)
|
12
|
+
end
|
13
|
+
|
14
|
+
# This is provided for clarity - many locations make this test
|
15
|
+
def non_nil?(item)
|
16
|
+
!self[item].nil?
|
10
17
|
end
|
11
18
|
end
|
12
19
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "stringio"
|
2
2
|
require "json"
|
3
3
|
require "inspec/globals"
|
4
|
+
require "inspec/config"
|
4
5
|
|
5
6
|
module Inspec
|
6
7
|
module Deprecation
|
@@ -32,6 +33,7 @@ module Inspec
|
|
32
33
|
@groups = {}
|
33
34
|
@unknown_group_action = :warn
|
34
35
|
validate!
|
36
|
+
silence_deprecations_from_cli
|
35
37
|
end
|
36
38
|
|
37
39
|
private
|
@@ -45,6 +47,25 @@ module Inspec
|
|
45
47
|
File.open(default_path)
|
46
48
|
end
|
47
49
|
|
50
|
+
def silence_deprecations_from_cli
|
51
|
+
# Read --silence-deprecations CLI option
|
52
|
+
cfg = Inspec::Config.cached
|
53
|
+
return unless cfg[:silence_deprecations]
|
54
|
+
|
55
|
+
groups_to_silence = cfg[:silence_deprecations]
|
56
|
+
silence_all = groups_to_silence.include?("all")
|
57
|
+
|
58
|
+
groups.each do |group_name, group|
|
59
|
+
# Only silence things that warn. Don't silence things that exit;
|
60
|
+
# those harsher measures are usually protecting removed code and ignoring
|
61
|
+
# and continuing regardless would be perilous and lead to errors.
|
62
|
+
if %i{warn fail_control}.include?(group.action) &&
|
63
|
+
(silence_all || groups_to_silence.include?(group_name.to_s))
|
64
|
+
group.action = :ignore
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
48
69
|
#====================================================================================================#
|
49
70
|
# Validation
|
50
71
|
#====================================================================================================#
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Inspec
|
2
|
+
module Telemetry
|
3
|
+
# Guesses the run context of InSpec - how were we invoked?
|
4
|
+
# All stack values here are determined experimentally
|
5
|
+
|
6
|
+
class RunContextProbe
|
7
|
+
def self.guess_run_context(stack = nil)
|
8
|
+
stack ||= caller_locations
|
9
|
+
return "test-kitchen" if kitchen?(stack)
|
10
|
+
return "cli" if run_by_thor?(stack)
|
11
|
+
return "audit-cookbook" if audit_cookbook?(stack)
|
12
|
+
|
13
|
+
"unknown"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.run_by_thor?(stack)
|
17
|
+
stack_match(stack: stack, path: "thor/command", label: "run") &&
|
18
|
+
stack_match(stack: stack, path: "thor/invocation", label: "invoke_command")
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.kitchen?(stack)
|
22
|
+
stack_match(stack: stack, path: "kitchen/instance", label: "verify_action") &&
|
23
|
+
stack_match(stack: stack, path: "kitchen/instance", label: "verify")
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.audit_cookbook?(stack)
|
27
|
+
stack_match(stack: stack, path: "chef/handler", label: "run_report_handlers") &&
|
28
|
+
stack_match(stack: stack, path: "handler/audit_report", label: "report")
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.stack_match(stack: [], label: nil, path: nil)
|
32
|
+
return false if stack.nil?
|
33
|
+
|
34
|
+
stack.any? do |frame|
|
35
|
+
if label && path
|
36
|
+
frame.label == label && frame.absolute_path.include?(path)
|
37
|
+
elsif label
|
38
|
+
frame.label == label
|
39
|
+
elsif path
|
40
|
+
frame.absolute_path.include?(path)
|
41
|
+
else
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/inspec/version.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
# inspec-reporter-html2 Plugin
|
2
|
+
|
3
|
+
An "improved" HTML output reporter specifically for Chef InSpec. Unlike the default `html` reporter, which is RSpec-based, this reporter knows about Chef InSpec structures like Controls and Profiles, and includes full metadata such as control tags, etc.
|
4
|
+
|
5
|
+
## To Install This Plugin
|
6
|
+
|
7
|
+
This plugin ships with Chef InSpec and requires no installation.
|
8
|
+
|
9
|
+
It should appear when you run:
|
10
|
+
|
11
|
+
```
|
12
|
+
you@machine $ inspec plugin list
|
13
|
+
```
|
14
|
+
|
15
|
+
## How to use this plugin
|
16
|
+
|
17
|
+
To generate an HTML report using this plugin and save the output to a file named `report.html`, run:
|
18
|
+
|
19
|
+
```
|
20
|
+
you@machine $ inspec exec some_profile --reporter html2:report.html
|
21
|
+
```
|
22
|
+
|
23
|
+
Note the `2` in the reporter name. If you omit it and run `--reporter html` instead, you will run the legacy RSpec HTML reporter.
|
24
|
+
|
25
|
+
## Configuring the Plugin
|
26
|
+
|
27
|
+
The `html2` reporter requires no configuration to function. However, two options--`alternate_css_file` and `alternate_js_file`--are available for customization. The options are set in the JSON-formatted configuration file that Chef InSpec consumes. For details, see [our configuration file documentation](https://www.inspec.io/docs/reference/config/).
|
28
|
+
|
29
|
+
For example:
|
30
|
+
|
31
|
+
```json
|
32
|
+
{
|
33
|
+
"version": "1.2",
|
34
|
+
"plugins": {
|
35
|
+
"inspec-reporter-html2": {
|
36
|
+
"alternate_js_file":"/var/www/js/my-javascript.js",
|
37
|
+
"alternate_css_file":"/var/www/css/my-style.css"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
```
|
42
|
+
|
43
|
+
### alternate\_css\_file
|
44
|
+
|
45
|
+
Specifies the full path to the location of a CSS file that will be read and inlined into the HTML report. The default CSS will not be included.
|
46
|
+
|
47
|
+
### alternate\_js\_file
|
48
|
+
|
49
|
+
Specifies the full path to the location of a JavaScript file that will be read and inlined into the HTML report. The default JavaScript will not be included. The JavaScript file should implement at least a `pageLoaded()` function, which will be called by the `onload` event of the HTML `body` element.
|
50
|
+
|
51
|
+
## Developing This Plugin
|
52
|
+
|
53
|
+
This plugin is part of the Chef InSpec source code. While it has its own tests, the general contribution policy is dictated by the Chef InSpec project at https://github.com/inspec/inspec/blob/master/CONTRIBUTING.md
|
@@ -0,0 +1,18 @@
|
|
1
|
+
libdir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
3
|
+
|
4
|
+
require "inspec-reporter-html2/version"
|
5
|
+
module InspecPlugins
|
6
|
+
module Html2Reporter
|
7
|
+
class Plugin < ::Inspec.plugin(2)
|
8
|
+
# Internal machine name of the plugin. InSpec will use this in errors, etc.
|
9
|
+
plugin_name :'inspec-reporter-html2'
|
10
|
+
|
11
|
+
# Define a new Reporter.
|
12
|
+
reporter :html2 do
|
13
|
+
require "inspec-reporter-html2/reporter"
|
14
|
+
InspecPlugins::Html2Reporter::Reporter
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "inspec/config"
|
3
|
+
|
4
|
+
module InspecPlugins::Html2Reporter
|
5
|
+
class Reporter < Inspec.plugin(2, :reporter)
|
6
|
+
def render
|
7
|
+
template_path = File.expand_path(__FILE__ + "../../../../templates")
|
8
|
+
|
9
|
+
# Read config data from the user's config file. Supports two settings, both of which are absolute filesystem paths:
|
10
|
+
# alternate_css_file - contents will be used instead of default CSS
|
11
|
+
# alternate_js_file - contents will be used instead of default JavaScript
|
12
|
+
cfg = Inspec::Config.cached.fetch_plugin_config("inspec-reporter-html2")
|
13
|
+
js_path = cfg[:alternate_js_file] || (template_path + "/default.js")
|
14
|
+
css_path = cfg[:alternate_css_file] || (template_path + "/default.css")
|
15
|
+
|
16
|
+
template = ERB.new(File.read(template_path + "/body.html.erb"))
|
17
|
+
output(template.result(binding))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.run_data_schema_constraints
|
21
|
+
"~> 0.0"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<!-- saved from url=(0014)about:internet -->
|
3
|
+
<!-- prior comment allows JS to execute on IE when saved as a local file, "MOTW" -->
|
4
|
+
<html lang="en">
|
5
|
+
<head>
|
6
|
+
<title><%= Inspec::Dist::PRODUCT_NAME %> Results</title>
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
8
|
+
<style type="text/css">
|
9
|
+
/* Must inline all CSS files, this is a single-file output that may be airgapped */
|
10
|
+
<%= ERB.new(File.read(css_path), nil, nil, "_css").result(binding) %>
|
11
|
+
</style>
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
/* Must inline all JavaScript files, this is a single-file output that may be airgapped */
|
15
|
+
<%= ERB.new(File.read(js_path), nil, nil, "_js").result(binding) %>
|
16
|
+
// ]]>
|
17
|
+
</script>
|
18
|
+
</head>
|
19
|
+
<body onload="pageLoaded()">
|
20
|
+
<%= ERB.new(File.read(template_path + "/selector.html.erb"), nil, nil, "_select").result(binding) %>
|
21
|
+
<div class="inspec-report">
|
22
|
+
<h1><%= Inspec::Dist::PRODUCT_NAME %> Report</h1>
|
23
|
+
<% run_data.profiles.each do |profile| %>
|
24
|
+
<%= ERB.new(File.read(template_path + "/profile.html.erb"), nil, nil, "_prof").result(binding) %>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<div class="inspec-summary">
|
28
|
+
<table id="platform" class="info">
|
29
|
+
<tr><th colspan=2><h4 id="platform-label">Platform Information</h4></th></tr>
|
30
|
+
<tr class= "name"><th>Name:</th><td><%= run_data.platform.name %></td></tr>
|
31
|
+
<tr class= "release"><th>Release:</th><td><%= run_data.platform.release %></td></tr>
|
32
|
+
<tr class= "target"><th>Target:</th><td><%= run_data.platform.target %></td></tr>
|
33
|
+
</table>
|
34
|
+
<table id="statistics" class="info">
|
35
|
+
<tr><th colspan="2"><h4 id="statistics-label">Control Statistics</h4></th></tr>
|
36
|
+
<tr class= "passed"><th>Passed:</th><td><%= run_data.statistics.controls.passed.total %></td></tr>
|
37
|
+
<tr class= "skipped"><th>Skipped:</th><td><%= run_data.statistics.controls.skipped.total %></td></tr>
|
38
|
+
<tr class= "failed"><th>Failed:</th><td><%= run_data.statistics.controls.failed.total %></td></tr>
|
39
|
+
<tr class= "duration"><th>Duration:</th><td><%= run_data.statistics.duration %> seconds</td></tr>
|
40
|
+
<tr class= "date"><th>Time Finished:</th><td><%= Time.now %></td></tr>
|
41
|
+
</table>
|
42
|
+
<span id="inspec-version"><%= Inspec::Dist::PRODUCT_NAME %> version <%= run_data.version %></span>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</body>
|
46
|
+
</html>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<% slugged_id = control.id.tr(" ", "_") %>
|
2
|
+
<%
|
3
|
+
# Determine status of control
|
4
|
+
status = "passed"
|
5
|
+
if control.results.any? { |r| r.status == "failed" }
|
6
|
+
status = "failed"
|
7
|
+
elsif control.results.any? { |r| r.status == "skipped" }
|
8
|
+
status = "skipped"
|
9
|
+
end
|
10
|
+
%>
|
11
|
+
|
12
|
+
<div class="control control-status-<%= status %>" id="control-<%= slugged_id %>">
|
13
|
+
|
14
|
+
<%
|
15
|
+
# Determine range of impact
|
16
|
+
i = control.impact || 0.0
|
17
|
+
impact_level = "none"
|
18
|
+
if i < 0.3
|
19
|
+
impact_level = "low"
|
20
|
+
elsif i < 0.7
|
21
|
+
impact_level = "medium"
|
22
|
+
else
|
23
|
+
impact_level = "high"
|
24
|
+
end
|
25
|
+
%>
|
26
|
+
|
27
|
+
<h3 class="control-title">Control <code><%= control.id %></code></h3>
|
28
|
+
<table class="control-metadata info" id="control-metadata-<%= slugged_id %>">
|
29
|
+
<tr class="status status-<%= status %>"><th>Status:</th><td><div><%= status.capitalize %></div></td></tr>
|
30
|
+
<% if control.title %><tr class="title"><th>Title:</th><td><%= control.title %></td></tr> <% end %>
|
31
|
+
<% if control.desc %><tr class="desc"><th>Description:</th><td><%= control.desc %></td></tr> <% end %>
|
32
|
+
<% if control.impact %><tr class="impact impact-<%= impact_level %>"><th>Impact:</th><td><%= control.impact %></td></tr> <% end %>
|
33
|
+
<% unless control.tags.empty? %>
|
34
|
+
<tr class="tags">
|
35
|
+
<th>Tags:</th>
|
36
|
+
<td>
|
37
|
+
<table class="tags">
|
38
|
+
<% control.tags.each do |tag_name, tag_text| %>
|
39
|
+
<tr><td><%= tag_name %></td><td><%= tag_text %></td></tr>
|
40
|
+
<% end %>
|
41
|
+
</table>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
<% unless control.refs.empty? %>
|
46
|
+
<tr class="refs">
|
47
|
+
<th>References:</th>
|
48
|
+
<td>
|
49
|
+
<ul>
|
50
|
+
<% control.refs.each do |r| %>
|
51
|
+
<li><a href="<%= r.url %>"><%= r.ref %></a></li>
|
52
|
+
<% end %>
|
53
|
+
</ul>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
<% end %>
|
57
|
+
<tr class="code">
|
58
|
+
<th>Source Code:</th>
|
59
|
+
<td>
|
60
|
+
<input type="button" class="show-source-code" id="show-code-<%= slugged_id %>" value="Show Source"/>
|
61
|
+
<input type="button" class="hide-source-code hidden" id="hide-code-<%= slugged_id %>" value="Hide Source"/>
|
62
|
+
<pre class="source-code hidden" id="source-code-<%= slugged_id %>">
|
63
|
+
<code>
|
64
|
+
<%= control.code %>
|
65
|
+
</code>
|
66
|
+
</pre>
|
67
|
+
</td>
|
68
|
+
</tr>
|
69
|
+
<!-- TODO waiver data -->
|
70
|
+
|
71
|
+
</table>
|
72
|
+
|
73
|
+
<% control.results.each do |result| %>
|
74
|
+
<%= ERB.new(File.read(template_path + "/result.html.erb"), nil, nil, "_rslt").result(binding) %>
|
75
|
+
<% end %>
|
76
|
+
|
77
|
+
</div>
|
@@ -0,0 +1,107 @@
|
|
1
|
+
body {
|
2
|
+
margin: 20px 10% 20px 10%;
|
3
|
+
padding: 0;
|
4
|
+
background: #fff;
|
5
|
+
}
|
6
|
+
h1, h2, h3, h4, h5 {
|
7
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
8
|
+
}
|
9
|
+
h1, h2 {
|
10
|
+
padding: 10px;
|
11
|
+
text-align: center
|
12
|
+
}
|
13
|
+
table.info th, table.info th {
|
14
|
+
padding: 2px;
|
15
|
+
}
|
16
|
+
table.info th {
|
17
|
+
text-align: right;
|
18
|
+
}
|
19
|
+
.hidden {
|
20
|
+
display: none;
|
21
|
+
}
|
22
|
+
pre code {
|
23
|
+
background-color: #eee;
|
24
|
+
border: 1px solid #999;
|
25
|
+
display: block;
|
26
|
+
padding: 20px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.profile, .control, .profile-metadata {
|
30
|
+
border: 1px solid #ccc;
|
31
|
+
padding: 10px;
|
32
|
+
margin: 5px auto;
|
33
|
+
}
|
34
|
+
|
35
|
+
.resource-title {
|
36
|
+
margin-left: 2.5%;
|
37
|
+
}
|
38
|
+
|
39
|
+
.control-title code,
|
40
|
+
.resource-title code {
|
41
|
+
font-size: larger;
|
42
|
+
}
|
43
|
+
.control-metadata .status div,
|
44
|
+
.result-metadata .status div {
|
45
|
+
color: white;
|
46
|
+
font-weight: bold;
|
47
|
+
width: fit-content;
|
48
|
+
padding: 0px 2px;
|
49
|
+
}
|
50
|
+
|
51
|
+
.control-metadata .status-passed div,
|
52
|
+
.result-metadata .status-passed div {
|
53
|
+
background-color: darkgreen;
|
54
|
+
}
|
55
|
+
.control-metadata .status-failed div,
|
56
|
+
.result-metadata .status-failed div {
|
57
|
+
background-color: red;
|
58
|
+
}
|
59
|
+
.control-metadata .status-skipped div,
|
60
|
+
.result-metadata .status-skipped div {
|
61
|
+
background-color: grey;
|
62
|
+
}
|
63
|
+
.result-metadata,
|
64
|
+
.control-metadata {
|
65
|
+
margin: 0 0 0 5%;
|
66
|
+
}
|
67
|
+
|
68
|
+
.selector-panel {
|
69
|
+
position: fixed;
|
70
|
+
z-index: 100;
|
71
|
+
background-color: #ccc;
|
72
|
+
padding: 10px;
|
73
|
+
top: 0;
|
74
|
+
margin-left: -10%;
|
75
|
+
border-bottom-right-radius: 10px;
|
76
|
+
}
|
77
|
+
|
78
|
+
@media print {
|
79
|
+
.selector-panel {
|
80
|
+
visibility: hidden;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
.inspec-summary {
|
85
|
+
border: 1px solid #ccc;
|
86
|
+
padding: 10px;
|
87
|
+
margin: 5px auto;
|
88
|
+
width: fit-content
|
89
|
+
}
|
90
|
+
|
91
|
+
.inspec-summary h4 {
|
92
|
+
margin-bottom: 0px;
|
93
|
+
}
|
94
|
+
|
95
|
+
.inspec-summary #platform, .inspec-summary #statistics {
|
96
|
+
display: inline;
|
97
|
+
}
|
98
|
+
|
99
|
+
#statistics .date td {
|
100
|
+
width: 100px
|
101
|
+
}
|
102
|
+
|
103
|
+
#inspec-version {
|
104
|
+
display: block;
|
105
|
+
text-align: center;
|
106
|
+
font-style: italic;
|
107
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
/* CSS primitives */
|
3
|
+
function addCssClass(id, cls) {
|
4
|
+
document.getElementById(id).className += (" " + cls);
|
5
|
+
}
|
6
|
+
|
7
|
+
function removeCssClass(id, cls) {
|
8
|
+
var el = document.getElementById(id);
|
9
|
+
var classes = el.className.replace(cls,'');
|
10
|
+
el.className = classes;
|
11
|
+
}
|
12
|
+
|
13
|
+
function handleShowSource(evt) {
|
14
|
+
var control_id = evt.srcElement.id.replace("show-code-", "")
|
15
|
+
addCssClass(evt.srcElement.id, "hidden")
|
16
|
+
removeCssClass("hide-code-" + control_id, "hidden")
|
17
|
+
removeCssClass("source-code-" + control_id, "hidden")
|
18
|
+
}
|
19
|
+
|
20
|
+
function handleHideSource(evt) {
|
21
|
+
var control_id = evt.srcElement.id.replace("hide-code-", "")
|
22
|
+
addCssClass(evt.srcElement.id, "hidden")
|
23
|
+
addCssClass("source-code-" + control_id, "hidden")
|
24
|
+
removeCssClass("show-code-" + control_id, "hidden")
|
25
|
+
}
|
26
|
+
|
27
|
+
function handleSelectorChange(evt) {
|
28
|
+
var should_show = evt.srcElement.checked
|
29
|
+
var which_group = evt.srcElement.id.replace("-checkbox","")
|
30
|
+
var controls = document.getElementsByClassName("control-status-" + which_group)
|
31
|
+
var i;
|
32
|
+
if (should_show) {
|
33
|
+
for (i = 0; i < controls.length; i++) {
|
34
|
+
removeCssClass(controls[i].id, "hidden")
|
35
|
+
}
|
36
|
+
} else {
|
37
|
+
for (i = 0; i < controls.length; i++) {
|
38
|
+
addCssClass(controls[i].id, "hidden")
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
function handleChildProfileChange(evt) {
|
44
|
+
var should_show = evt.srcElement.checked
|
45
|
+
var child_profiles = document.getElementsByClassName("child-profile")
|
46
|
+
var i;
|
47
|
+
if (should_show) {
|
48
|
+
for (i = 0; i < child_profiles.length; i++) {
|
49
|
+
removeCssClass(child_profiles[i].id, "hidden")
|
50
|
+
}
|
51
|
+
} else {
|
52
|
+
for (i = 0; i < child_profiles.length; i++) {
|
53
|
+
addCssClass(child_profiles[i].id, "hidden")
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
/* Main entry point */
|
59
|
+
function pageLoaded() {
|
60
|
+
var i;
|
61
|
+
|
62
|
+
// wire up show source links
|
63
|
+
var show_links = document.getElementsByClassName("show-source-code");
|
64
|
+
for (i = 0; i < show_links.length; i++) {
|
65
|
+
show_links[i].onclick = handleShowSource;
|
66
|
+
}
|
67
|
+
// wire up hide source links
|
68
|
+
var hide_links = document.getElementsByClassName("hide-source-code");
|
69
|
+
for (i = 0; i < hide_links.length; i++) {
|
70
|
+
hide_links[i].onclick = handleHideSource;
|
71
|
+
}
|
72
|
+
// wire up selector checkboxes
|
73
|
+
var selectors = document.getElementsByClassName("selector-checkbox");
|
74
|
+
for (i = 0; i < selectors.length; i++) {
|
75
|
+
selectors[i].onchange = handleSelectorChange;
|
76
|
+
}
|
77
|
+
// wire up child profile checkbox
|
78
|
+
document.getElementById("child-profile-checkbox").onchange = handleChildProfileChange;
|
79
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="profile <%= profile.parent_profile ? "child-profile hidden" : "" %>" id="profile-<%= profile.name %>">
|
2
|
+
<% display_name = profile.title || profile.name %>
|
3
|
+
<h2 class="profile_title">Profile <%= display_name %> (<%= profile.name %>)</h2>
|
4
|
+
|
5
|
+
<table class="profile-metadata info" id="profile-metadata-<%= profile.name %>">
|
6
|
+
<tr class="profile-version"><th>Version:</th><td><%= profile.version %></td></tr>
|
7
|
+
<% if profile.summary %>
|
8
|
+
<tr class="profile-summary"><th>Summary:</th><td><%= profile.summary %></td></tr>
|
9
|
+
<% end %>
|
10
|
+
<% if profile.skip_message %>
|
11
|
+
<tr class="profile-skip-message"><th>Skip Message:</th><td><%= profile.skip_message %></td></tr>
|
12
|
+
<% end %>
|
13
|
+
</table>
|
14
|
+
|
15
|
+
<% if profile.status == "loaded" %>
|
16
|
+
<% profile.controls.each do |control| %>
|
17
|
+
<%= ERB.new(File.read(template_path + "/control.html.erb"), nil, nil, "_ctl").result(binding) %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% slugged_id = result.resource_title.to_s.gsub(/\W/, "_") %>
|
2
|
+
<div class="result" id="result-<%= slugged_id %>">
|
3
|
+
<h4 class="resource-title">Resource <code><%= result.resource_title.to_s %></code></h4>
|
4
|
+
<table class="result-metadata info">
|
5
|
+
<tr class="expectation_message"><th>Test:</th><td><code><%= result.expectation_message %></code></td></tr>
|
6
|
+
<tr class="status status-<%= result.status %>"><th>Status:</th><td><div><%= result.status.capitalize %></div></td></tr>
|
7
|
+
<% if result.status == "failed" %>
|
8
|
+
<tr class="fail_message"><th>Failure Message:</th><td><code><%= result.message %></code></td></tr>
|
9
|
+
<% end %>
|
10
|
+
<% if result.status == "skipped" %>
|
11
|
+
<tr class="skip_message"><th>Skip Message:</th><td><%= result.skip_message %></td></tr>
|
12
|
+
<% end %>
|
13
|
+
<tr class="duration"><th>Duration:</th><td><%= result.run_time %> seconds</td></tr>
|
14
|
+
</table>
|
15
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="selector-panel">
|
2
|
+
<p id="selector-instructions">Display controls that are:</p>
|
3
|
+
<input class="selector-checkbox" id="passed-checkbox" type="checkbox" checked="checked"/><label for="passed-checkbox">Passed</label>
|
4
|
+
<input class="selector-checkbox" id="skipped-checkbox" type="checkbox" checked="checked"/><label for="skipped-checkbox">Skipped</label>
|
5
|
+
<input class="selector-checkbox" id="failed-checkbox" type="checkbox" checked="checked"/><label for="failed-checkbox">Failed</label>
|
6
|
+
<p id="selector-instructions">Display profiles that are:</p>
|
7
|
+
<input class="profile-selector-checkbox" id="child-profile-checkbox" type="checkbox" /><label for="child-profile-checkbox">Dependent Profiles</label>
|
8
|
+
</div>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# JSON Minimal Reporter Plugin
|
2
|
+
|
3
|
+
## To Install This Plugin
|
4
|
+
|
5
|
+
This plugin is included with InSpec. There is no need to install it.
|
6
|
+
|
7
|
+
## What This Plugin Does
|
8
|
+
|
9
|
+
This plugin provides the `json-min` reporter, which produces test output in JSON format with less detail than the `json` reporter.
|
10
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative "inspec-reporter-json-min/version"
|
2
|
+
|
3
|
+
module InspecPlugins
|
4
|
+
module JsonMinReporter
|
5
|
+
class Plugin < ::Inspec.plugin(2)
|
6
|
+
plugin_name :"inspec-reporter-json-min"
|
7
|
+
reporter :"json-min" do
|
8
|
+
require_relative "inspec-reporter-json-min/reporter"
|
9
|
+
InspecPlugins::JsonMinReporter::Reporter
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module InspecPlugins::JsonMinReporter
|
4
|
+
class Reporter < Inspec.plugin(2, :reporter)
|
5
|
+
def self.run_data_schema_constraints
|
6
|
+
"~> 0.0"
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
output(report.to_json, false)
|
11
|
+
end
|
12
|
+
|
13
|
+
def report # rubocop:disable Metrics/AbcSize
|
14
|
+
report = {
|
15
|
+
controls: [],
|
16
|
+
statistics: { duration: run_data.statistics.duration },
|
17
|
+
version: run_data.version,
|
18
|
+
}
|
19
|
+
|
20
|
+
# collect all test results and add them to the report
|
21
|
+
run_data.profiles.each do |profile|
|
22
|
+
profile_id = profile.name
|
23
|
+
|
24
|
+
profile.controls.each do |control|
|
25
|
+
control_id = control.id
|
26
|
+
|
27
|
+
control.results.each do |result|
|
28
|
+
result_for_report = {
|
29
|
+
id: control_id,
|
30
|
+
profile_id: profile_id,
|
31
|
+
profile_sha256: profile.sha256,
|
32
|
+
status: result.status,
|
33
|
+
code_desc: result.code_desc,
|
34
|
+
}
|
35
|
+
|
36
|
+
result_for_report[:skip_message] = result.skip_message if result.non_nil?(:skip_message)
|
37
|
+
result_for_report[:resource] = result.resource if result.non_nil?(:resource)
|
38
|
+
result_for_report[:message] = result.message if result.non_nil?(:message)
|
39
|
+
result_for_report[:exception] = result.exception if result.non_nil?(:exception)
|
40
|
+
result_for_report[:backtrace] = result.backtrace if result.non_nil?(:backtrace)
|
41
|
+
|
42
|
+
report[:controls] << result_for_report
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
report
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
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: 4.
|
4
|
+
version: 4.21.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef InSpec Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-telemetry
|
@@ -264,14 +264,14 @@ dependencies:
|
|
264
264
|
requirements:
|
265
265
|
- - "~>"
|
266
266
|
- !ruby/object:Gem::Version
|
267
|
-
version:
|
267
|
+
version: 1.2.0
|
268
268
|
type: :runtime
|
269
269
|
prerelease: false
|
270
270
|
version_requirements: !ruby/object:Gem::Requirement
|
271
271
|
requirements:
|
272
272
|
- - "~>"
|
273
273
|
- !ruby/object:Gem::Version
|
274
|
-
version:
|
274
|
+
version: 1.2.0
|
275
275
|
- !ruby/object:Gem::Dependency
|
276
276
|
name: addressable
|
277
277
|
requirement: !ruby/object:Gem::Requirement
|
@@ -483,7 +483,6 @@ files:
|
|
483
483
|
- lib/inspec/reporters/cli.rb
|
484
484
|
- lib/inspec/reporters/json.rb
|
485
485
|
- lib/inspec/reporters/json_automate.rb
|
486
|
-
- lib/inspec/reporters/json_min.rb
|
487
486
|
- lib/inspec/reporters/junit.rb
|
488
487
|
- lib/inspec/reporters/yaml.rb
|
489
488
|
- lib/inspec/require_loader.rb
|
@@ -537,6 +536,7 @@ files:
|
|
537
536
|
- lib/inspec/resources/inetd_conf.rb
|
538
537
|
- lib/inspec/resources/ini.rb
|
539
538
|
- lib/inspec/resources/interface.rb
|
539
|
+
- lib/inspec/resources/interfaces.rb
|
540
540
|
- lib/inspec/resources/ip6tables.rb
|
541
541
|
- lib/inspec/resources/iptables.rb
|
542
542
|
- lib/inspec/resources/json.rb
|
@@ -667,6 +667,7 @@ files:
|
|
667
667
|
- lib/inspec/utils/telemetry/collector.rb
|
668
668
|
- lib/inspec/utils/telemetry/data_series.rb
|
669
669
|
- lib/inspec/utils/telemetry/global_methods.rb
|
670
|
+
- lib/inspec/utils/telemetry/run_context_probe.rb
|
670
671
|
- lib/inspec/version.rb
|
671
672
|
- lib/matchers/matchers.rb
|
672
673
|
- lib/plugins/README.md
|
@@ -724,6 +725,21 @@ files:
|
|
724
725
|
- lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli.rb
|
725
726
|
- lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb
|
726
727
|
- lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/plugin.rb
|
728
|
+
- lib/plugins/inspec-reporter-html2/README.md
|
729
|
+
- lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2.rb
|
730
|
+
- lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/reporter.rb
|
731
|
+
- lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/version.rb
|
732
|
+
- lib/plugins/inspec-reporter-html2/templates/body.html.erb
|
733
|
+
- lib/plugins/inspec-reporter-html2/templates/control.html.erb
|
734
|
+
- lib/plugins/inspec-reporter-html2/templates/default.css
|
735
|
+
- lib/plugins/inspec-reporter-html2/templates/default.js
|
736
|
+
- lib/plugins/inspec-reporter-html2/templates/profile.html.erb
|
737
|
+
- lib/plugins/inspec-reporter-html2/templates/result.html.erb
|
738
|
+
- lib/plugins/inspec-reporter-html2/templates/selector.html.erb
|
739
|
+
- lib/plugins/inspec-reporter-json-min/README.md
|
740
|
+
- lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min.rb
|
741
|
+
- lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/reporter.rb
|
742
|
+
- lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/version.rb
|
727
743
|
- lib/plugins/shared/core_plugin_test_helper.rb
|
728
744
|
- lib/plugins/things-for-train-integration.rb
|
729
745
|
- lib/source_readers/flat.rb
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
|
-
module Inspec::Reporters
|
4
|
-
class JsonMin < Base
|
5
|
-
def render
|
6
|
-
output(report.to_json, false)
|
7
|
-
end
|
8
|
-
|
9
|
-
def report # rubocop:disable Metrics/AbcSize
|
10
|
-
report = {
|
11
|
-
controls: [],
|
12
|
-
statistics: { duration: run_data[:statistics][:duration] },
|
13
|
-
version: run_data[:version],
|
14
|
-
}
|
15
|
-
|
16
|
-
# collect all test results and add them to the report
|
17
|
-
run_data[:profiles].each do |profile|
|
18
|
-
profile_id = profile[:name]
|
19
|
-
next unless profile[:controls]
|
20
|
-
|
21
|
-
profile[:controls].each do |control|
|
22
|
-
control_id = control[:id]
|
23
|
-
next unless control[:results]
|
24
|
-
|
25
|
-
control[:results].each do |result|
|
26
|
-
result_for_report = {
|
27
|
-
id: control_id,
|
28
|
-
profile_id: profile_id,
|
29
|
-
profile_sha256: profile[:sha256],
|
30
|
-
status: result[:status],
|
31
|
-
code_desc: result[:code_desc],
|
32
|
-
}
|
33
|
-
|
34
|
-
result_for_report[:skip_message] = result[:skip_message] if result.key?(:skip_message)
|
35
|
-
result_for_report[:resource] = result[:resource] if result.key?(:resource)
|
36
|
-
result_for_report[:message] = result[:message] if result.key?(:message)
|
37
|
-
result_for_report[:exception] = result[:exception] if result.key?(:exception)
|
38
|
-
result_for_report[:backtrace] = result[:backtrace] if result.key?(:backtrace)
|
39
|
-
|
40
|
-
report[:controls] << result_for_report
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
report
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|