inspec-core 4.20.10 → 4.22.8

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/inspec-core.gemspec +1 -1
  4. data/lib/inspec/base_cli.rb +1 -1
  5. data/lib/inspec/exceptions.rb +1 -0
  6. data/lib/inspec/input_registry.rb +2 -1
  7. data/lib/inspec/metadata.rb +6 -1
  8. data/lib/inspec/plugin/v2/plugin_types/reporter.rb +11 -5
  9. data/lib/inspec/profile.rb +30 -9
  10. data/lib/inspec/reporters/base.rb +11 -5
  11. data/lib/inspec/reporters/cli.rb +1 -0
  12. data/lib/inspec/reporters/json.rb +9 -4
  13. data/lib/inspec/resources/apt.rb +2 -0
  14. data/lib/inspec/resources/interface.rb +55 -0
  15. data/lib/inspec/resources/interfaces.rb +119 -0
  16. data/lib/inspec/resources/mount.rb +1 -1
  17. data/lib/inspec/resources/mysql_session.rb +26 -7
  18. data/lib/inspec/resources/postgres_session.rb +1 -1
  19. data/lib/inspec/resources/service.rb +2 -2
  20. data/lib/inspec/resources/users.rb +1 -1
  21. data/lib/inspec/run_data.rb +1 -1
  22. data/lib/inspec/run_data/profile.rb +4 -4
  23. data/lib/inspec/runner.rb +8 -2
  24. data/lib/inspec/runner_rspec.rb +4 -1
  25. data/lib/inspec/schema.rb +2 -0
  26. data/lib/inspec/schema/exec_json.rb +4 -3
  27. data/lib/inspec/schema/primitives.rb +1 -1
  28. data/lib/inspec/version.rb +1 -1
  29. data/lib/plugins/inspec-reporter-html2/README.md +53 -0
  30. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2.rb +18 -0
  31. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/reporter.rb +24 -0
  32. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/version.rb +8 -0
  33. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +46 -0
  34. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +77 -0
  35. data/lib/plugins/inspec-reporter-html2/templates/default.css +107 -0
  36. data/lib/plugins/inspec-reporter-html2/templates/default.js +79 -0
  37. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +23 -0
  38. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +15 -0
  39. data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +8 -0
  40. metadata +22 -4
@@ -61,7 +61,7 @@ module Inspec::Resources
61
61
  os = inspec.os
62
62
  if os.linux?
63
63
  LinuxMounts.new(inspec)
64
- elsif ["freebsd"].include?(os[:family])
64
+ elsif os.bsd?
65
65
  BsdMounts.new(inspec)
66
66
  end
67
67
  end
@@ -4,6 +4,23 @@ require "inspec/resources/command"
4
4
  require "shellwords"
5
5
 
6
6
  module Inspec::Resources
7
+ class Lines
8
+ attr_reader :output
9
+
10
+ def initialize(raw, desc)
11
+ @output = raw
12
+ @desc = desc
13
+ end
14
+
15
+ def lines
16
+ output.split("\n")
17
+ end
18
+
19
+ def to_s
20
+ @desc
21
+ end
22
+ end
23
+
7
24
  class MysqlSession < Inspec.resource(1)
8
25
  name "mysql_session"
9
26
  supports platform: "unix"
@@ -28,15 +45,17 @@ module Inspec::Resources
28
45
 
29
46
  def query(q, db = "")
30
47
  mysql_cmd = create_mysql_cmd(q, db)
31
- cmd = inspec.command(mysql_cmd)
48
+ cmd = if !@pass.nil?
49
+ inspec.command(mysql_cmd, redact_regex: /(mysql -u\w+ -p).+(\s-(h|S).*)/)
50
+ else
51
+ inspec.command(mysql_cmd)
52
+ end
32
53
  out = cmd.stdout + "\n" + cmd.stderr
33
- if out =~ /Can't connect to .* MySQL server/ || out.downcase =~ /^error /
34
- # skip this test if the server can't run the query
35
- warn("Can't connect to MySQL instance for SQL checks.")
54
+ if cmd.exit_status != 0 || out =~ /Can't connect to .* MySQL server/ || out.downcase =~ /^error:.*/
55
+ Lines.new(out, "MySQL query with errors: #{q}")
56
+ else
57
+ Lines.new(cmd.stdout.strip, "MySQL query: #{q}")
36
58
  end
37
-
38
- # return the raw command output
39
- cmd
40
59
  end
41
60
 
42
61
  def to_s
@@ -47,7 +47,7 @@ module Inspec::Resources
47
47
 
48
48
  def query(query, db = [])
49
49
  psql_cmd = create_psql_cmd(query, db)
50
- cmd = inspec.command(psql_cmd)
50
+ cmd = inspec.command(psql_cmd, redact_regex: /(PGPASSWORD=').+(' psql .*)/)
51
51
  out = cmd.stdout + "\n" + cmd.stderr
52
52
  if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/
53
53
  Lines.new(out, "PostgreSQL query with errors: #{query}")
@@ -141,7 +141,7 @@ module Inspec::Resources
141
141
  elsif version > 0
142
142
  SysV.new(inspec, service_ctl || "/usr/sbin/service")
143
143
  end
144
- when "redhat", "fedora", "centos", "oracle", "cloudlinux"
144
+ when "redhat", "fedora", "centos", "oracle", "cloudlinux", "scientific"
145
145
  version = os[:release].to_i
146
146
 
147
147
  systemd = ((platform != "fedora" && version >= 7) ||
@@ -154,7 +154,7 @@ module Inspec::Resources
154
154
  end
155
155
  when "wrlinux"
156
156
  SysV.new(inspec, service_ctl)
157
- when "mac_os_x"
157
+ when "mac_os_x", "darwin"
158
158
  LaunchCtl.new(inspec, service_ctl)
159
159
  when "freebsd"
160
160
  BSDInit.new(inspec, service_ctl)
@@ -20,7 +20,7 @@ module Inspec::Resources
20
20
  WindowsUser.new(inspec)
21
21
  elsif ["darwin"].include?(os[:family])
22
22
  DarwinUser.new(inspec)
23
- elsif ["freebsd"].include?(os[:family])
23
+ elsif ["bsd"].include?(os[:family])
24
24
  FreeBSDUser.new(inspec)
25
25
  elsif ["aix"].include?(os[:family])
26
26
  AixUser.new(inspec)
@@ -47,7 +47,7 @@ module Inspec
47
47
  # core reporters have been migrated to plugins. It is probable that new data elements
48
48
  # and new Hash compatibility behavior will be added during the core reporter plugin
49
49
  # conversion process.
50
- SCHEMA_VERSION = "0.1.0".freeze
50
+ SCHEMA_VERSION = "0.2.0".freeze
51
51
 
52
52
  def self.compatible_schema?(constraints)
53
53
  reqs = Gem::Requirement.create(constraints)
@@ -15,7 +15,7 @@ module Inspec
15
15
  :summary,
16
16
  :supports, # complex local
17
17
  :parent_profile,
18
- :skip_message,
18
+ :status_message,
19
19
  :waiver_data, # Undocumented but used in JSON reporter - should not be?
20
20
  :title,
21
21
  :version
@@ -40,7 +40,7 @@ module Inspec
40
40
  title
41
41
  version
42
42
  parent_profile
43
- skip_message
43
+ status_message
44
44
  waiver_data
45
45
  }.each do |field|
46
46
  self[field] = raw_prof_data[field]
@@ -51,11 +51,11 @@ module Inspec
51
51
  class Profile
52
52
  # Good candidate for keyword_init, but that is not in 2.4
53
53
  Dependency = Struct.new(
54
- :name, :path, :status, :skip_message, :git, :url, :compliance, :supermarket, :branch, :tag, :commit, :version, :relative_path
54
+ :name, :path, :status, :status_message, :git, :url, :compliance, :supermarket, :branch, :tag, :commit, :version, :relative_path
55
55
  ) do
56
56
  include HashLikeStruct
57
57
  def initialize(raw_dep_data)
58
- %i{name path status skip_message git url supermarket compliance branch tag commit version relative_path}.each { |f| self[f] = raw_dep_data[f] }
58
+ %i{name path status status_message git url supermarket compliance branch tag commit version relative_path}.each { |f| self[f] = raw_dep_data[f] }
59
59
  end
60
60
  end
61
61
 
@@ -115,8 +115,14 @@ module Inspec
115
115
  @test_collector.add_profile(requirement.profile)
116
116
  end
117
117
 
118
- tests = profile.collect_tests
119
- all_controls += tests unless tests.nil?
118
+ begin
119
+ tests = profile.collect_tests
120
+ all_controls += tests unless tests.nil?
121
+ rescue Inspec::Exceptions::ProfileLoadFailed => e
122
+ Inspec::Log.error "Failed to load profile #{profile.name}: #{e}"
123
+ profile.set_status_message e.to_s
124
+ next
125
+ end
120
126
  end
121
127
 
122
128
  all_controls.each do |rule|
@@ -90,9 +90,12 @@ module Inspec
90
90
  return @rspec_exit_code if @formatter.results.empty?
91
91
 
92
92
  stats = @formatter.results[:statistics][:controls]
93
+ load_failures = @formatter.results[:profiles]&.select { |p| p[:status] == "failed" }&.any?
93
94
  skipped = @formatter.results.dig(:profiles, 0, :status) == "skipped"
94
- if stats[:failed][:total] == 0 && stats[:skipped][:total] == 0 && !skipped
95
+ if stats[:failed][:total] == 0 && stats[:skipped][:total] == 0 && !skipped && !load_failures
95
96
  0
97
+ elsif load_failures
98
+ @conf["distinct_exit"] ? 102 : 1
96
99
  elsif stats[:failed][:total] > 0
97
100
  @conf["distinct_exit"] ? 100 : 1
98
101
  elsif stats[:skipped][:total] > 0 || skipped
@@ -147,6 +147,8 @@ module Inspec
147
147
  "license" => { "type" => "string", "optional" => true },
148
148
  "summary" => { "type" => "string", "optional" => true },
149
149
  "status" => { "type" => "string", "optional" => false },
150
+ "status_message" => { "type" => "string", "optional" => true },
151
+ # skip_message is deprecated, status_message should be used to store the reason for skipping
150
152
  "skip_message" => { "type" => "string", "optional" => true },
151
153
 
152
154
  "supports" => {
@@ -83,7 +83,7 @@ module Inspec
83
83
  "required" => %w{name sha256 supports attributes groups controls},
84
84
  # Name is mandatory in inspec.yml.
85
85
  # supports, controls, groups, and attributes are always present, even if empty
86
- # sha256, status, skip_message
86
+ # sha256, status, status_message
87
87
  "properties" => {
88
88
  # These are provided in inspec.yml
89
89
  "name" => Primitives::STRING,
@@ -100,10 +100,11 @@ module Inspec
100
100
  "description" => Primitives::STRING,
101
101
  "inspec_version" => Primitives::STRING,
102
102
 
103
- # These are generated at runtime, and all except skip_message are guaranteed
103
+ # These are generated at runtime, and all except status_message and skip_message are guaranteed
104
104
  "sha256" => Primitives::STRING,
105
105
  "status" => Primitives::STRING,
106
- "skip_message" => Primitives::STRING, # If skipped, why
106
+ "status_message" => Primitives::STRING, # If skipped or failed to load, why
107
+ "skip_message" => Primitives::STRING, # Deprecated field storing reason for skipping. status_message should be used instead.
107
108
  "controls" => Primitives.array(CONTROL.ref),
108
109
  "groups" => Primitives.array(Primitives::CONTROL_GROUP.ref),
109
110
  "attributes" => Primitives.array(Primitives::INPUT),
@@ -160,7 +160,7 @@ module Inspec
160
160
  "url" => URL,
161
161
  "branch" => STRING,
162
162
  "path" => STRING,
163
- "skip_message" => STRING,
163
+ "status_message" => STRING,
164
164
  "status" => STRING,
165
165
  "git" => URL,
166
166
  "supermarket" => STRING,
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.20.10".freeze
2
+ VERSION = "4.22.8".freeze
3
3
  end
@@ -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,8 @@
1
+ # This file simply makes it easier for CI engines to update
2
+ # the version stamp, and provide a clean way for the gemspec
3
+ # to learn the current version.
4
+ module InspecPlugins
5
+ module Html2Reporter
6
+ VERSION = "0.1.0".freeze
7
+ end
8
+ 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>