diff --git a/lib/openscap_parser/fix.rb b/lib/openscap_parser/fix.rb index 3cce864..1aa2650 100644 --- a/lib/openscap_parser/fix.rb +++ b/lib/openscap_parser/fix.rb @@ -26,6 +26,20 @@ def strategy @strategy ||= @parsed_xml['strategy'] end + def full_text(set_values) + full_text_lines(set_values).join('') + end + + def full_text_lines(set_values) + map_child_nodes(set_values).map do |text_node| + text_node.respond_to?(:text) ? text_node.text : '' + end + end + + def map_child_nodes(set_values = []) + map_sub_nodes @parsed_xml.children, set_values + end + def to_h { :id => id, diff --git a/lib/openscap_parser/subs.rb b/lib/openscap_parser/subs.rb index cd41843..865147a 100644 --- a/lib/openscap_parser/subs.rb +++ b/lib/openscap_parser/subs.rb @@ -16,6 +16,22 @@ def subs def sub_nodes(xpath = './/sub') @sub_nodes ||= xpath_nodes(xpath) end + + def map_sub_nodes(children, set_values) + children.map do |child| + next child if child.name == 'text' + next replace_sub(Sub.new(parsed_xml: child), set_values) if child.name == 'sub' + child + end + end + + private + + def replace_sub(sub, set_values) + set_value = set_values.find { |set_value| set_value.id == sub.id } + return unless set_value + set_value.parsed_xml.children.first + end end end end diff --git a/test/fixtures/files/selinux_full_fix.sh b/test/fixtures/files/selinux_full_fix.sh new file mode 100644 index 0000000..4776954 --- /dev/null +++ b/test/fixtures/files/selinux_full_fix.sh @@ -0,0 +1,63 @@ + +var_selinux_state="enforcing" + +function replace_or_append { + local config_file=$1 + local key=$2 + local value=$3 + local cce=$4 + local format=$5 + + # Check sanity of the input + if [ $# -lt "3" ] + then + echo "Usage: replace_or_append 'config_file_location' 'key_to_search' 'new_value'" + echo + echo "If symlinks need to be taken into account, add yes/no to the last argument" + echo "to allow to 'follow_symlinks'." + echo "Aborting." + exit 1 + fi + + # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed. + # Otherwise, regular sed command will do. + if test -L $config_file; then + sed_command="sed -i --follow-symlinks" + else + sed_command="sed -i" + fi + + # Test that the cce arg is not empty or does not equal @CCENUM@. + # If @CCENUM@ exists, it means that there is no CCE assigned. + if ! [ "x$cce" = x ] && [ "$cce" != '@CCENUM@' ]; then + cce="CCE-${cce}" + else + cce="CCE" + fi + + # Strip any search characters in the key arg so that the key can be replaced without + # adding any search characters to the config file. + stripped_key=$(sed "s/[\^=\$,;+]*//g" <<< $key) + + # If there is no print format specified in the last arg, use the default format. + if ! [ "x$format" = x ] ; then + printf -v formatted_output "$format" "$stripped_key" "$value" + else + formatted_output="$stripped_key = $value" + fi + + # If the key exists, change it. Otherwise, add it to the config_file. + if `grep -qi $key $config_file` ; then + $sed_command "s/$key.*/$formatted_output/g" $config_file + else + # \n is precaution for case where file ends without trailing newline + echo -e "\n# Per $cce: Set $formatted_output in $config_file" >> $config_file + echo -e "$formatted_output" >> $config_file + fi + +} + +replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state 'CCE-27334-2' '%s=%s' + +fixfiles onboot +fixfiles -f relabel diff --git a/test/openscap_parser/test_result_file_test.rb b/test/openscap_parser/test_result_file_test.rb index c6c362a..8d7f09a 100644 --- a/test/openscap_parser/test_result_file_test.rb +++ b/test/openscap_parser/test_result_file_test.rb @@ -160,6 +160,24 @@ def setup assert sub.text assert sub.use end + + test "should resolve set-values for subs" do + set_values = @arf_result_file.test_result.set_values + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_selinux_state" } + rule.fixes.first.map_child_nodes(set_values).all? { |node| node.is_a? Nokogiri::XML::Text } + end + + test "should parse full fix text lines" do + set_values = @arf_result_file.test_result.set_values + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_selinux_state" } + assert_equal 5, rule.fixes.first.full_text_lines(set_values).count + end + + test "should compose full fix" do + set_values = @arf_result_file.test_result.set_values + rule = @arf_result_file.benchmark.rules.find { |rule| rule.id == "xccdf_org.ssgproject.content_rule_selinux_state" } + assert_equal file_fixture('selinux_full_fix.sh').read, rule.fixes.first.full_text(set_values) + end end end