From 1dbd72f924864430b2b8059542875fe904323535 Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Tue, 6 Apr 2021 07:03:53 -0400 Subject: [PATCH 01/10] Update gemspec to add roo Signed-off-by: Rony Xavier --- inspec-reporter-json-hdf.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inspec-reporter-json-hdf.gemspec b/inspec-reporter-json-hdf.gemspec index 6d8ec99..3114a16 100644 --- a/inspec-reporter-json-hdf.gemspec +++ b/inspec-reporter-json-hdf.gemspec @@ -18,6 +18,8 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '~> 2.5' spec.add_runtime_dependency 'git-lite-version-bump', '~> 0.17', '>= 0.17.3' + spec.add_runtime_dependency 'roo', '~> 2.8.3' + spec.add_development_dependency 'bundler' spec.add_development_dependency 'bundler-audit' spec.add_development_dependency 'codeclimate-test-reporter' From aee577a28f99b1dedb072215631d6a6b002a6007 Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Tue, 6 Apr 2021 07:04:33 -0400 Subject: [PATCH 02/10] Update plugin to get data from csv or xlsx; ignore entries with nil status Signed-off-by: Rony Xavier --- lib/inspec-reporter-json-hdf/reporter.rb | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/inspec-reporter-json-hdf/reporter.rb b/lib/inspec-reporter-json-hdf/reporter.rb index 64f802c..2392fca 100644 --- a/lib/inspec-reporter-json-hdf/reporter.rb +++ b/lib/inspec-reporter-json-hdf/reporter.rb @@ -1,6 +1,7 @@ require 'inspec/plugin/v2' require 'json' +require 'roo' VALID_FREQUENCY = %w[annually semiannually quarterly monthly every2weeks weekly every3days daily].freeze @@ -123,7 +124,44 @@ def valid_status?(status) def collect_attestations plugin_config = Inspec::Config.cached.fetch_plugin_config('inspec-reporter-json-hdf') - attestations = plugin_config['attestations'] || [] + attestations = [] + if plugin_config['include-attestations-file'] + if File.exist?(plugin_config['include-attestations-file']['path']) + if plugin_config['include-attestations-file']['type'].eql?('csv') + sheet = Roo::Spreadsheet.open(plugin_config['include-attestations-file']['path'], extension: :csv).sheet(0) + + attestations = sheet.parse(control_id: "Control_ID", + explanation: "Explanation", + frequency: "Frequency", + status: "Status", + updated: "Updated", + updated_by: "Updated_By", + clean:true + ) + elsif plugin_config['include-attestations-file']['type'].eql?('xlsx') + sheet = Roo::Spreadsheet.open(plugin_config['include-attestations-file']['path'], extension: :xlsx).sheet(0) + + attestations = sheet.parse(control_id: "Control_ID", + explanation: "Explanation", + frequency: "Frequency", + status: "Status", + updated: "Updated", + updated_by: "Updated_By", + clean:true + ) + attestations.map do |h| + h[:updated] = h[:updated].to_s + end + else + puts 'Warning: Invalid `include-attestations-file` type provided. Supported types: csv, xlsx' + end + else + puts "Warning: Include Attestation File provided '#{plugin_config['include-attestations-file']['path']}' not found." + end + end + attestations.map!{ |x| x.transform_keys(&:to_s) } + attestations = attestations + (plugin_config['attestations'] || []) + attestations.reject! { |x| x['status'].eql?("") || x['status'].nil? } if attestations.empty? puts 'Warning: Attestations not provided; HDF will be generated without attestations.' From 3e722b21f83d35258e5a2a11ce84d4244ef33607 Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Tue, 6 Apr 2021 07:05:09 -0400 Subject: [PATCH 03/10] Update test setup to test file based attestation feature Signed-off-by: Rony Xavier --- test/generate_attestation_file.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/generate_attestation_file.rb b/test/generate_attestation_file.rb index 0fbeed4..9bf03be 100644 --- a/test/generate_attestation_file.rb +++ b/test/generate_attestation_file.rb @@ -1,5 +1,6 @@ require 'json' require 'date' +require 'csv' DATE_FORMAT = '%Y-%m-%d'.freeze @@ -144,10 +145,21 @@ config_json = { 'plugins' => { 'inspec-reporter-json-hdf' => { - 'attestations' => attestations + 'include-attestations-file' => { + 'type' => 'csv', + 'path' => './attestations.csv' + }, + 'attestations' => attestations[0..6] } }, 'version' => '1.2' } File.write('attestations.json', config_json.to_json) + +CSV.open("attestations.csv", "wb") do |csv| + csv << ["Control_ID","Explanation","Frequency","Status","Updated","Updated_By"] + attestations[7..15].each do |hash| + csv << hash.values + end +end From 71fddd4ac4d25733f40b0e18005f9fd594db4184 Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Tue, 6 Apr 2021 08:34:55 -0400 Subject: [PATCH 04/10] Add template files Signed-off-by: Rony Xavier --- templates/attestations.config.template.json | 29 ++++++++++++++++++++ templates/attestations.template.xlsx | Bin 0 -> 10850 bytes 2 files changed, 29 insertions(+) create mode 100644 templates/attestations.config.template.json create mode 100644 templates/attestations.template.xlsx diff --git a/templates/attestations.config.template.json b/templates/attestations.config.template.json new file mode 100644 index 0000000..6f0b4a7 --- /dev/null +++ b/templates/attestations.config.template.json @@ -0,0 +1,29 @@ +{ + "plugins": { + "inspec-reporter-json-hdf": { + "include-attestations-file": { + "path": "./attestations.xlsx", + "type": "xlsx" + }, + "attestations": [ + { + "control_id": "test-control-1", + "explanation": "Non-expired Status passed", + "frequency": "annually", + "status": "passed", + "updated": "2021-04-06", + "updated_by": "John Doe, ISSO" + }, + { + "control_id": "test-control-2", + "explanation": "Non-expired Status passed", + "frequency": "semiannually", + "status": "passed", + "updated": "2021-04-06", + "updated_by": "John Doe, ISSO" + } + ] + } + }, + "version": "1.2" +} \ No newline at end of file diff --git a/templates/attestations.template.xlsx b/templates/attestations.template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2a56d1b639a885b11432ceea9fbec9a8c54291db GIT binary patch literal 10850 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 Date: Wed, 7 Apr 2021 14:39:28 -0400 Subject: [PATCH 05/10] Update to avoid using fractions to advance date; resolve issue in windwos Signed-off-by: Rony Xavier --- lib/inspec-reporter-json-hdf/reporter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/inspec-reporter-json-hdf/reporter.rb b/lib/inspec-reporter-json-hdf/reporter.rb index 2392fca..1a314d7 100644 --- a/lib/inspec-reporter-json-hdf/reporter.rb +++ b/lib/inspec-reporter-json-hdf/reporter.rb @@ -89,9 +89,9 @@ def advanced_date(date, frequency) when 'annually' parsed_date.next_year(1) when 'semiannually' - parsed_date.next_year(0.5) + parsed_date.next_month(6) when 'quarterly' - parsed_date.next_year(0.25) + parsed_date.next_month(3) when 'monthly' parsed_date.next_month(1) when 'every2weeks' From 7bf2dcf607481e8eb1148c46ef4b1cfd3cfb856e Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Wed, 7 Apr 2021 14:39:56 -0400 Subject: [PATCH 06/10] Better verbiage on template files Signed-off-by: Rony Xavier --- templates/attestations.config.template.json | 4 ++-- templates/attestations.template.xlsx | Bin 10850 -> 10889 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/attestations.config.template.json b/templates/attestations.config.template.json index 6f0b4a7..8d3c37b 100644 --- a/templates/attestations.config.template.json +++ b/templates/attestations.config.template.json @@ -8,7 +8,7 @@ "attestations": [ { "control_id": "test-control-1", - "explanation": "Non-expired Status passed", + "explanation": "The routine review through interview/examination attests to this control passing", "frequency": "annually", "status": "passed", "updated": "2021-04-06", @@ -16,7 +16,7 @@ }, { "control_id": "test-control-2", - "explanation": "Non-expired Status passed", + "explanation": "The routine review through interview/examination attests to this control passing", "frequency": "semiannually", "status": "passed", "updated": "2021-04-06", diff --git a/templates/attestations.template.xlsx b/templates/attestations.template.xlsx index 2a56d1b639a885b11432ceea9fbec9a8c54291db..cb14bcfa483d4f7a742ef895d5f389895a0d0ec7 100644 GIT binary patch delta 2846 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 Y{}%;;3Q2oPXIbDR9c3u{rs8k(U&OvLnE(I) delta 2804 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 From 9ddae75b8a5fe0901dec082aa4a870f9129b935b Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Wed, 7 Apr 2021 16:25:19 -0400 Subject: [PATCH 07/10] Updates to give inline attestation preference; code comments Signed-off-by: Rony Xavier --- lib/inspec-reporter-json-hdf/reporter.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/inspec-reporter-json-hdf/reporter.rb b/lib/inspec-reporter-json-hdf/reporter.rb index 1a314d7..c72ff4b 100644 --- a/lib/inspec-reporter-json-hdf/reporter.rb +++ b/lib/inspec-reporter-json-hdf/reporter.rb @@ -125,6 +125,8 @@ def valid_status?(status) def collect_attestations plugin_config = Inspec::Config.cached.fetch_plugin_config('inspec-reporter-json-hdf') attestations = [] + + # Parse Attestations from include file. if plugin_config['include-attestations-file'] if File.exist?(plugin_config['include-attestations-file']['path']) if plugin_config['include-attestations-file']['type'].eql?('csv') @@ -160,7 +162,12 @@ def collect_attestations end end attestations.map!{ |x| x.transform_keys(&:to_s) } - attestations = attestations + (plugin_config['attestations'] || []) + + # Merge inline Attestations from config file and `include file` with precedence to inline definitions. + attestations = (plugin_config['attestations'] || []) + attestations + attestations.uniq! {|e| e['control_id'] } + + # Remove Attestations records without status provided. attestations.reject! { |x| x['status'].eql?("") || x['status'].nil? } if attestations.empty? From 34c92a319ad47f86964494cc45add9d8aa976738 Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Wed, 7 Apr 2021 16:25:34 -0400 Subject: [PATCH 08/10] test code update Signed-off-by: Rony Xavier --- test/generate_attestation_file.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/generate_attestation_file.rb b/test/generate_attestation_file.rb index 9bf03be..59f3517 100644 --- a/test/generate_attestation_file.rb +++ b/test/generate_attestation_file.rb @@ -149,7 +149,7 @@ 'type' => 'csv', 'path' => './attestations.csv' }, - 'attestations' => attestations[0..6] + 'attestations' => attestations[0..4] } }, 'version' => '1.2' @@ -159,7 +159,7 @@ CSV.open("attestations.csv", "wb") do |csv| csv << ["Control_ID","Explanation","Frequency","Status","Updated","Updated_By"] - attestations[7..15].each do |hash| + attestations[5..15].each do |hash| csv << hash.values end end From 8b3a013aafba7372762d1112e20ca037cca4ccdc Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Fri, 9 Apr 2021 07:11:38 -0400 Subject: [PATCH 09/10] Fixes #14 Attestation status pattern redesign Code cleanup Signed-off-by: Rony Xavier --- lib/inspec-reporter-json-hdf/reporter.rb | 110 ++++++++++------------- 1 file changed, 45 insertions(+), 65 deletions(-) diff --git a/lib/inspec-reporter-json-hdf/reporter.rb b/lib/inspec-reporter-json-hdf/reporter.rb index c72ff4b..67e570a 100644 --- a/lib/inspec-reporter-json-hdf/reporter.rb +++ b/lib/inspec-reporter-json-hdf/reporter.rb @@ -9,6 +9,8 @@ DATE_FORMAT = '%Y-%m-%d'.freeze +SUPPORTED_INCLUDE_TYPES = %w[csv xlsx].freeze + module InspecPlugins::HdfReporter # Reporter Plugin Class class Reporter < Inspec.plugin(2, :reporter) @@ -42,40 +44,24 @@ def report private def apply_attestation(results, attestation) - if results.empty? - results = [{ - "code_desc": 'Manually verified Status provided through attestation', - "run_time": 0.0, - "start_time": DateTime.now.to_s, - "status": attestation['status'], - "message": attestation_message(attestation) - }] - else - results.each do |result| - result[:message] = 'Automated test returned as passed.' if result[:status].eql?('passed') - result[:message] = result[:skip_message] if result[:status].eql?('skipped') - - result[:status] = attestation['status'] - result[:message] = result[:message] + attestation_message(attestation) - - if result[:backtrace] - result[:message] = result[:message] + "\nbacktrace: #{result[:backtrace]}" - result[:backtrace] = nil - end - end - end - results + results << { + "code_desc": 'Manually verified Status provided through attestation', + "run_time": 0.0, + "start_time": DateTime.now.to_s, + "status": attestation['status'], + "message": attestation_message(attestation) + } end def attestation_message(attestation) - " - Attestation: - Status: #{attestation['status']} - Explanation: #{attestation['explanation']} - Updated: #{attestation['updated']} - Updated By: #{attestation['updated_by']} - Frequency: #{attestation['frequency']} - " + [ + 'Attestation:', + "Status: #{attestation['status']}", + "Explanation: #{attestation['explanation']}", + "Updated: #{attestation['updated']}", + "Updated By: #{attestation['updated_by']}", + "Frequency: #{attestation['frequency']}", + ].join("\n") end def attestation_expired?(date, frequency) @@ -122,45 +108,39 @@ def valid_status?(status) status.is_a?(String) && VALID_STATUSES.include?(status.downcase) end + def parse_include_file(include_file) + if File.exist?(include_file['path']) + if SUPPORTED_INCLUDE_TYPES.include?(include_file['type']) + sheet = Roo::Spreadsheet.open(include_file['path'], extension: include_file['type'].to_sym ).sheet(0) + + attestations = sheet.parse(control_id: "Control_ID", + explanation: "Explanation", + frequency: "Frequency", + status: "Status", + updated: "Updated", + updated_by: "Updated_By", + clean:true + ) + # Following is required to convert Datetime field returned by xlsx parser to string + attestations.map do |h| + h[:updated] = h[:updated].to_s + end + else + puts "Warning: Invalid `include-attestations-file` type provided. Supported types: #{SUPPORTED_INCLUDE_TYPES.to_s}" + end + else + puts "Warning: Include Attestation File provided '#{include_file['path']}' not found." + end + attestations || [] + end + def collect_attestations plugin_config = Inspec::Config.cached.fetch_plugin_config('inspec-reporter-json-hdf') attestations = [] # Parse Attestations from include file. - if plugin_config['include-attestations-file'] - if File.exist?(plugin_config['include-attestations-file']['path']) - if plugin_config['include-attestations-file']['type'].eql?('csv') - sheet = Roo::Spreadsheet.open(plugin_config['include-attestations-file']['path'], extension: :csv).sheet(0) - - attestations = sheet.parse(control_id: "Control_ID", - explanation: "Explanation", - frequency: "Frequency", - status: "Status", - updated: "Updated", - updated_by: "Updated_By", - clean:true - ) - elsif plugin_config['include-attestations-file']['type'].eql?('xlsx') - sheet = Roo::Spreadsheet.open(plugin_config['include-attestations-file']['path'], extension: :xlsx).sheet(0) - - attestations = sheet.parse(control_id: "Control_ID", - explanation: "Explanation", - frequency: "Frequency", - status: "Status", - updated: "Updated", - updated_by: "Updated_By", - clean:true - ) - attestations.map do |h| - h[:updated] = h[:updated].to_s - end - else - puts 'Warning: Invalid `include-attestations-file` type provided. Supported types: csv, xlsx' - end - else - puts "Warning: Include Attestation File provided '#{plugin_config['include-attestations-file']['path']}' not found." - end - end + attestations = parse_include_file(plugin_config['include-attestations-file']) if plugin_config['include-attestations-file'] + attestations.map!{ |x| x.transform_keys(&:to_s) } # Merge inline Attestations from config file and `include file` with precedence to inline definitions. From 616cf320499fa6d76bfc0d377b14c8deb71eeccf Mon Sep 17 00:00:00 2001 From: Rony Xavier Date: Fri, 9 Apr 2021 07:12:37 -0400 Subject: [PATCH 10/10] Update func test to match updates Signed-off-by: Rony Xavier --- .../inspec_plugin_functional_test.rb | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/test/functional/inspec_plugin_functional_test.rb b/test/functional/inspec_plugin_functional_test.rb index af6fff3..8acb550 100644 --- a/test/functional/inspec_plugin_functional_test.rb +++ b/test/functional/inspec_plugin_functional_test.rb @@ -4,97 +4,103 @@ class InspecPluginFunctionalTest < Minitest::Test def test_with_a_single_pass_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('passed', hdf_json['profiles'][0]['controls'][0]['results'][0]['status']) - assert_match(%r(Automated test returned as passed.\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][0]['results'][0]['message']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][0]['results'][1]['status']) + + message = hdf_json['profiles'][0]['controls'][0]['results'][1]['message'] + assert_match(%r(Attestation:), message) + assert_match(%r(Status: passed), message) + assert_match(%r(Explanation: Non-expired Status passed), message) + assert_match(%r(Updated By: John Doe, ISSO), message) + assert_match(%r(Frequency: annually), message) refute_nil(hdf_json['profiles'][0]['controls'][0]['attestation']) end - def test_with_a_multiple_pass_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('passed', hdf_json['profiles'][0]['controls'][1]['results'][0]['status']) assert_equal('passed', hdf_json['profiles'][0]['controls'][1]['results'][1]['status']) - assert_match(%r(Automated test returned as passed.\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][1]['results'][0]['message']) - assert_match(%r(Automated test returned as passed.\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][1]['results'][1]['message']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][1]['results'][2]['status']) refute_nil(hdf_json['profiles'][0]['controls'][1]['attestation']) end def test_with_a_single_fail_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) - assert_equal('passed', hdf_json['profiles'][0]['controls'][2]['results'][0]['status']) - assert_match(%r(\nexpected false\n got true\n\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][2]['results'][0]['message']) + assert_equal('failed', hdf_json['profiles'][0]['controls'][2]['results'][0]['status']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][2]['results'][1]['status']) refute_nil(hdf_json['profiles'][0]['controls'][2]['attestation']) end def test_with_a_multiple_fail_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) - assert_equal('passed', hdf_json['profiles'][0]['controls'][3]['results'][0]['status']) - assert_equal('passed', hdf_json['profiles'][0]['controls'][3]['results'][1]['status']) - assert_match(%r(\nexpected false\n got true\n\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][3]['results'][0]['message']) - assert_match(%r(\nexpected true\n got false\n\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][3]['results'][1]['message']) + assert_equal('failed', hdf_json['profiles'][0]['controls'][3]['results'][0]['status']) + assert_equal('failed', hdf_json['profiles'][0]['controls'][3]['results'][1]['status']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][3]['results'][2]['status']) refute_nil(hdf_json['profiles'][0]['controls'][3]['attestation']) end def test_with_a_single_skip_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) - assert_equal('passed', hdf_json['profiles'][0]['controls'][4]['results'][0]['status']) - assert_match(%r(Manual Test\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][4]['results'][0]['message']) + assert_equal('skipped', hdf_json['profiles'][0]['controls'][4]['results'][0]['status']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][4]['results'][1]['status']) refute_nil(hdf_json['profiles'][0]['controls'][4]['attestation']) end def test_with_a_multiple_skip_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) - assert_equal('passed', hdf_json['profiles'][0]['controls'][5]['results'][0]['status']) - assert_equal('passed', hdf_json['profiles'][0]['controls'][5]['results'][1]['status']) - assert_match(%r(Manual Test2\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][5]['results'][0]['message']) - assert_match(%r(Manual Test2\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][5]['results'][1]['message']) + assert_equal('skipped', hdf_json['profiles'][0]['controls'][5]['results'][0]['status']) + assert_equal('skipped', hdf_json['profiles'][0]['controls'][5]['results'][1]['status']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][5]['results'][2]['status']) refute_nil(hdf_json['profiles'][0]['controls'][5]['attestation']) end def test_with_a_mixed_statuses_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) - assert_equal('passed', hdf_json['profiles'][0]['controls'][6]['results'][0]['status']) + assert_equal('skipped', hdf_json['profiles'][0]['controls'][6]['results'][0]['status']) assert_equal('passed', hdf_json['profiles'][0]['controls'][6]['results'][1]['status']) - assert_equal('passed', hdf_json['profiles'][0]['controls'][6]['results'][2]['status']) - assert_match(%r(Manual Test\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][6]['results'][0]['message']) - assert_match(%r(Automated test returned as passed.\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][6]['results'][1]['message']) - assert_match(%r(\nexpected false\n got true\n\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][6]['results'][2]['message']) + assert_equal('failed', hdf_json['profiles'][0]['controls'][6]['results'][2]['status']) + assert_equal('passed', hdf_json['profiles'][0]['controls'][6]['results'][3]['status']) refute_nil(hdf_json['profiles'][0]['controls'][6]['attestation']) end def test_with_a_no_statuses_non_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('passed', hdf_json['profiles'][0]['controls'][7]['results'][0]['status']) - assert_match(%r(\n Attestation:\n Status: passed\n Explanation: Non-expired Status passed\n), hdf_json['profiles'][0]['controls'][7]['results'][0]['message']) refute_nil(hdf_json['profiles'][0]['controls'][7]['attestation']) end def test_with_a_single_pass_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('passed', hdf_json['profiles'][0]['controls'][8]['results'][0]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][8]['results'][1]) refute_nil(hdf_json['profiles'][0]['controls'][8]['attestation']) end def test_with_a_multiple_pass_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('passed', hdf_json['profiles'][0]['controls'][9]['results'][0]['status']) assert_equal('passed', hdf_json['profiles'][0]['controls'][9]['results'][1]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][9]['results'][2]) refute_nil(hdf_json['profiles'][0]['controls'][9]['attestation']) end def test_with_a_single_fail_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('failed', hdf_json['profiles'][0]['controls'][10]['results'][0]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][10]['results'][1]) refute_nil(hdf_json['profiles'][0]['controls'][10]['attestation']) end def test_with_a_multiple_fail_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('failed', hdf_json['profiles'][0]['controls'][11]['results'][0]['status']) assert_equal('failed', hdf_json['profiles'][0]['controls'][11]['results'][1]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][11]['results'][2]) refute_nil(hdf_json['profiles'][0]['controls'][11]['attestation']) end def test_with_a_single_skip_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('skipped', hdf_json['profiles'][0]['controls'][12]['results'][0]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][12]['results'][1]) refute_nil(hdf_json['profiles'][0]['controls'][12]['attestation']) end def test_with_a_multiple_skip_expired_attestation hdf_json = JSON.parse(File.read('test_hdf.json')) assert_equal('skipped', hdf_json['profiles'][0]['controls'][13]['results'][0]['status']) assert_equal('skipped', hdf_json['profiles'][0]['controls'][13]['results'][1]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][13]['results'][2]) refute_nil(hdf_json['profiles'][0]['controls'][12]['attestation']) end def test_with_a_mixed_statuses_expired_attestation @@ -102,6 +108,7 @@ def test_with_a_mixed_statuses_expired_attestation assert_equal('skipped', hdf_json['profiles'][0]['controls'][14]['results'][0]['status']) assert_equal('passed', hdf_json['profiles'][0]['controls'][14]['results'][1]['status']) assert_equal('failed', hdf_json['profiles'][0]['controls'][14]['results'][2]['status']) + assert_nil(hdf_json['profiles'][0]['controls'][14]['results'][3]) refute_nil(hdf_json['profiles'][0]['controls'][14]['attestation']) end def test_with_a_no_statuses_expired_attestation