Add support for multiple descriptions for controls (#3424)

* Add support for multiple descriptions for controls

This adds the ability to specify multiple descriptions in controls.

Example:

```ruby
control 'my-control' do
  impact 1.0
  title 'My control'
  desc 'A default description'
  desc 'rational', 'I need an example'
  describe file('/tmp') do
    it { should be_directory }
  end
end
```

Many thanks to @jquick for helping me with the unit tests.
* Remove unused `descriptions` method
* Remove unused profile from test mocks
* Respond to feedback

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
This commit is contained in:
Jerry Aldrich 2018-09-26 10:28:58 -07:00 committed by Jared Quick
parent 3b6bd808e9
commit 20776b363d
24 changed files with 156 additions and 65 deletions

View file

@ -26,10 +26,8 @@ In various use cases like implementing IT compliance across different department
control 'sshd-8' do
impact 0.6
title 'Server: Configure the service port'
desc '
Always specify which port the SSH server should listen to.
Prevent unexpected settings.
'
desc 'Always specify which port the SSH server should listen.'
desc 'rationale', 'This ensures that there are no unexpected settings'
tag 'ssh','sshd','openssh-server'
tag cce: 'CCE-27072-8'
ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'
@ -44,6 +42,7 @@ where
* `'sshd-8'` is the name of the control
* `impact`, `title`, and `desc` define metadata that fully describes the importance of the control, its purpose, with a succinct and complete description
* `desc` when given only one argument it sets the default description. When given 2 arguments (see: `'rationale'`) it will use the first argument as a header when rendering in Automate
* `impact` is an float that measures the importance of the compliance results and must be a value between `0.0` and `1.0`. The value ranges are:
* `0.0 to <0.4` these are controls with minor criticality
* `0.4 to <0.7` these are controls with major criticality

View file

@ -4,15 +4,16 @@
title '/tmp profile'
# you add controls here
control "tmp-1.0" do # A unique ID for this control
impact 0.7 # The criticality, if this control fails.
title "Create /tmp directory" # A human-readable title
desc "An optional description..." # Describe why this is needed
tag data: "temp data" # A tag allows you to associate key information
tag "security" # to the test
ref "Document A-12", url: 'http://...' # Additional references
control "tmp-1.0" do # A unique ID for this control
impact 0.7 # The criticality, if this control fails.
title "Create /tmp directory" # A human-readable title
desc "An optional description..." # Describe why this is needed
desc "label", "An optional description with a label" # Pair a part of the description with a label
tag data: "temp data" # A tag allows you to associate key information
tag "security" # to the test
ref "Document A-12", url: 'http://...' # Additional references
describe file('/tmp') do # The actual test
describe file('/tmp') do # The actual test
it { should be_directory }
end
end

View file

@ -2,11 +2,12 @@
module Inspec
class Control
attr_accessor :id, :title, :desc, :impact, :tests, :tags, :refs
attr_accessor :id, :title, :descriptions, :impact, :tests, :tags, :refs
def initialize
@tests = []
@tags = []
@refs = []
@descriptions = {}
end
def add_test(t)
@ -18,13 +19,27 @@ module Inspec
end
def to_hash
{ id: id, title: title, desc: desc, impact: impact, tests: tests.map(&:to_hash), tags: tags.map(&:to_hash) }
{
id: id,
title: title,
descriptions: descriptions,
impact: impact,
tests: tests.map(&:to_hash),
tags: tags.map(&:to_hash),
}
end
def to_ruby # rubocop:disable Metrics/AbcSize
res = ["control #{id.inspect} do"]
res.push " title #{title.inspect}" unless title.to_s.empty?
res.push " desc #{prettyprint_text(desc, 2)}" unless desc.to_s.empty?
descriptions.each do |label, text|
if label == :default
next if text.nil? or text == '' # don't render empty/nil desc
res.push " desc #{prettyprint_text(text, 2)}"
else
res.push " desc #{label.to_s.inspect}, #{prettyprint_text(text, 2)}"
end
end
res.push " impact #{impact}" unless impact.nil?
tags.each { |t| res.push(indent(t.to_ruby, 2)) }
refs.each { |t| res.push(" ref #{print_ref(t)}") }

View file

@ -369,7 +369,7 @@ module Inspec
error.call(sfile, sline, nil, id, 'Avoid controls with empty IDs') if id.nil? or id.empty?
next if id.start_with? '(generated '
warn.call(sfile, sline, nil, id, "Control #{id} has no title") if control[:title].to_s.empty?
warn.call(sfile, sline, nil, id, "Control #{id} has no description") if control[:desc].to_s.empty?
warn.call(sfile, sline, nil, id, "Control #{id} has no descriptions") if control[:descriptions][:default].to_s.empty?
warn.call(sfile, sline, nil, id, "Control #{id} has impact > 1.0") if control[:impact].to_f > 1.0
warn.call(sfile, sline, nil, id, "Control #{id} has impact < 0.0") if control[:impact].to_f < 0.0
warn.call(sfile, sline, nil, id, "Control #{id} has no tests defined") if control[:checks].nil? or control[:checks].empty?
@ -561,6 +561,7 @@ module Inspec
controls[id] = {
title: rule.title,
desc: rule.desc,
descriptions: rule.descriptions,
impact: rule.impact,
refs: rule.ref,
tags: rule.tag,

View file

@ -60,7 +60,8 @@ module Inspec::Reporters
control = {
id: c[:id],
title: c[:title],
desc: c[:desc],
desc: c.dig(:descriptions, :default),
descriptions: convert_descriptions(c[:descriptions]),
impact: c[:impact],
refs: c[:refs],
tags: c[:tags],
@ -116,5 +117,14 @@ module Inspec::Reporters
end
profiles
end
def convert_descriptions(data)
return [] if data.nil?
results = []
data.each do |label, text|
results.push({ label: label.to_s, data: text })
end
results
end
end
end

View file

@ -32,7 +32,7 @@ module Inspec
def initialize(id, profile_id, opts, &block)
@impact = nil
@title = nil
@desc = nil
@descriptions = {}
@refs = []
@tags = {}
@ -89,9 +89,18 @@ module Inspec
@title
end
def desc(v = nil)
@desc = unindent(v) unless v.nil?
@desc
def desc(v = nil, data = nil)
return @descriptions[:default] if v.nil?
if data.nil?
@descriptions[:default] = unindent(v)
else
@descriptions[v.to_sym] = unindent(data)
end
end
def descriptions(description_hash = nil)
return @descriptions if description_hash.nil?
@descriptions.merge!(description_hash)
end
def ref(ref = nil, opts = {})
@ -221,11 +230,11 @@ module Inspec
return
end
# merge all fields
dst.impact(src.impact) unless src.impact.nil?
dst.title(src.title) unless src.title.nil?
dst.desc(src.desc) unless src.desc.nil?
dst.tag(src.tag) unless src.tag.nil?
dst.ref(src.ref) unless src.ref.nil?
dst.impact(src.impact) unless src.impact.nil?
dst.title(src.title) unless src.title.nil?
dst.descriptions(src.descriptions) unless src.descriptions.nil?
dst.tag(src.tag) unless src.tag.nil?
dst.ref(src.ref) unless src.ref.nil?
# merge indirect fields
# checks defined in the source will completely eliminate

View file

@ -167,7 +167,7 @@ module Inspec
metadata[:profile_id] = ::Inspec::Rule.profile_id(rule)
metadata[:impact] = rule.impact
metadata[:title] = rule.title
metadata[:desc] = rule.desc
metadata[:descriptions] = rule.descriptions
metadata[:code] = rule.instance_variable_get(:@__code)
metadata[:source_location] = rule.instance_variable_get(:@__source_location)
end

View file

@ -84,6 +84,7 @@ module Inspec
'id' => { 'type' => 'string' },
'title' => { 'type' => %w{string null} },
'desc' => { 'type' => %w{string null} },
'descriptions' => { 'type' => %w{array} },
'impact' => { 'type' => 'number' },
'refs' => REFS,
'tags' => TAGS,

View file

@ -73,7 +73,7 @@ describe 'inspec exec with json formatter' do
"license" => "Apache-2.0",
"summary" => "Demonstrates the use of InSpec Compliance Profile",
"version" => "1.0.0",
"sha256" => "c2416865d6da8cdeb4610442d6eac18be2737453e010d028cb901103fefebf6a",
"sha256" => "9ce86873d1e0c450ec739883dfe39828b481697f573304ad24c835885085b132",
"supports" => [{"platform-family" => "unix"}, {"platform-family"=>"windows"}],
"attributes" => []
})
@ -114,21 +114,14 @@ describe 'inspec exec with json formatter' do
result['start_time'].wont_be :nil?
actual.must_equal({
"id" => "tmp-1.0",
"title" => "Create /tmp directory",
"desc" => "An optional description...",
"impact" => 0.7,
"refs" => [
{
"url" => "http://...",
"ref" => "Document A-12"
}
],
"tags" => {
"data" => "temp data",
"security" => nil
},
"code" => "control \"tmp-1.0\" do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title \"Create /tmp directory\" # A human-readable title\n desc \"An optional description...\" # Describe why this is needed\n tag data: \"temp data\" # A tag allows you to associate key information\n tag \"security\" # to the test\n ref \"Document A-12\", url: 'http://...' # Additional references\n\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n",
"id"=>"tmp-1.0",
"title"=>"Create /tmp directory",
"desc"=>"An optional description...",
"descriptions"=>[{"label"=>"default", "data"=>"An optional description..."}, {"label"=>"label", "data"=>"An optional description with a label"}],
"impact"=>0.7,
"refs"=>[{"url"=>"http://...", "ref"=>"Document A-12"}],
"tags"=>{"data"=>"temp data", "security"=>nil},
"code"=>"control \"tmp-1.0\" do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title \"Create /tmp directory\" # A human-readable title\n desc \"An optional description...\" # Describe why this is needed\n desc \"label\", \"An optional description with a label\" # Pair a part of the description with a label\n tag data: \"temp data\" # A tag allows you to associate key information\n tag \"security\" # to the test\n ref \"Document A-12\", url: 'http://...' # Additional references\n\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n"
})
end
end

View file

@ -446,17 +446,28 @@ Test Summary: \e[38;5;41m2 successful\e[0m, 0 failures, 0 skipped\n"
controls.count.must_equal 2
# check for json override
assert = " control 'pro1-con2' do\n impact 0.999\n title 'Profile 1 - Control 2-updated'\n desc 'Profile 1 - Control 2 description-updated'\n tag 'password-updated'\n ref 'Section 3.5.2.1', url: 'https://example.com'\n describe file('/etc/passwd') do\n it { should exist }\n end\n end\n"
override['code'].must_equal assert
expected_value = " control 'pro1-con2' do\n impact 0.999\n title 'Profile 1 - Control 2-updated'\n desc 'Profile 1 - Control 2 description-updated'\n desc 'overwrite me', 'it is overwritten'\n desc 'new entry', 'this is appended to the description list'\n tag 'password-updated'\n ref 'Section 3.5.2.1', url: 'https://example.com'\n describe file('/etc/passwd') do\n it { should exist }\n end\n end\n"
override['code'].must_equal expected_value
override['impact'].must_equal 0.999
override['descriptions'].must_equal([
{ 'label' => 'default',
'data' => 'Profile 1 - Control 2 description-updated'
},
{ 'label' => 'overwrite me',
'data' => 'it is overwritten'
},
{ 'label' => 'new entry',
'data' => 'this is appended to the description list'
},
])
override['title'].must_equal "Profile 1 - Control 2-updated"
tags_assert = {"password"=>nil, "password-updated"=>nil}
override['tags'].must_equal tags_assert
child_profile['parent_profile'].must_equal 'wrapper-override'
# check for original code on child profile
assert = "control 'pro1-con2' do\n impact 0.9\n title 'Profile 1 - Control 2'\n desc 'Profile 1 - Control 2 description'\n tag 'password'\n describe file('/etc/passwdddddddddd') do\n it { should exist }\n end\nend\n"
child_control['code'].must_equal assert
expected_value = "control 'pro1-con2' do\n impact 0.9\n title 'Profile 1 - Control 2'\n desc 'Profile 1 - Control 2 description'\n desc 'overwrite me', 'overwrite this'\n tag 'password'\n describe file('/etc/passwdddddddddd') do\n it { should exist }\n end\nend\n"
child_control['code'].must_equal expected_value
end
end

View file

@ -22,22 +22,42 @@ describe 'controls' do
end
it 'adds a description' do
load("desc #{rand_string.inspect}")[:desc].must_equal rand_string
load("desc #{rand_string.inspect}")[:descriptions][:default].must_equal rand_string
end
it 'allows multiple desc with keys and values' do
lines = <<-DESC_EXAMPLES
desc 'this is default'
desc 'example', 'this is foo'
desc 'a space', 'this label has a space'
desc 'newline', 'this value has
a newline'
desc 'heredoc', <<-EOF
This is a heredoc
EOF
DESC_EXAMPLES
result = load(lines)
result[:descriptions][:default].must_equal('this is default')
result[:descriptions][:example].must_equal('this is foo')
result[:descriptions][:'a space'].must_equal('this label has a space')
result[:descriptions][:newline].must_match(/this value has\n\s*a newline/)
result[:descriptions][:heredoc].must_equal('This is a heredoc')
end
it 'adds a multiline description' do
t = rand_string + "\n" + rand_string
load("desc #{t.inspect}")[:desc].must_equal t
load("desc #{t.inspect}")[:descriptions][:default].must_equal t
end
it 'strips empty lines and spaces in description at start and end' do
t = " \n" + rand_string + "\n "
load("desc #{t.inspect}")[:desc].must_equal rand_string
load("desc #{t.inspect}")[:descriptions][:default].must_equal rand_string
end
it 'unindents properly' do
t = "\n #{rand_string}\n \n\t\t #{rand_string}\n "
load("desc #{t.inspect}")[:desc].must_equal "#{rand_string}\n \n #{rand_string}"
load("desc #{t.inspect}")[:descriptions][:default].must_equal "#{rand_string}\n \n #{rand_string}"
end
it 'works with empty refs' do

View file

@ -274,13 +274,19 @@ end
control.add_test(obj1)
control.id = 'sample.control.id'
control.title = 'Sample Control Important Title'
control.desc = 'The most critical control the world has ever seen'
control.descriptions = {
default: 'The most critical control the world has ever seen',
rationale: 'It is needed to save the planet',
'more info': 'Insert clever joke here',
}
control.refs = ['simple ref', {ref: 'title', url: 'my url'}]
control.impact = 1.0
control.to_ruby.must_equal '
control "sample.control.id" do
title "Sample Control Important Title"
desc "The most critical control the world has ever seen"
desc "rationale", "It is needed to save the planet"
desc "more info", "Insert clever joke here"
impact 1.0
ref "simple ref"
ref ({:ref=>"title", :url=>"my url"})
@ -293,7 +299,7 @@ end
it 'constructs a multiline desc in a control with indentation' do
control = Inspec::Control.new
control.desc = "Multiline\n control"
control.descriptions[:default] = "Multiline\n control"
control.to_ruby.must_equal '
control nil do
desc "
@ -311,16 +317,16 @@ control nil do
end
'.strip
control.desc = ''
control.descriptions[:default] = ''
control.to_ruby.must_equal x
control.desc = nil
control.descriptions[:default] = nil
control.to_ruby.must_equal x
end
it 'handles non-string descriptions' do
control = Inspec::Control.new
control.desc = 123
control.descriptions[:default] = 123
control.to_ruby.must_equal '
control nil do
desc "123"
@ -352,7 +358,7 @@ end
control.id = 'variable.control.id'
control.title = 'Variable Control Important Title'
control.desc = 'The most variable control the world has ever seen'
control.descriptions[:default] = 'The most variable control the world has ever seen'
control.impact = 1.0
control.to_ruby.must_equal '
control "variable.control.id" do
@ -441,7 +447,7 @@ end
control_hash = {
id:"tag.control.id",
title: nil,
desc: nil,
descriptions: {},
impact: nil,
tests: [],
tags:[{
@ -459,7 +465,6 @@ end
}]
}
control.to_hash.must_equal control_hash
end
end
end

View file

@ -0,0 +1,13 @@
# encoding: utf-8
control 'tmp-1.0' do
impact 0.7
title 'Create /tmp directory'
description 'Default description'
description rational: 'Rational for the metadata test control'
description 'something else': 'Even more metadata for the test control'
describe 'a thing' do
it { should cmp 'a thing' }
end
end

View file

@ -0,0 +1,8 @@
name: control_metadata
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.1.0

View file

@ -7,6 +7,8 @@ include_controls 'myprofile1' do
impact 0.999
title 'Profile 1 - Control 2-updated'
desc 'Profile 1 - Control 2 description-updated'
desc 'overwrite me', 'it is overwritten'
desc 'new entry', 'this is appended to the description list'
tag 'password-updated'
ref 'Section 3.5.2.1', url: 'https://example.com'
describe file('/etc/passwd') do

View file

@ -8,4 +8,4 @@ summary: Profile that wraps other profiles
version: 0.6.1
depends:
- name: myprofile1
url: https://s3-eu-west-1.amazonaws.com/apop-bucket/profiles/myprofile1-1.0.0.tar.gz
path: does_not_matter_check_vendor

View file

@ -13,6 +13,7 @@ control 'pro1-con2' do
impact 0.9
title 'Profile 1 - Control 2'
desc 'Profile 1 - Control 2 description'
desc 'overwrite me', 'overwrite this'
tag 'password'
describe file('/etc/passwdddddddddd') do
it { should exist }

View file

@ -1 +1 @@
{"platform":{"name":"mac_os_x","release":"17.5.0"},"profiles":[{"name":"wrapper-override","version":"0.6.1","sha256":"7436aac31d44de7987419d5f2ffb822f265645f4fc3c5d2ab37d8fff4dd5cf61","title":"Linux Wrapper Child Profile","maintainer":"Demo, Inc.","summary":"Profile that wraps other profiles","license":"Apache-2.0","copyright":"Demo, Inc.","copyright_email":"support@example.com","supports":[],"attributes":[],"depends":[{"name":"myprofile1z","url":"https://s3-eu-west-1.amazonaws.com/apop-bucket/profiles/myprofile1-1.0.0.tar.gz"}],"groups":[{"id":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb","controls":["pro1-con1","pro1-con2","pro1-con4"]}],"controls":[{"id":"pro1-con1","title":"Profile 1 - Control 1","desc":"Profile 1 - Control 1 description","impact":0.8,"refs":[],"tags":{"hosts":null,"file":null,"cce":"CCE-27072-8"},"code":"control 'pro1-con1' do\n impact 0.8\n title 'Profile 1 - Control 1'\n desc 'Profile 1 - Control 1 description'\n tag 'hosts','file'\n tag cce: 'CCE-27072-8'\n describe file('/etc/hosts') do\n its('mode') { should eq 0644 }\n end\nend\n","source_location":{"line":1,"ref":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb"},"results":[{"status":"passed","code_desc":"File /etc/hosts mode should eq 420","run_time":0.031503,"start_time":"2018-07-30T08:56:41-04:00"}]},{"id":"pro1-con2","title":"Profile 1 - Control 2-updated","desc":"Profile 1 - Control 2 description-updated","impact":0.999,"refs":[{"ref":[{"url":"https://example.com","ref":"Section 3.5.2.1"}]}],"tags":{"password":null,"password-updated":null},"code":" control 'pro1-con2' do\n impact 0.999\n title 'Profile 1 - Control 2-updated'\n desc 'Profile 1 - Control 2 description-updated'\n tag 'password-updated'\n ref 'Section 3.5.2.1', url: 'https://example.com'\n describe file('/etc/passwd') do\n it { should exist }\n end\n end\n","source_location":{"line":6,"ref":"wrapper-override/controls/defaut.rb"},"results":[{"status":"passed","code_desc":"File /etc/passwd should exist","run_time":0.003954,"start_time":"2018-07-30T08:56:41-04:00"}]},{"id":"pro1-con4","title":"Profile 1 - Control 3 - useless","desc":"Profile 1 - Control 3 description","impact":1,"refs":[],"tags":{},"code":"control 'pro1-con4' do\n impact 1\n title 'Profile 1 - Control 3 - useless'\n desc 'Profile 1 - Control 3 description'\n only_if do\n 1.eql?(0)\n end\n describe file('/tmp5') do\n it { should exist }\n end\nend\n","source_location":{"line":31,"ref":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb"},"results":[{"status":"skipped","code_desc":"Operating System Detection","run_time":2.9e-05,"start_time":"2018-07-30T08:56:41-04:00","resource":"Operating System Detection","skip_message":"Skipped control due to only_if condition."}]}]}],"statistics":{"duration":0.039182},"version":"2.2.26"}
{"platform":{"name":"mac_os_x","release":"17.5.0"},"profiles":[{"name":"wrapper-override","version":"0.6.1","sha256":"7436aac31d44de7987419d5f2ffb822f265645f4fc3c5d2ab37d8fff4dd5cf61","title":"Linux Wrapper Child Profile","maintainer":"Demo, Inc.","summary":"Profile that wraps other profiles","license":"Apache-2.0","copyright":"Demo, Inc.","copyright_email":"support@example.com","supports":[],"attributes":[],"depends":[{"name":"myprofile1z","url":"https://s3-eu-west-1.amazonaws.com/apop-bucket/profiles/myprofile1-1.0.0.tar.gz"}],"groups":[{"id":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb","controls":["pro1-con1","pro1-con2","pro1-con4"]}],"controls":[{"id":"pro1-con1","title":"Profile 1 - Control 1","desc":"Profile 1 - Control 1 description","descriptions":[{"label":"default","data":"Profile 1 - Control 1 description"}],"impact":0.8,"refs":[],"tags":{"hosts":null,"file":null,"cce":"CCE-27072-8"},"code":"control 'pro1-con1' do\n impact 0.8\n title 'Profile 1 - Control 1'\n desc 'Profile 1 - Control 1 description'\n tag 'hosts','file'\n tag cce: 'CCE-27072-8'\n describe file('/etc/hosts') do\n its('mode') { should eq 0644 }\n end\nend\n","source_location":{"line":1,"ref":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb"},"results":[{"status":"passed","code_desc":"File /etc/hosts mode should eq 420","run_time":0.031503,"start_time":"2018-07-30T08:56:41-04:00"}]},{"id":"pro1-con2","title":"Profile 1 - Control 2-updated","desc":"Profile 1 - Control 2 description-updated","descriptions":[{"label":"default","data":"Profile 1 - Control 2 description-updated"}],"impact":0.999,"refs":[{"ref":[{"url":"https://example.com","ref":"Section 3.5.2.1"}]}],"tags":{"password":null,"password-updated":null},"code":" control 'pro1-con2' do\n impact 0.999\n title 'Profile 1 - Control 2-updated'\n desc 'Profile 1 - Control 2 description-updated'\n tag 'password-updated'\n ref 'Section 3.5.2.1', url: 'https://example.com'\n describe file('/etc/passwd') do\n it { should exist }\n end\n end\n","source_location":{"line":6,"ref":"wrapper-override/controls/defaut.rb"},"results":[{"status":"passed","code_desc":"File /etc/passwd should exist","run_time":0.003954,"start_time":"2018-07-30T08:56:41-04:00"}]},{"id":"pro1-con4","title":"Profile 1 - Control 3 - useless","desc":"Profile 1 - Control 3 description","descriptions":[{"label":"default","data":"Profile 1 - Control 3 description"}],"impact":1,"refs":[],"tags":{},"code":"control 'pro1-con4' do\n impact 1\n title 'Profile 1 - Control 3 - useless'\n desc 'Profile 1 - Control 3 description'\n only_if do\n 1.eql?(0)\n end\n describe file('/tmp5') do\n it { should exist }\n end\nend\n","source_location":{"line":31,"ref":"/Users/jquick/.inspec/cache/e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477/controls/profile1.rb"},"results":[{"status":"skipped","code_desc":"Operating System Detection","run_time":2.9e-05,"start_time":"2018-07-30T08:56:41-04:00","resource":"Operating System Detection","skip_message":"Skipped control due to only_if condition."}]}]}],"statistics":{"duration":0.039182},"version":"2.2.26"}

View file

@ -1 +1 @@
{"platform":{"name":"mac_os_x","release":"17.2.0"},"profiles":[{"name":"long_commands","version":"0.1.0","sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4","title":"InSpec Profile","maintainer":"The Authors","summary":"An InSpec Compliance Profile","license":"Apache-2.0","copyright":"The Authors","copyright_email":"you@example.com","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"attributes":[],"groups":[{"id":"controls/example.rb","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"title":"sample section"},{"id":"controls/run_command.rb","controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"]}],"controls":[{"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"tmp-1.0","title":"Create /tmp directory","desc":"An optional description...","impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","source_location":{"line":12,"ref":"../inspec-demo/_test/long_commands/controls/example.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"failed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","message":"rubocop is not installed"}]},{"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500"}]}]}],"statistics":{"duration":0.039182},"version":"1.49.2"}
{"platform":{"name":"mac_os_x","release":"17.2.0"},"profiles":[{"name":"long_commands","version":"0.1.0","sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4","title":"InSpec Profile","maintainer":"The Authors","summary":"An InSpec Compliance Profile","license":"Apache-2.0","copyright":"The Authors","copyright_email":"you@example.com","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"attributes":[],"groups":[{"id":"controls/example.rb","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"title":"sample section"},{"id":"controls/run_command.rb","controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"]}],"controls":[{"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"tmp-1.0","title":"Create /tmp directory","desc":"An optional description...","descriptions":[{"label":"default","data":"An optional description..."}],"impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","source_location":{"line":12,"ref":"../inspec-demo/_test/long_commands/controls/example.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"failed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","message":"rubocop is not installed"}]},{"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500"}]}]}],"statistics":{"duration":0.039182},"version":"1.49.2"}

View file

@ -1 +1 @@
{"controls":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"},{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"},{"status":"passed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"gem package rubocop","expectation_message":"should be installed"},{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"stdout","expectation_message":"stdout should eq \"jquick\\n\""}],"other_checks":[],"profiles":[{"name":"long_commands","title":"InSpec Profile","maintainer":"The Authors","copyright":"The Authors","copyright_email":"you@example.com","license":"Apache-2.0","summary":"An InSpec Compliance Profile","version":"0.1.0","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"controls":[{"title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"}]},{"title":"Create /tmp directory","desc":"An optional description...","impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","source_location":{"ref":"../inspec-demo/_test/long_commands/controls/example.rb","line":12},"id":"tmp-1.0","results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"}]},{"title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","results":[{"status":"failed","message":"rubocop is not installed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"gem package rubocop","expectation_message":"should be installed"}]},{"title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"stdout","expectation_message":"stdout should eq \"jquick\\n\""}]}],"groups":[{"title":"sample section","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"id":"controls/example.rb"},{"title":null,"controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"],"id":"controls/run_command.rb"}],"attributes":[],"sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4"}],"platform":{"name":"mac_os_x","release":"17.2.0","target":"local://"},"version":"1.49.2","statistics":{"duration":0.039182}}
{"controls":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"},{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"},{"status":"passed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"gem package rubocop","expectation_message":"should be installed"},{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"stdout","expectation_message":"stdout should eq \"jquick\\n\""}],"other_checks":[],"profiles":[{"name":"long_commands","title":"InSpec Profile","maintainer":"The Authors","copyright":"The Authors","copyright_email":"you@example.com","license":"Apache-2.0","summary":"An InSpec Compliance Profile","version":"0.1.0","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"controls":[{"title":null,"desc":null,"descriptions":{},"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"}]},{"title":"Create /tmp directory","desc":"An optional description...","descriptions": { "default": "An optional description..."},"impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","source_location":{"ref":"../inspec-demo/_test/long_commands/controls/example.rb","line":12},"id":"tmp-1.0","results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"File /tmp","expectation_message":"should be directory"}]},{"title":null,"desc":null,"descriptions":{},"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","results":[{"status":"failed","message":"rubocop is not installed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"gem package rubocop","expectation_message":"should be installed"}]},{"title":null,"desc":null,"descriptions":{},"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb","line":89},"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500","resource_title":"stdout","expectation_message":"stdout should eq \"jquick\\n\""}]}],"groups":[{"title":"sample section","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"id":"controls/example.rb"},{"title":null,"controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"],"id":"controls/run_command.rb"}],"attributes":[],"sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4"}],"platform":{"name":"mac_os_x","release":"17.2.0","target":"local://"},"version":"1.49.2","statistics":{"duration":0.039182}}

File diff suppressed because one or more lines are too long

View file

@ -16,6 +16,7 @@
- :id: "(generated from t.rb:1 0aa70d93be7b0cf41b97a1363bb5e8b8)"
:title:
:desc:
:descriptions: []
:impact: 0.5
:refs: []
:tags: {}

View file

@ -15,7 +15,7 @@ describe Inspec::Reporters::Automate do
'job_uuid' => "22ad2f99-f84f-5456-95a0-jobuuid12345",
}
end
let(:report) do
let(:report) do
data = JSON.parse(File.read(path + '/../mock/reporters/run_data.json'), symbolize_names: true)
options.merge!({ run_data: data })
Inspec::Reporters::Automate.new(options)

View file

@ -84,6 +84,7 @@ describe Inspec::Reporters::Json do
id: '(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)',
title: nil,
desc: nil,
descriptions: [],
impact: 0.5,
refs: [],
tags: {},