From 545dcb1c752a4f415b226a98491c96c7540f693d Mon Sep 17 00:00:00 2001 From: Ondrej Prazak Date: Thu, 28 Nov 2019 14:23:07 +0100 Subject: [PATCH 1/3] Parse fixes --- lib/openscap_parser/fix.rb | 35 +++++++++++++++ lib/openscap_parser/fixes.rb | 21 +++++++++ lib/openscap_parser/rule.rb | 2 + lib/openscap_parser/rule_result.rb | 10 +++++ lib/openscap_parser/sub.rb | 18 ++++++++ lib/openscap_parser/subs.rb | 20 +++++++++ test/openscap_parser/test_result_file_test.rb | 44 +++++++++++++++++++ 7 files changed, 150 insertions(+) create mode 100644 lib/openscap_parser/fix.rb create mode 100644 lib/openscap_parser/fixes.rb create mode 100644 lib/openscap_parser/sub.rb create mode 100644 lib/openscap_parser/subs.rb diff --git a/lib/openscap_parser/fix.rb b/lib/openscap_parser/fix.rb new file mode 100644 index 0000000..fd690b0 --- /dev/null +++ b/lib/openscap_parser/fix.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true +require 'openscap_parser/xml_node' +require 'openscap_parser/subs' + +module OpenscapParser + class Fix < XmlNode + include OpenscapParser::Subs + + def id + @id ||= @parsed_xml['id'] + end + + def system + @system ||= @parsed_xml['system'] + end + + def complexity + @complexity ||= @parsed_xml['complexity'] + end + + def text + @parsed_xml.text unless sub + end + + def to_h + { + :id => id, + :system => system, + :complexity => complexity, + :text => text, + :sub => sub.to_h + } + end + end +end diff --git a/lib/openscap_parser/fixes.rb b/lib/openscap_parser/fixes.rb new file mode 100644 index 0000000..9183463 --- /dev/null +++ b/lib/openscap_parser/fixes.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'openscap_parser/fix' + +module OpenscapParser + module Fixes + def self.included(base) + base.class_eval do + def fixes + @fixes ||= fix_nodes.map do |fix_node| + OpenscapParser::Fix.new(parsed_xml: fix_node) + end + end + + def fix_nodes(xpath = ".//fix") + xpath_nodes(xpath) + end + end + end + end +end diff --git a/lib/openscap_parser/rule.rb b/lib/openscap_parser/rule.rb index ed8dc19..82e79af 100644 --- a/lib/openscap_parser/rule.rb +++ b/lib/openscap_parser/rule.rb @@ -2,6 +2,7 @@ require 'openscap_parser/rule_identifier' require 'openscap_parser/rule_references' +require 'openscap_parser/fixes' require 'openscap_parser/xml_file' # Mimics openscap-ruby Rule interface @@ -9,6 +10,7 @@ module OpenscapParser class Rule < XmlNode include OpenscapParser::Util include OpenscapParser::RuleReferences + include OpenscapParser::Fixes def id @id ||= parsed_xml['id'] diff --git a/lib/openscap_parser/rule_result.rb b/lib/openscap_parser/rule_result.rb index bf0856b..5f7d386 100644 --- a/lib/openscap_parser/rule_result.rb +++ b/lib/openscap_parser/rule_result.rb @@ -22,6 +22,16 @@ def result @result ||= parsed_xml.at_xpath('result') && parsed_xml.at_xpath('result').text || '' end + + def to_h + { + :id => id, + :time => time, + :severity => severity, + :weight => weight, + :result => result + } + end end end diff --git a/lib/openscap_parser/sub.rb b/lib/openscap_parser/sub.rb new file mode 100644 index 0000000..8fa1437 --- /dev/null +++ b/lib/openscap_parser/sub.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +require 'openscap_parser/xml_node' + +module OpenscapParser + class Sub < XmlNode + def idref + @idref ||= @parsed_xml['idref'] + end + + def text + @parsed_xml.text + end + + def to_h + { :idref => idref, :text => text } + end + end +end diff --git a/lib/openscap_parser/subs.rb b/lib/openscap_parser/subs.rb new file mode 100644 index 0000000..5100d14 --- /dev/null +++ b/lib/openscap_parser/subs.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'openscap_parser/sub' + +module OpenscapParser + module Subs + def self.included(base) + base.class_eval do + def sub + return unless sub_node + Sub.new(parsed_xml: sub_node) + end + + def sub_node + @sub_node ||= xpath_node('.//sub') + end + end + end + end +end diff --git a/test/openscap_parser/test_result_file_test.rb b/test/openscap_parser/test_result_file_test.rb index 4dcd5f8..77a12b8 100644 --- a/test/openscap_parser/test_result_file_test.rb +++ b/test/openscap_parser/test_result_file_test.rb @@ -115,6 +115,50 @@ def setup parse_set_values @arf_result_file end end + + context 'fixes' do + test 'should parse fixes for xccdf report' do + parse_fixes @test_result_file + end + + test 'should parse fixes for arf report' do + parse_fixes @arf_result_file + end + + test 'should parse multiple fixes for one rule' do + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" } + fixes = rule.fixes + assert_equal 2, fixes.count + assert fixes.map(&:id).all? { |id| id == 'ensure_gpgcheck_globally_activated' } + refute_equal fixes.first.system, fixes.last.system + end + + test "should parse sub for fix" do + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" } + fix = rule.fixes.find(&:sub) + refute fix.text + assert fix.sub.idref + assert fix.sub.text + end + + test "should parse text for fix without sub" do + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" } + fix = rule.fixes.find(&:text) + refute fix.sub + assert fix.text + end + end + end + + private + + def parse_fixes(result_file) + fixes = result_file.benchmark.rules.flat_map(&:fixes).map(&:to_h) + ids = fixes.map { |fix| fix[:id] } + systems = fixes.map { |fix| fix[:system] } + refute_empty fixes + assert_equal ids, ids.compact + assert_equal systems, systems.compact end def parse_set_values(result_file) From 620fa7fe79ab1ef710d8bf4f589c9779041dee31 Mon Sep 17 00:00:00 2001 From: Ondrej Prazak Date: Fri, 6 Dec 2019 12:49:44 +0100 Subject: [PATCH 2/3] Parse multiple subs for fix --- lib/openscap_parser/fix.rb | 6 +---- lib/openscap_parser/sub.rb | 10 +++---- lib/openscap_parser/subs.rb | 12 +++++---- lib/openscap_parser/xml_node.rb | 4 +++ test/openscap_parser/test_result_file_test.rb | 26 ++++++++++++------- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/lib/openscap_parser/fix.rb b/lib/openscap_parser/fix.rb index fd690b0..73bc474 100644 --- a/lib/openscap_parser/fix.rb +++ b/lib/openscap_parser/fix.rb @@ -18,17 +18,13 @@ def complexity @complexity ||= @parsed_xml['complexity'] end - def text - @parsed_xml.text unless sub - end - def to_h { :id => id, :system => system, :complexity => complexity, :text => text, - :sub => sub.to_h + :subs => subs.map(&:to_h) } end end diff --git a/lib/openscap_parser/sub.rb b/lib/openscap_parser/sub.rb index 8fa1437..be22477 100644 --- a/lib/openscap_parser/sub.rb +++ b/lib/openscap_parser/sub.rb @@ -3,16 +3,12 @@ module OpenscapParser class Sub < XmlNode - def idref - @idref ||= @parsed_xml['idref'] - end - - def text - @parsed_xml.text + def id + @id ||= @parsed_xml['idref'] end def to_h - { :idref => idref, :text => text } + { :id => id, :text => text } end end end diff --git a/lib/openscap_parser/subs.rb b/lib/openscap_parser/subs.rb index 5100d14..cd41843 100644 --- a/lib/openscap_parser/subs.rb +++ b/lib/openscap_parser/subs.rb @@ -6,13 +6,15 @@ module OpenscapParser module Subs def self.included(base) base.class_eval do - def sub - return unless sub_node - Sub.new(parsed_xml: sub_node) + def subs + return [] unless sub_nodes + @subs ||= sub_nodes.map do |xml| + Sub.new(parsed_xml: xml) + end end - def sub_node - @sub_node ||= xpath_node('.//sub') + def sub_nodes(xpath = './/sub') + @sub_nodes ||= xpath_nodes(xpath) end end end diff --git a/lib/openscap_parser/xml_node.rb b/lib/openscap_parser/xml_node.rb index 12eb694..553067c 100644 --- a/lib/openscap_parser/xml_node.rb +++ b/lib/openscap_parser/xml_node.rb @@ -19,6 +19,10 @@ def parsed_xml(report_contents = '') @parsed_xml.remove_namespaces! end + def text + @parsed_xml.text + end + def xpath_node(xpath) parsed_xml && parsed_xml.at_xpath(xpath) end diff --git a/test/openscap_parser/test_result_file_test.rb b/test/openscap_parser/test_result_file_test.rb index 77a12b8..4f976f2 100644 --- a/test/openscap_parser/test_result_file_test.rb +++ b/test/openscap_parser/test_result_file_test.rb @@ -133,20 +133,28 @@ def setup refute_equal fixes.first.system, fixes.last.system end - test "should parse sub for fix" do + test "should parse one sub for fix" do rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" } - fix = rule.fixes.find(&:sub) - refute fix.text - assert fix.sub.idref - assert fix.sub.text + fix = rule.fixes.find { |fix| !fix.subs.empty? } + assert_equal 1, fix.subs.count + assert fix.subs.first.id + assert fix.subs.first.text end - test "should parse text for fix without sub" do - rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" } - fix = rule.fixes.find(&:text) - refute fix.sub + test "should parse text for fix" do + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_enable_selinux_bootloader" } + fix = rule.fixes.find { |fx| fx.system == "urn:xccdf:fix:script:sh" } + assert_empty fix.subs assert fix.text end + + test "should parse multiple subs for fix" do + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_selinux_state" } + fix = rule.fixes.find { |fix| !fix.subs.empty? } + assert_equal 2, fix.subs.count + assert fix.subs.last.id + assert fix.subs.last.text + end end end From baba20c361f9286a1d8a7ab1e3f5217b95fee5df Mon Sep 17 00:00:00 2001 From: Ondrej Prazak Date: Wed, 11 Dec 2019 09:19:36 +0100 Subject: [PATCH 3/3] Parse additional attrs for Sub and Fix --- lib/openscap_parser/fix.rb | 10 ++++++++++ lib/openscap_parser/sub.rb | 6 +++++- test/openscap_parser/test_result_file_test.rb | 11 ++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/openscap_parser/fix.rb b/lib/openscap_parser/fix.rb index 73bc474..3cce864 100644 --- a/lib/openscap_parser/fix.rb +++ b/lib/openscap_parser/fix.rb @@ -18,11 +18,21 @@ def complexity @complexity ||= @parsed_xml['complexity'] end + def disruption + @disruption ||= @parsed_xml['disruption'] + end + + def strategy + @strategy ||= @parsed_xml['strategy'] + end + def to_h { :id => id, :system => system, :complexity => complexity, + :disruption => disruption, + :strategy => strategy, :text => text, :subs => subs.map(&:to_h) } diff --git a/lib/openscap_parser/sub.rb b/lib/openscap_parser/sub.rb index be22477..42957f4 100644 --- a/lib/openscap_parser/sub.rb +++ b/lib/openscap_parser/sub.rb @@ -7,8 +7,12 @@ def id @id ||= @parsed_xml['idref'] end + def use + @use ||= @parsed_xml['use'] + end + def to_h - { :id => id, :text => text } + { :id => id, :text => text, :use => use } end end end diff --git a/test/openscap_parser/test_result_file_test.rb b/test/openscap_parser/test_result_file_test.rb index 4f976f2..c6c362a 100644 --- a/test/openscap_parser/test_result_file_test.rb +++ b/test/openscap_parser/test_result_file_test.rb @@ -141,19 +141,24 @@ def setup assert fix.subs.first.text end - test "should parse text for fix" do + test "should parse attributes for fix" do rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_enable_selinux_bootloader" } fix = rule.fixes.find { |fx| fx.system == "urn:xccdf:fix:script:sh" } assert_empty fix.subs assert fix.text + assert fix.complexity + assert fix.disruption + assert fix.strategy end test "should parse multiple subs for fix" do rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_selinux_state" } fix = rule.fixes.find { |fix| !fix.subs.empty? } assert_equal 2, fix.subs.count - assert fix.subs.last.id - assert fix.subs.last.text + sub = fix.subs.last + assert sub.id + assert sub.text + assert sub.use end end end