inspec-reporter-flex 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []