inspec-core 4.20.10 → 4.21.1
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 +1 -0
- data/lib/inspec/resources/interface.rb +55 -0
- data/lib/inspec/resources/interfaces.rb +119 -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
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7be94754504cd2aeda9badd0701a9ac28691e0c62f76741db0c3b1b75988b2b
|
4
|
+
data.tar.gz: 314ce4bedf429cb87185f4903bcb5e47c93587fc1c125f9dcff112574f5dde72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa7f2ac74a61e23f82236d175b5adcc4236eb6b48316d7eaca9cfa85fe9f3917a22eb87fc56723ff56635348897e21f635816071fcf1c13a2f808df212388693
|
7
|
+
data.tar.gz: 17245f5ba3ca9aad13bba4870e52bf48c2e2cf2219b03ee569d0a1aa2e699bd2b6de447d30a2d23c44e01c72ded87c9dab596e564eb9206f7826ae72f6b4d366
|
data/Gemfile
CHANGED
@@ -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/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>
|
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.1
|
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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-telemetry
|
@@ -536,6 +536,7 @@ files:
|
|
536
536
|
- lib/inspec/resources/inetd_conf.rb
|
537
537
|
- lib/inspec/resources/ini.rb
|
538
538
|
- lib/inspec/resources/interface.rb
|
539
|
+
- lib/inspec/resources/interfaces.rb
|
539
540
|
- lib/inspec/resources/ip6tables.rb
|
540
541
|
- lib/inspec/resources/iptables.rb
|
541
542
|
- lib/inspec/resources/json.rb
|
@@ -724,6 +725,17 @@ 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
|
727
739
|
- lib/plugins/inspec-reporter-json-min/README.md
|
728
740
|
- lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min.rb
|
729
741
|
- lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/reporter.rb
|