inspec-core 4.19.2 → 4.21.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|