mitre-inspec-objects 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9d65c4605033c4239780e56b8a9084d8f7fa9cdb2a971ba9062b9657a788949a
4
+ data.tar.gz: 226d6194461b806d249dbc188bc1cda532973f60c06d53dd0c1a5c75558a5f5f
5
+ SHA512:
6
+ metadata.gz: 289530d31dd264f8b2339f09b8ea55858d644fd91cb48420ff4b9e269a2566b726aaee50e6849428b5f2c8fc23ec35cb240d486b6f428868dc83d4cb0918a7d8
7
+ data.tar.gz: 2468c9a73f7f5bfa729fe0b6b8b2d96a62ebfa1d99e122976d070ce716a41de3839eba843c171de27fab5c985087d5b04a7300a485cd8df2c9e1315318594ed8
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "mitre-inspec-objects", path: "."
6
+
7
+ group :test do
8
+ gem "chef-utils", "~> 16.6.14"
9
+ gem "chefstyle", "0.13.0"
10
+ gem "minitest", "~> 5.5"
11
+ gem "rake", ">= 10"
12
+ end
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # inspec-objects
2
+ [![Gem Version](https://badge.fury.io/rb/mitre-inspec-objects.svg)](https://badge.fury.io/rb/mitre-inspec-objects)
3
+
4
+ **Umbrella Project**: [InSpec](https://github.com/chef/chef-oss-practices/blob/master/projects/inspec.md)
5
+
6
+ **Project State**: [Maintained](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md#maintained)
7
+
8
+ **Issues [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: None
9
+
10
+ **Pull Request [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: None
11
+
12
+ These classes were migrated out of InSpec, specifically [inspec/lib/objects](https://github.com/inspec/inspec/tree/master/lib/inspec/objects).
13
+
14
+ InSpec does not uses these classes directly. They can be used to programmatically create InSpec profiles.
15
+
16
+ No further documentation or support is available.
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Control
5
+ attr_accessor :header, :id, :title, :descriptions, :impact, :tests, :post_body, :tags, :refs, :only_if
6
+ def initialize
7
+ @header = ""
8
+ @tests = []
9
+ @tags = []
10
+ @refs = []
11
+ @descriptions = {}
12
+ @post_body = ""
13
+ end
14
+
15
+ def add_header(header)
16
+ @header = header
17
+ end
18
+
19
+ def add_test(t)
20
+ @tests.push(t)
21
+ end
22
+
23
+ def add_tag(t)
24
+ @tags.push(t)
25
+ end
26
+
27
+ def add_post_body(post_body)
28
+ @post_body = post_body
29
+ end
30
+
31
+ def to_hash
32
+ {
33
+ header: header,
34
+ id: id,
35
+ title: title,
36
+ descriptions: descriptions,
37
+ impact: impact,
38
+ tests: tests.map(&:to_hash),
39
+ tags: tags.map(&:to_hash),
40
+ post_body: post_body,
41
+ }
42
+ end
43
+
44
+ def to_ruby
45
+ res = []
46
+ res.push header unless header.nil? || header.empty?
47
+ res.push "control #{id.inspect} do"
48
+ res.push " title #{title.inspect}" unless title.to_s.empty?
49
+ descriptions.each do |label, text|
50
+ if label == :default
51
+ next if text.nil? || (text == "") # don't render empty/nil desc
52
+
53
+ res.push " desc #{prettyprint_text(text, 2)}"
54
+ else
55
+ res.push " desc #{label.to_s.inspect}, #{prettyprint_text(text, 2)}"
56
+ end
57
+ end
58
+ res.push " impact #{impact}" unless impact.nil?
59
+ tags.each { |t| res.push(indent(t.to_ruby, 2)) }
60
+ refs.each { |t| res.push(" ref #{print_ref(t)}") }
61
+ res.push " only_if { #{only_if} }" if only_if
62
+ tests.each { |t| res.push(indent(t.to_ruby, 2)) }
63
+ res.push(indent(post_body, 2)) unless post_body.nil? || post_body.empty?
64
+ res.push "end"
65
+ res.join("\n")
66
+ end
67
+
68
+ private
69
+
70
+ def print_ref(x)
71
+ return x.inspect if x.is_a?(String)
72
+ raise "Cannot process the ref: #{x}" unless x.is_a?(Hash)
73
+
74
+ "(" + x.inspect + ")"
75
+ end
76
+
77
+ # Pretty-print a text block of InSpec code
78
+ #
79
+ # @param s [String] should not be empty
80
+ # @param depth [Int] indentation length for multiline text blocks
81
+ # @return [String] pretty-printed textblock
82
+ def prettyprint_text(s, depth)
83
+ txt = s.to_s.inspect.gsub('\n', "\n")
84
+ return txt unless txt.include?("\n")
85
+
86
+ middle = indent(txt[1..-2], depth + 2)
87
+ txt[0] + "\n" + middle + "\n" + " " * depth + txt[-1]
88
+ end
89
+
90
+ def indent(txt, d)
91
+ dt = " " * d
92
+ dt + txt.gsub("\n", "\n" + dt)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Describe
5
+ # Internal helper to structure test objects.
6
+ # Should not be exposed to the user as it is hidden behind
7
+ # `add_test`, `to_hash`, and `to_ruby` in Inspec::Object::Describe
8
+ Test = Struct.new(:its, :matcher, :expectation, :negated) do
9
+ def negate!
10
+ self.negated = !negated
11
+ end
12
+
13
+ def to_ruby
14
+ itsy = "it"
15
+ unless its.nil?
16
+ itsy = if its.is_a? Array
17
+ "its(" + its.inspect + ")"
18
+ else
19
+ "its(" + its.to_s.inspect + ")"
20
+ end
21
+ end
22
+ naughty = negated ? "_not" : ""
23
+ xpect = if expectation.nil?
24
+ ""
25
+ elsif expectation.class == Regexp
26
+ # without this, xpect values like / \/zones\// will not be parsed properly
27
+ "(#{expectation.inspect})"
28
+ else
29
+ " " + expectation.inspect
30
+ end
31
+ format("%s { should%s %s%s }", itsy, naughty, matcher, xpect)
32
+ end
33
+ end
34
+
35
+ # A qualifier describing the resource that will be tested. It may consist
36
+ # of the resource identification and multiple accessors to pinpoint the data
37
+ # the user wants to test.
38
+ attr_accessor :qualifier
39
+
40
+ # An array of individual tests for the qualifier. Every entry will be
41
+ # translated into an `it` or `its` clause.
42
+ attr_accessor :tests
43
+
44
+ # Optional variables which are used by tests.
45
+ attr_accessor :variables
46
+
47
+ # Optional method to skip this describe block altogether. If `skip` is
48
+ # defined it takes precendence and will print the skip statement instead
49
+ # of adding other tests.
50
+ attr_accessor :skip
51
+
52
+ include RubyHelper
53
+
54
+ def initialize
55
+ @qualifier = []
56
+ @tests = []
57
+ @variables = []
58
+ end
59
+
60
+ def add_test(its, matcher, expectation, opts = {})
61
+ test = Inspec::Object::Describe::Test.new(its, matcher, expectation, opts[:negated])
62
+ tests.push(test)
63
+ test
64
+ end
65
+
66
+ def to_ruby
67
+ return rb_skip unless skip.nil?
68
+
69
+ rb_describe
70
+ end
71
+
72
+ def to_hash
73
+ { qualifier: qualifier, tests: tests.map(&:to_h), variables: variables, skip: skip }
74
+ end
75
+
76
+ def resource
77
+ return if qualifier.empty? || qualifier[0].empty? || qualifier[0][0].empty?
78
+
79
+ qualifier[0][0]
80
+ end
81
+
82
+ private
83
+
84
+ def rb_describe
85
+ vars = variables.map(&:to_ruby).join("\n")
86
+ vars += "\n" unless vars.empty?
87
+
88
+ objarr = @qualifier
89
+ objarr = [["unknown object".inspect]] if objarr.nil? || objarr.empty?
90
+ obj = objarr.map { |q| ruby_qualifier(q) }.join(".")
91
+
92
+ rbtests = tests.map(&:to_ruby).join("\n ")
93
+ format("%sdescribe %s do\n %s\nend", vars, obj, rbtests)
94
+ end
95
+
96
+ def rb_skip
97
+ obj = @qualifier || skip.inspect
98
+ format("describe %s do\n skip %s\nend", obj, skip.inspect)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class EachLoop < List
5
+ attr_reader :variables
6
+ attr_accessor :tests
7
+ def initialize
8
+ super
9
+ @tests = []
10
+ @variables = []
11
+ end
12
+
13
+ def add_test(t = nil)
14
+ t ||= Test.new
15
+ t.qualifier[0] = ["entry"]
16
+ @tests.push(t)
17
+ t
18
+ end
19
+
20
+ def negate!
21
+ @tests.each(&:negate!)
22
+ end
23
+
24
+ def to_hash
25
+ { qualifier: qualifier, test: @test }
26
+ end
27
+
28
+ def to_ruby
29
+ vars = variables.map(&:to_ruby).join("\n")
30
+ vars += "\n" unless vars.empty?
31
+ obj = super
32
+ all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
33
+ format("%s%s.each do |entry|\n %s\nend", vars, obj, all_tests)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Header
5
+ attr_accessor :header
6
+
7
+ def initialize(header)
8
+ @header = header
9
+ end
10
+
11
+ def to_hash
12
+ {
13
+ header: header,
14
+ }
15
+ end
16
+
17
+ def to_ruby
18
+ header.inspect.to_s
19
+ end
20
+
21
+ def to_s
22
+ "Header #{header}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "inspec/input"
4
+
5
+ module Inspec::Object
6
+ class Input < ::Inspec::Input
7
+ # NOTE: No initialize method or accessors for the reasons listed above
8
+
9
+ #--------------------------------------------------------------------------#
10
+ # Marshalling
11
+ #--------------------------------------------------------------------------#
12
+
13
+ def to_hash
14
+ as_hash = { name: name, options: {} }
15
+ %i{description title identifier type required value}.each do |field|
16
+ val = send(field)
17
+ next if val.nil?
18
+
19
+ as_hash[:options][field] = val
20
+ end
21
+ as_hash
22
+ end
23
+
24
+ def ruby_var_identifier
25
+ identifier || "attr_" + name.downcase.strip.gsub(/\s+/, "-").gsub(/[^\w-]/, "")
26
+ end
27
+
28
+ def to_ruby
29
+ res = ["#{ruby_var_identifier} = attribute('#{name}',{"]
30
+ res.push " title: '#{title}'," unless title.to_s.empty?
31
+ res.push " value: #{value.inspect}," unless value.to_s.empty?
32
+ # to_ruby may generate code that is to be used by older versions of inspec.
33
+ # Anything older than 3.4 will not recognize the value: option, so
34
+ # send the default: option as well. See #3759
35
+ res.push " default: #{value.inspect}," unless value.to_s.empty?
36
+ res.push " description: '#{description}'," unless description.to_s.empty?
37
+ res.push "})"
38
+ res.join("\n")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class List < Value
5
+ def map
6
+ raise "Inspec::Object::List.map needs to be called with a block" unless block_given?
7
+
8
+ t = List.new
9
+ t.qualifier = [["x"]]
10
+ yield(t)
11
+ return if t.qualifier == [["x"]]
12
+
13
+ @qualifier.push(["map", "{ |x| #{t.to_ruby} }"])
14
+ self
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class OrTest
5
+ attr_reader :tests
6
+ def initialize(tests)
7
+ @tests = tests
8
+ @negated = false
9
+ end
10
+
11
+ def skip
12
+ nil
13
+ end
14
+
15
+ def negate!
16
+ @negated = !@negated
17
+ end
18
+
19
+ def to_ruby
20
+ if @negated
21
+ # We don't use the describe.one wrapper when negated because:
22
+ # !(test1 || test2) same as (!test1 && !test2) where && is implicit in inspec
23
+ @tests.map do |test|
24
+ test.negate!
25
+ test
26
+ end.map(&:to_ruby).join("\n")
27
+
28
+ else
29
+ all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
30
+
31
+ format("describe.one do\n %s\nend", all_tests)
32
+ end
33
+ end
34
+
35
+ def to_hash
36
+ { describe_one: @tests.map(&:to_hash) }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class PostBody
5
+ attr_accessor :post_body
6
+
7
+ def initialize(post_body)
8
+ @post_body = post_body
9
+ end
10
+
11
+ def to_hash
12
+ {
13
+ post_body: post_body,
14
+ }
15
+ end
16
+
17
+ def to_ruby
18
+ post_body.inspect.to_s
19
+ end
20
+
21
+ def to_s
22
+ "Post Body #{post_body}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ module RubyHelper
5
+ def ruby_qualifier(q)
6
+ if q.length <= 1
7
+ q[0]
8
+ elsif q[0] == "map" && q.length == 2
9
+ q[0] + " " + q[1]
10
+ else
11
+ q[0] + "(" + q[1..-1].map(&:inspect).join(", ") + ")"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Tag
5
+ attr_accessor :key, :value
6
+
7
+ def initialize(key, value)
8
+ @key = key
9
+ @value = value
10
+ end
11
+
12
+ def to_hash
13
+ {
14
+ name: key,
15
+ value: value,
16
+ }
17
+ end
18
+
19
+ def to_ruby
20
+ "tag #{key}: #{value.inspect}"
21
+ end
22
+
23
+ def to_s
24
+ "Tag #{key} with #{value}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Test
5
+ attr_accessor :qualifier, :matcher, :expectation, :skip, :negated, :variables, :only_if
6
+ include RubyHelper
7
+
8
+ def initialize
9
+ @qualifier = []
10
+ @negated = false
11
+ @variables = []
12
+ end
13
+
14
+ def negate!
15
+ @negated = !@negated
16
+ end
17
+
18
+ def to_ruby
19
+ return rb_skip unless skip.nil?
20
+
21
+ rb_describe
22
+ end
23
+
24
+ def to_hash
25
+ { qualifier: qualifier, matcher: matcher, expectation: expectation, skip: skip, negated: negated }
26
+ end
27
+
28
+ def resource
29
+ @resource ||=
30
+ if qualifier.empty? || qualifier[0].empty? || qualifier[0][0].empty?
31
+ nil
32
+ else
33
+ qualifier[0][0]
34
+ end
35
+ end
36
+
37
+ def remove_expectation
38
+ remove_instance_variable(:@expectation)
39
+ end
40
+
41
+ private
42
+
43
+ def describe_chain
44
+ return if @qualifier.empty?
45
+
46
+ resource = @qualifier.length > 1 ? @qualifier[0..-2] : [@qualifier[0]]
47
+ res = resource.map { |q| ruby_qualifier(q) }.join(".")
48
+ xres = nil
49
+
50
+ if @qualifier.length > 1
51
+ last = @qualifier[-1]
52
+ last_call = last.is_a?(Array) ? last[0].to_s : ""
53
+ if last.length == 1 && last_call !~ /^to_.$/ && !last_call.include?("[") && !last_call.empty?
54
+ # this will go in its()
55
+ xres = last_call
56
+ else
57
+ res += "." + ruby_qualifier(last) unless last_call.empty?
58
+ end
59
+ end
60
+
61
+ [res, xres]
62
+ end
63
+
64
+ def rb_describe
65
+ only_if_clause = "only_if { #{only_if} }\n" if only_if
66
+ vars = variables.map(&:to_ruby).join("\n")
67
+ vars += "\n" unless vars.empty?
68
+ res, xtra = describe_chain
69
+ itsy = xtra.nil? ? "it" : "its(" + xtra.to_s.inspect + ")"
70
+ naughty = @negated ? "_not" : ""
71
+ xpect = if !defined?(@expectation)
72
+ ""
73
+ elsif @expectation.class == Regexp
74
+ # without this, xpect values like / \/zones\// will not be parsed properly
75
+ "(#{@expectation.inspect})"
76
+ elsif xpect != ""
77
+ " " + expectation.inspect
78
+ end
79
+ format("%s%sdescribe %s do\n %s { should%s %s%s }\nend",
80
+ only_if_clause, vars, res, itsy, naughty, matcher, xpect)
81
+ end
82
+
83
+ def rb_skip
84
+ dc = describe_chain
85
+ obj = dc.nil? ? skip.inspect : dc[0]
86
+ format("describe %s do\n skip %s\nend", obj, skip.inspect)
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec::Object
4
+ class Value
5
+ include ::Inspec::Object::RubyHelper
6
+
7
+ attr_accessor :qualifier
8
+ attr_accessor :skip
9
+ attr_accessor :variable
10
+
11
+ def initialize(qualifiers = [])
12
+ @qualifier = qualifiers
13
+ @variable = nil
14
+ end
15
+
16
+ def to_ruby
17
+ res = @variable.nil? ? "" : "#{@variable} = "
18
+ res + @qualifier.map { |x| ruby_qualifier(x) }.join(".")
19
+ end
20
+
21
+ def name_variable(cache = [])
22
+ @variable = Array("a".."z").find { |x| !cache.include?(x) }
23
+ cache.push(@variable)
24
+ @variable
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inspec
4
+ module Object
5
+ require_relative "objects/tag"
6
+ require_relative "objects/control"
7
+ require_relative "objects/ruby_helper"
8
+ require_relative "objects/describe"
9
+ require_relative "objects/value"
10
+ require_relative "objects/list"
11
+ require_relative "objects/each_loop"
12
+ require_relative "objects/or_test"
13
+ require_relative "objects/test"
14
+ require_relative "objects/input"
15
+ require_relative "objects/post_body"
16
+ require_relative "objects/header"
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InspecObjects
4
+ VERSION = "0.3.2"
5
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mitre-inspec-objects/version"
4
+ require_relative "inspec/objects"
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "mitre-inspec-objects/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "mitre-inspec-objects"
10
+ spec.version = InspecObjects::VERSION
11
+ spec.authors = ["Dominik Richter", "Christoph Hartmann", "Aaron Lippold"]
12
+ spec.email = ["dominik.richter@gmail.com", "chris@lollyrock.com"]
13
+ spec.summary = "InSpec Objects library"
14
+ spec.description = "Library that provides an API for programmatically creating InSpec profiles"
15
+ spec.homepage = "https://github.com/mitre/inspec-objects"
16
+ spec.license = "Apache-2.0"
17
+
18
+ spec.files = %w{
19
+ README.md mitre-inspec-objects.gemspec Gemfile
20
+ } + Dir.glob("{lib}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
21
+
22
+ spec.require_paths = ["lib"]
23
+ spec.add_dependency "inspec-core"
24
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mitre-inspec-objects
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Dominik Richter
8
+ - Christoph Hartmann
9
+ - Aaron Lippold
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2022-02-08 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: inspec-core
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ description: Library that provides an API for programmatically creating InSpec profiles
30
+ email:
31
+ - dominik.richter@gmail.com
32
+ - chris@lollyrock.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - Gemfile
38
+ - README.md
39
+ - lib/inspec/objects.rb
40
+ - lib/inspec/objects/control.rb
41
+ - lib/inspec/objects/describe.rb
42
+ - lib/inspec/objects/each_loop.rb
43
+ - lib/inspec/objects/header.rb
44
+ - lib/inspec/objects/input.rb
45
+ - lib/inspec/objects/list.rb
46
+ - lib/inspec/objects/or_test.rb
47
+ - lib/inspec/objects/post_body.rb
48
+ - lib/inspec/objects/ruby_helper.rb
49
+ - lib/inspec/objects/tag.rb
50
+ - lib/inspec/objects/test.rb
51
+ - lib/inspec/objects/value.rb
52
+ - lib/mitre-inspec-objects.rb
53
+ - lib/mitre-inspec-objects/version.rb
54
+ - mitre-inspec-objects.gemspec
55
+ homepage: https://github.com/mitre/inspec-objects
56
+ licenses:
57
+ - Apache-2.0
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.2.32
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: InSpec Objects library
78
+ test_files: []