inspec-reporter-flex 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 462241a08906f9500cc8ac2eff3d66cf9419d933b4166502dd35b5bc4445834c
4
+ data.tar.gz: c6aefa556b71a5ef91ce07f3d406c4f4dddedf16c89cd577919813aa4ce3fc26
5
+ SHA512:
6
+ metadata.gz: ffc434833148c5c32706ebc64c479a94b05a673d1fb526ec6d4514c2ac549b542018ed7e0412f0304af4aeeb2205253ef68392a3f429679d6e7f66da9b26bb2c
7
+ data.tar.gz: a737d31db943e3755e73a695bf58030851d5191e0015b9dd84a2dbe993049f98f30669ba73c4ea700e49aa896a436883853854a069670d26d749e6d5aee8b835
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## v0.1.0
6
+
7
+ - Initial version
@@ -0,0 +1,133 @@
1
+ # inspec-reporter-flex Plugin
2
+
3
+ InSpec Flex reporter for freeform templating.
4
+
5
+ ## To Install This Plugin
6
+
7
+ Inside InSpec:
8
+
9
+ ```shell
10
+ you@machine $ inspec plugin install inspec-reporter-flex
11
+ ```
12
+
13
+ For use within `kitchen`:
14
+
15
+ ```shell
16
+ you@machine $ gem install inspec-reporter-flex
17
+ ```
18
+
19
+ ## How to use this plugin
20
+
21
+ To generate a report using this plugin and save the output to a file named `report.txt`, run:
22
+
23
+ ```shell
24
+ you@machine $ inspec exec some_profile --reporter flex:/tmp/report.txt
25
+ ```
26
+
27
+ ## Configuring the Plugin
28
+
29
+ The `flex` reporter offers only one customization option:
30
+
31
+ For example:
32
+
33
+ ```json
34
+ {
35
+ "version": "1.2",
36
+ "plugins": {
37
+ "inspec-reporter-flex": {
38
+ "template_file":"template/markdown.rb"
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ See below all customization options available:
45
+
46
+ | Option | Default | Description |
47
+ |------------------|:--------------------:|:--------------:|
48
+ | `template_file` | `templates/flex.erb` | Name of the file for templating. Will look up in order "absolute path", "relative to current directory", "relative to gem directory" |
49
+
50
+ ## Writing Templates
51
+
52
+ Templates are written in the omnipresent ERB language, which might read like this:
53
+
54
+ ```erb
55
+ <% profiles.each do |profile| %>
56
+ <%= profile.title %>:
57
+ <% profile.controls.each do |control| %>
58
+ <%= control.title %>:
59
+ <% control.results.each do |result| %>
60
+ <%= <%= result.status %>
61
+ <% end %>
62
+ <% end %>
63
+ <% end %>
64
+ ```
65
+
66
+ ### Variables
67
+
68
+ The following variables are passed to your template:
69
+
70
+ | Name | Contents |
71
+ | --------------- | ----------------------------------------------- |
72
+ | `profiles` | Array of all profiles from the InSpec run |
73
+ | `statistics` | Statistics (e.g. runtime) |
74
+ | `platform` | Platform information |
75
+ | `version` | InSpec version used |
76
+ | `passed_tests` | Number of passed tests |
77
+ | `failed_tests` | Number of failed tests |
78
+ | `percent_pass` | Percentage of passed tests |
79
+ | `percent_fail` | Percentage of failed tests |
80
+ | `platform_arch` | Architecture of the platform (e.g. `x86_64`) |
81
+ | `platform_name` | Full name of the platform (e.g. `Ubuntu Linux`) |
82
+
83
+ ### Helpers
84
+
85
+ Some helper functions for easier template processing:
86
+
87
+ | Name | Returns | Description |
88
+ | ------------------------------ | ---------- | --------------------------------------------- |
89
+ | `scan_time` | `DateTime` | Roughly the time of scan end |
90
+ | `control_passed?(control)` | `Boolean` | If all results of the control are passed |
91
+ | `status_to_pass(status)` | `String` | Translate to "ok"/not ok" |
92
+ | `impact_to_severity(severity)` | `String` | Translate InSpec numeric severity to a string |
93
+
94
+ You also have the option of running some additional commands against the machine under test. This is sometimes needed for some metadata in reports.
95
+
96
+ Execution or InSpec resource related helpers:
97
+
98
+ | Name | Returns | Description |
99
+ | --------------------------------------- | ------------------- | ------------------------------------------------------------------------- |
100
+ | `remote_command(cmd)` | `CommandResult` | Execute command (`.stdout`/`.stderr`/`.exit_status`) |
101
+ | `remote_file_content(remote_file)` | `String` | Contents of a file |
102
+ | `os` | `os` resource | OS information (`.arch`/`.family`/`.name`) |
103
+ | `sys_info` | `sys_info` resource | System Information (`.domain`/`.fqdn`/`.hostname`/`.ip_address`/`.model`) |
104
+ | `inspec_resource.*` | Any InSpec resource | Return value varies depending on the resource |
105
+
106
+ ### Template-specific settings
107
+
108
+ You can add your own template-specific settings via the `template_config` hash in the ERB templates. Just add a block to read those and apply defaults like:
109
+
110
+ ```ruby
111
+ <%
112
+ config_emojis = template_config.fetch("emojis", true)
113
+ %>
114
+ ```
115
+
116
+ You can configure these freeform settings in your `~/.inspec/config.json`:
117
+
118
+ ```json
119
+ {
120
+ "version": "1.2",
121
+ "plugins": {
122
+ "inspec-reporter-flex": {
123
+ "template_config": {
124
+ "emojis": true
125
+ }
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## Developing This Plugin
132
+
133
+ Submit PR and will discuss, thank you!
@@ -0,0 +1,4 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require "inspec-reporter-flex/plugin"
@@ -0,0 +1,92 @@
1
+ module InspecPlugins::FlexReporter
2
+ module ErbHelpers
3
+ # Return latest start time of the scan
4
+ #
5
+ # @return [DateTime] Timestamp of the last scan in the profile
6
+ def scan_time
7
+ DateTime.strptime(report[:profiles].last[:controls].last[:results].last[:start_time])
8
+ end
9
+
10
+ # Execute a remote command.
11
+ #
12
+ # @param [String] cmd Command to execute
13
+ # @return [Train::Extras::CommandResult] Command result (.stdout/.stderr/.exit_status)
14
+ def remote_command(cmd)
15
+ runner.backend.backend.run_command(cmd)
16
+ end
17
+
18
+ # Retrieve remote file contents.
19
+ #
20
+ # @param [String] remote_file Path to the remote file
21
+ # @return [String] Contents of the file
22
+ def remote_file_content(remote_file)
23
+ runner.backend.backend.file(remote_file).content
24
+ end
25
+
26
+ # Allow access to all InSpec resources from the report.
27
+ #
28
+ # @return [Inspec::Backend] The InSpec backend
29
+ def inspec_resource
30
+ runner.backend
31
+ end
32
+
33
+ # Return InSpec OS resource results.
34
+ #
35
+ # @return [Class] Look into documentation for properties (.arch/.family/.name/...)
36
+ # @see https://github.com/inspec/inspec/blob/master/lib/inspec/resources/os.rb
37
+ def os
38
+ runner.backend.os
39
+ end
40
+
41
+ # Return InSpec SysInfo resource results.
42
+ #
43
+ # @return [Class] Look into documentation for properteis (.domain/.fqdn/.hostname/.ip_address/.model/...)
44
+ # @see https://github.com/inspec/inspec/blob/master/lib/inspec/resources/sys_info.rb
45
+ def sys_info
46
+ runner.backend.sys_info
47
+ end
48
+
49
+ # Return if all results of a control have passed/skipped/waived.
50
+ #
51
+ # @param [Hash] control Data of a control run
52
+ # @return [Boolean] If all passed checks
53
+ def control_passed?(control)
54
+ control[:results].any? { |result| result[:status] == "failed" }
55
+ end
56
+
57
+ # Map InSpec status to cleartext
58
+ #
59
+ # @param [String] inspec_status One of the valid InSpec result status.
60
+ # @return [Strint] "ok"/"not ok" depending on status
61
+ def status_to_pass(inspec_status)
62
+ case inspec_status
63
+ when "passed", "skipped", "waived"
64
+ "ok"
65
+ else
66
+ "not ok"
67
+ end
68
+ end
69
+
70
+ # Map InSpec severity (0..1) to CVSS scale (none-low-medium-high-critical)
71
+ #
72
+ # @param [Float] inspec_severity Severity from the profile
73
+ # @return [String] One of the scale values
74
+ # @see https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale
75
+ def impact_to_severity(inspec_severity)
76
+ case inspec_severity
77
+ when 0.0...0.1
78
+ "none"
79
+ when 0.1...0.4
80
+ "low"
81
+ when 0.4...0.7
82
+ "medium"
83
+ when 0.7...0.9
84
+ "high"
85
+ when 0.9..1.0
86
+ "critical"
87
+ else
88
+ "unknown"
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,60 @@
1
+ module InspecPlugins::FlexReporter
2
+ module FileResolver
3
+ # Resolve the absolute path for a file in order absolute path/gem bundled file/relative.
4
+ #
5
+ # @param [String] name Name or path of a file to resolve
6
+ # @return [String] Absolute path to the file, if any
7
+ # @raise [RuntimeError] if file not found
8
+ def resolve_path(name)
9
+ if absolute_path?(name)
10
+ name
11
+ elsif relative_path?(name)
12
+ relative_path(name)
13
+ elsif gem_path?(name)
14
+ gem_path(name)
15
+ else
16
+ raise "Template file #{name} not found"
17
+ end
18
+ end
19
+
20
+ # Is this an absolute path?
21
+ #
22
+ # @param [String] name name or path of a file
23
+ # @return [Boolean] if it is an absolute path
24
+ def absolute_path?(name)
25
+ name.start_with? "/"
26
+ end
27
+
28
+ # Is this an relative path?
29
+ #
30
+ # @param [String] name name or path of a file
31
+ # @return [Boolean] if it is an relative path
32
+ def relative_path?(name)
33
+ File.exist? relative_path(name)
34
+ end
35
+
36
+ # Is this a Gem-bundled path?
37
+ #
38
+ # @param [String] name name or path of a file
39
+ # @return [Boolean] if it is a Gem-bundled path
40
+ def gem_path?(name)
41
+ File.exist? gem_path(name)
42
+ end
43
+
44
+ # Return absolute path for a file relative to Dir.pwd.
45
+ #
46
+ # @param [String] name Name or path of a file
47
+ # @return [String] Absolute path to the file
48
+ def relative_path(name)
49
+ File.join(Dir.pwd, name)
50
+ end
51
+
52
+ # Return absolute path for a file bundled with this Gem.
53
+ #
54
+ # @param [String] name Name or path of a file
55
+ # @return [String] Absolute path to the file
56
+ def gem_path(name)
57
+ File.join(__dir__, "../../..", name)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "version"
2
+
3
+ module InspecPlugins
4
+ module FlexReporter
5
+ class Plugin < ::Inspec.plugin(2)
6
+ # Internal machine name of the plugin. InSpec will use this in errors, etc.
7
+ plugin_name :"inspec-reporter-flex"
8
+
9
+ reporter :flex do
10
+ require_relative "reporter"
11
+ InspecPlugins::FlexReporter::Reporter
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,76 @@
1
+ require_relative "mixin/erb_helpers"
2
+ require_relative "mixin/file_resolver"
3
+
4
+ require "erb" unless defined? ERB
5
+
6
+ module InspecPlugins::FlexReporter
7
+ class Reporter < Inspec::Reporters::Json
8
+ include InspecPlugins::FlexReporter::ErbHelpers
9
+ include InspecPlugins::FlexReporter::FileResolver
10
+
11
+ # Render report
12
+ def render
13
+ template_file = resolve_path(config["template"])
14
+ template = ERB.new(File.read(template_file))
15
+
16
+ # Use JSON Reporter base's `report` to have pre-processed data
17
+ mushy_report = Hashie::Mash.new(report)
18
+
19
+ # Eeease of use here
20
+ platform = mushy_report.platform
21
+ profiles = mushy_report.profiles
22
+ statistics = mushy_report.statistics
23
+ version = mushy_report.version
24
+
25
+ # Some pass/fail information
26
+ test_results = profiles.map(&:controls).flatten.map(&:results).flatten.map(&:status)
27
+ passed_tests = test_results.select { |text| text == "passed" }.count
28
+ failed_tests = test_results.count - passed_tests
29
+ percent_pass = 100.0 * passed_tests / test_results.count
30
+ percent_fail = 100.0 - percent_pass
31
+
32
+ # Detailed OS
33
+ platform_arch = runner.backend.backend.os.arch
34
+ platform_name = runner.backend.backend.os.title
35
+
36
+ # Allow template-based settings
37
+ template_config = config.fetch("template_config", {})
38
+
39
+ # ... also can use all InSpec resources via "inspec_resource.NAME.PROPERTY"
40
+
41
+ output(template.result(binding))
42
+ end
43
+
44
+ # Return Constraints.
45
+ #
46
+ # @return [String] Always "~> 0.0"
47
+ def self.run_data_schema_constraints
48
+ "~> 0.0"
49
+ end
50
+
51
+ private
52
+
53
+ # Initialize configuration with defaults and Plugin config.
54
+ #
55
+ # @return [Hash] Configuration data after merge
56
+ def config
57
+ @config unless @config.nil?
58
+
59
+ # Defaults
60
+ @config = {
61
+ "template" => "templates/flex.erb",
62
+ }
63
+
64
+ @config.merge! Inspec::Config.cached.fetch_plugin_config("inspec-reporter-flex")
65
+ end
66
+
67
+ # Return InSpec Runner for further inspection.
68
+ #
69
+ # @return [Inspec::Runner] Runner instance
70
+ def runner
71
+ require "binding_of_caller"
72
+
73
+ binding.callers.find { |b| b.frame_description == "run_tests" }.receiver
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ module InspecPlugins
2
+ module FlexReporter
3
+ VERSION = "0.1.0".freeze
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ <%
2
+ # Free-form, template-based settings are available
3
+ config_emojis = template_config["emojis"]
4
+
5
+ %># InSpec Report
6
+
7
+ Scanned on <%= scan_time.strftime('%Y-%m-%d') %>.
8
+
9
+ Host: <%= sys_info.fqdn %>
10
+ OS: <%= platform_name %> <%= platform[:release] %> (<%= platform_arch %>)
11
+
12
+ Tests passed: <%= passed_tests %> (<%= format("%2.1f%%", percent_pass) %>)
13
+ Tests failed: <%= failed_tests %> (<%= format("%2.1f%%", percent_fail) %>)
14
+
15
+ <% profiles.each do |profile|
16
+
17
+ %>## Profile `<%= profile.title %>`<%
18
+ profile.controls.each do |control| %>
19
+
20
+ ### Control `<%= control.title %>`
21
+
22
+ <%= control.desc %>
23
+
24
+ Results:
25
+ <% control.results.each do |result| %>
26
+ - <%= result.code_desc %>: <%= result.status %><%= config_emojis ? (result.status == "passed" ? " :heavy_check_mark:" : " :red_circle:") : "" %><%
27
+ end # result %>
28
+ <% end # control %>
29
+ <% end # profile %>
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inspec-reporter-flex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Heinen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bump
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chefstyle
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mdl
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ description: Plugin for templated reports
84
+ email:
85
+ - theinen@tecracer.de
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - CHANGELOG.md
91
+ - README.md
92
+ - lib/inspec-reporter-flex.rb
93
+ - lib/inspec-reporter-flex/mixin/erb_helpers.rb
94
+ - lib/inspec-reporter-flex/mixin/file_resolver.rb
95
+ - lib/inspec-reporter-flex/plugin.rb
96
+ - lib/inspec-reporter-flex/reporter.rb
97
+ - lib/inspec-reporter-flex/version.rb
98
+ - templates/flex.erb
99
+ homepage: https://github.com/tecracer-chef/inspec-reporter-flex
100
+ licenses:
101
+ - Apache-2.0
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '2.6'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubygems_version: 3.0.3
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: InSpec Reporter for flexible, template-based reports
122
+ test_files: []