Waivers Feedback - Per control reporting and other minor issues (#4567)

Waivers Feedback - Per control reporting and other minor issues
This commit is contained in:
Clinton Wolfe 2019-10-10 13:39:18 -07:00 committed by GitHub
commit a04142d034
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 278 additions and 70 deletions

View file

@ -26,13 +26,13 @@ Waiver files are [input files](https://www.inspec.io/docs/reference/inputs/) wit
```yaml
control_id:
expiration_date: YYYY-MM-DD
skip: true
run: false
justification: "reason for waiving this control"
```
+ `expiration_date` is optional. Absence means the waiver is permanent.
+ `skip` is optional. Absence means the control will run and be
reported, but failures in it won't make the overall run fail.
+ `run` is optional. If present and true, the control will run and be
reported, but failures in it won't make the overall run fail. If absent or false, the control will not be run. You may use any of yes, no, true or false.
+ `justification` can be any text you want and might include a reason
as well as who signed off on the waiver.
@ -46,5 +46,5 @@ waiver_control_1_2_3:
xccdf_org.cisecurity.benchmarks_rule_1.1.1.4_Ensure_mounting_of_hfs_filesystems_is_disabled:
expiry_date: 2020-03-01
justification: "This might be a bug in the test. @qateam"
skip_run: true
run: false
```

View file

@ -259,6 +259,11 @@ module Inspec::Formatters
example.delete(:id)
example.delete(:profile_id)
control[:results].push(example)
# Waiver data, if available, is internally stored on a per-result
# (that is, per-describe-block) basis, because that is the only granularity
# available to us in the RSpec report data structure which we use as a vehicle.
control[:waiver_data] ||= example[:waiver_data] || {}
end
end
end

View file

@ -40,7 +40,6 @@ module Inspec::Reporters
message: r[:message],
exception: r[:exception],
backtrace: r[:backtrace],
waiver_data: r[:waiver_data],
}.reject { |_k, v| v.nil? }
}
end
@ -96,6 +95,7 @@ module Inspec::Reporters
line: c[:source_location][:line],
ref: c[:source_location][:ref],
},
waiver_data: c[:waiver_data] || {},
results: profile_results(c),
}
}

View file

@ -297,11 +297,11 @@ module Inspec
__waiver_data["skipped_due_to_waiver"] = false
__waiver_data["message"] = ""
# Waivers should have a hash value with keys possibly including skip and
# expiration_date. We only care here if it has a skip key and it
# is yes-like, since all non-skipped waiver operations are handled
# Waivers should have a hash value with keys possibly including "run" and
# expiration_date. We only care here if it has a "run" key and it
# is false-like, since all non-skipped waiver operations are handled
# during reporting phase.
return unless __waiver_data.key?("skip") && __waiver_data["skip"]
return unless __waiver_data.key?("run") && !__waiver_data["run"]
# OK, the intent is to skip. Does it have an expiration date, and
# if so, is it in the future?

View file

@ -96,6 +96,16 @@ module Inspec
},
},
"results" => { "type" => "array", "items" => RESULT },
"waiver_data" => {
"type" => "object",
"properties" => {
"skipped_due_to_waiver" => { "type" => "string" },
"run" => { "type" => "boolean" },
"message" => { "type" => "string" },
"expiration_date" => { "type" => "string" },
"justification" => { "type" => "string" },
},
},
},
}.freeze

View file

@ -1,17 +1,16 @@
require "functional/helper"
require "json-schema"
require "inspec/schema"
describe "inspec exec with json formatter" do
include FunctionalHelper
let(:schema) { Inspec::Schema.json("exec-json") }
parallelize_me!
it "can execute a simple file and validate the json schema" do
out = inspec("exec " + example_control + " --reporter json --no-create-lockfile")
data = JSON.parse(out.stdout)
sout = inspec("schema exec-json")
schema = JSON.parse(sout.stdout)
_(JSON::Validator.validate(schema, data)).wont_equal false
_(out.stderr).must_equal ""
@ -22,10 +21,7 @@ describe "inspec exec with json formatter" do
it "can execute a profile and validate the json schema" do
out = inspec("exec " + example_profile + " --reporter json --no-create-lockfile")
data = JSON.parse(out.stdout)
sout = inspec("schema exec-json")
schema = JSON.parse(sout.stdout)
_(JSON::Validator.validate(schema, data)).wont_equal false
_(out.stderr).must_equal ""
@ -36,8 +32,6 @@ describe "inspec exec with json formatter" do
it "can execute a simple file while using end of options after reporter cli option" do
out = inspec("exec --no-create-lockfile --reporter json -- " + example_control)
data = JSON.parse(out.stdout)
sout = inspec("schema exec-json")
schema = JSON.parse(sout.stdout)
_(JSON::Validator.validate(schema, data)).wont_equal false
_(out.stderr).must_equal ""
@ -50,8 +44,6 @@ describe "inspec exec with json formatter" do
out = inspec("exec " + example_profile + " --reporter json --no-create-lockfile --target-id 1d3e399f-4d71-4863-ac54-84d437fbc444")
data = JSON.parse(out.stdout)
_(data["platform"]["target_id"]).must_equal "1d3e399f-4d71-4863-ac54-84d437fbc444"
sout = inspec("schema exec-json")
schema = JSON.parse(sout.stdout)
_(JSON::Validator.validate(schema, data)).wont_equal false
_(out.stderr).must_equal ""
@ -224,6 +216,7 @@ describe "inspec exec with json formatter" do
"refs" => [{ "url" => "http://...", "ref" => "Document A-12" }],
"tags" => { "data" => "temp data", "security" => nil },
"code" => example_rb_code,
"waiver_data" => {},
})
end
end

View file

@ -20,7 +20,7 @@ describe "waivers" do
end
def waiver_data(control_id)
controls_by_id.dig(control_id, "results", 0, "waiver_data")
controls_by_id.dig(control_id, "waiver_data")
end
def assert_waiver_annotation(control_id)
@ -30,24 +30,26 @@ describe "waivers" do
expiry = !!(control_id !~ /no_expiry/)
in_past = !!(control_id =~ /in_past/)
in_future = !!(control_id =~ /in_future/)
skipped = !!(control_id !~ /not_skipped/)
ran = !!(control_id !~ /not_ran/)
# higher logic
waived = (!expiry && skipped) || (expiry && skipped && in_future)
waived = (!expiry && !ran) || (expiry && !ran && in_future)
# TODO: wasn't message was originally specced as being optional?
has_message = expiry && skipped && in_past
has_message = expiry && !ran && in_past
assert_instance_of Hash, act
assert_stringy act["justification"] # TODO: optional?
assert_equal skipped, act["skip"]
assert_equal ran, act["run"]
assert_equal waived, act["skipped_due_to_waiver"]
assert_stringy act["message"] if has_message
assert_equal "", act["message"] unless has_message
end
def refute_waiver_annotation(control_id)
assert_nil waiver_data control_id
act = waiver_data control_id
assert_instance_of Hash, act
assert_empty act
end
def assert_skip_message(yea, nay)
@ -64,15 +66,15 @@ describe "waivers" do
{
"01_not_waivered_passes" => "passed",
"02_not_waivered_fails" => "failed",
"03_waivered_no_expiry_not_skipped_passes" => "passed",
"04_waivered_no_expiry_not_skipped_fails" => "failed",
"05_waivered_no_expiry_skipped" => "skipped",
"06_waivered_expiry_in_past_not_skipped_passes" => "passed",
"07_waivered_expiry_in_past_not_skipped_fails" => "failed",
"08_waivered_expiry_in_past_skipped" => "passed",
"09_waivered_expiry_in_future_not_skipped_passes" => "passed",
"10_waivered_expiry_in_future_not_skipped_fails" => "failed",
"11_waivered_expiry_in_future_skipped" => "skipped",
"03_waivered_no_expiry_ran_passes" => "passed",
"04_waivered_no_expiry_ran_fails" => "failed",
"05_waivered_no_expiry_not_ran" => "skipped",
"06_waivered_expiry_in_past_ran_passes" => "passed",
"07_waivered_expiry_in_past_ran_fails" => "failed",
"08_waivered_expiry_in_past_not_ran" => "passed",
"09_waivered_expiry_in_future_ran_passes" => "passed",
"10_waivered_expiry_in_future_ran_fails" => "failed",
"11_waivered_expiry_in_future_not_ran" => "skipped",
}.each do |control_id, expected|
it "has all of the expected outcomes #{control_id}" do
assert_test_outcome expected, control_id
@ -86,7 +88,30 @@ describe "waivers" do
end
end
# describe "an inherited profile"
describe "an inherited profile" do
let(:profile_name) { "waiver-wrapper" }
let(:waiver_file) { "waivers.yaml" }
it "should set the data in the child but be empty in the wrapper" do
json = run_result.payload.json
child_profile = json["profiles"].detect { |p| p["name"] == "waiver-child" }
child_waiver_data = child_profile.dig("controls", 0, "waiver_data")
assert_instance_of Hash, child_waiver_data
refute_empty child_waiver_data
expected_child_waiver_data = {
"run" => false,
"justification" => "I said so",
"skipped_due_to_waiver" => true,
"message" => "",
}
assert_equal expected_child_waiver_data, child_waiver_data
wrapper_profile = json["profiles"].detect { |p| p["name"] == "waiver-wrapper" }
wrapper_waiver_data = wrapper_profile.dig("controls", 0, "waiver_data")
assert_instance_of Hash, wrapper_waiver_data
assert_empty wrapper_waiver_data
end
end
# describe "a profile whose control ids require transformation"
describe "a waiver file with invalid dates" do

View file

@ -6,38 +6,38 @@ control "02_not_waivered_fails" do
describe(true) { it { should eq false } }
end
control "03_waivered_no_expiry_not_skipped_passes" do
control "03_waivered_no_expiry_ran_passes" do
describe(true) { it { should eq true } }
end
control "04_waivered_no_expiry_not_skipped_fails" do
control "04_waivered_no_expiry_ran_fails" do
describe(true) { it { should eq false } }
end
control "05_waivered_no_expiry_skipped" do
control "05_waivered_no_expiry_not_ran" do
describe(true) { it { should eq true } }
end
control "06_waivered_expiry_in_past_not_skipped_passes" do
control "06_waivered_expiry_in_past_ran_passes" do
describe(true) { it { should eq true } }
end
control "07_waivered_expiry_in_past_not_skipped_fails" do
control "07_waivered_expiry_in_past_ran_fails" do
describe(true) { it { should eq false } }
end
control "08_waivered_expiry_in_past_skipped" do
control "08_waivered_expiry_in_past_not_ran" do
describe(true) { it { should eq true } }
end
control "09_waivered_expiry_in_future_not_skipped_passes" do
control "09_waivered_expiry_in_future_ran_passes" do
describe(true) { it { should eq true } }
end
control "10_waivered_expiry_in_future_not_skipped_fails" do
control "10_waivered_expiry_in_future_ran_fails" do
describe(true) { it { should eq false } }
end
control "11_waivered_expiry_in_future_skipped" do
control "11_waivered_expiry_in_future_not_ran" do
describe(true) { it { should eq true } }
end

View file

@ -1,41 +1,41 @@
03_waivered_no_expiry_not_skipped_passes:
03_waivered_no_expiry_ran_passes:
justification: Sound reasoning
skip: no
run: true
04_waivered_no_expiry_not_skipped_fails:
04_waivered_no_expiry_ran_fails:
justification: Unassailable thinking
skip: no
run: true
05_waivered_no_expiry_skipped:
05_waivered_no_expiry_not_ran:
justification: Sheer cleverness
skip: yes
run: false
06_waivered_expiry_in_past_not_skipped_passes:
06_waivered_expiry_in_past_ran_passes:
expiration_date: 1977-06-01
justification: Necessity
skip: no
run: true
07_waivered_expiry_in_past_not_skipped_fails:
07_waivered_expiry_in_past_ran_fails:
expiration_date: 1977-06-01
justification: Whimsy
skip: no
run: true
08_waivered_expiry_in_past_skipped:
08_waivered_expiry_in_past_not_ran:
expiration_date: 1977-06-01
justification: Contrariness
skip: yes
run: false
09_waivered_expiry_in_future_not_skipped_passes:
09_waivered_expiry_in_future_ran_passes:
expiration_date: 2077-06-01
justification: Handwaving
skip: no
run: true
10_waivered_expiry_in_future_not_skipped_fails:
10_waivered_expiry_in_future_ran_fails:
expiration_date: 2077-06-01
justification: Didn't feel like it
skip: no
run: true
11_waivered_expiry_in_future_skipped:
11_waivered_expiry_in_future_not_ran:
expiration_date: 2077-06-01
justification: Lack of imagination
skip: yes
run: false

View file

@ -1,3 +1,3 @@
01_only_if:
skip: true
run: false
justification: test_message_from_waiver

View file

@ -1,4 +1,4 @@
01_small:
expiration_date: never
skip: true
run: false
justification: Callous disregard

View file

@ -0,0 +1,5 @@
control "waiver-child-01" do
describe true do
it { should cmp true }
end
end

View file

@ -0,0 +1,4 @@
name: waiver-child
version: 0.1.0
supports:
platform: os

View file

@ -0,0 +1 @@
include_controls "waiver-child"

View file

@ -0,0 +1,3 @@
waiver-child-01:
run: no
justification: I said so

View file

@ -0,0 +1,9 @@
name: waiver-wrapper
license: Apache-2.0
summary: Verify waiver behavior under inheritance
version: 0.1.0
supports:
platform: os
depends:
- name: waiver-child
path: ../waiver-child

View file

@ -1 +1,145 @@
{"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"}
{
"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"
},
"waiver_data": {},
"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"
},
"waiver_data": {},
"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"
},
"waiver_data": {},
"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,"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"}
{"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"},"waiver_data":{},"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","waiver_data":{},"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":"","waiver_data":{},"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":"","waiver_data":{},"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,"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}}
{"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"}],"waiver_data":{}},{"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"}],"waiver_data":{}},{"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"}],"waiver_data":{}},{"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\""}],"waiver_data":{}}],"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}}

View file

@ -28,6 +28,7 @@
:code_desc: File /tmp should exist
:run_time: 0.001313935
:start_time: '2018-05-31T16:22:19+05:30'
:waiver_data: {}
:statistics:
:duration: 0.002678506
:version: 2.1.83

File diff suppressed because one or more lines are too long

View file

@ -24,6 +24,7 @@
:source_location:
:line: 89
:ref: "/home/frezbo/git/work/ruby/inspec/lib/inspec/control_eval_context.rb"
:waiver_data: {}
:results:
- :status: passed
:code_desc: File /tmp should exist

View file

@ -2,6 +2,8 @@ require "helper"
require "inspec/reporters"
describe Inspec::Reporters::JsonAutomate do
make_my_diffs_pretty!
let(:path) { File.expand_path(File.dirname(__FILE__)) }
let(:report) do
data = JSON.parse(File.read(path + "/../mock/reporters/run_data_wrapper.json"), symbolize_names: true)
@ -12,8 +14,12 @@ describe Inspec::Reporters::JsonAutomate do
describe "#render" do
it "confirms render output" do
output = File.read(path + "/../mock/reporters/json_merged_output")
output = JSON.parse(output, symbolize_names: true)
report.render
_(report.rendered_output).must_equal output
actual = JSON.parse(report.rendered_output, symbolize_names: true)
_(actual).must_equal output
end
end

View file

@ -14,7 +14,7 @@ describe Inspec::Reporters::Json do
it "confirm render output" do
output = File.read(path + "/../mock/reporters/json_output")
report.render
_(report.rendered_output).must_equal output
_(JSON.parse(report.rendered_output)).must_equal JSON.parse(output)
end
end
@ -92,6 +92,7 @@ describe Inspec::Reporters::Json do
line: 89,
ref: "/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb",
},
waiver_data: {},
}
control = report.send(:profile_controls, profile).first
control.delete(:results)