Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the check-fact-ref element in CPE-AL #150

Merged
merged 3 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions openscap_report/scap_results_parser/parsers/cpe_al_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from ..namespaces import NAMESPACES
from .full_text_parser import FullTextParser

TEXT_TO_BOOL = {"true": True, "false": False, "": False}


class CPEApplicabilityLanguageParser:
def __init__(self, root):
Expand Down Expand Up @@ -35,26 +37,33 @@ def _get_cpe_platform_elements(self):
cpe_platform_elements[platform_id] = platform
return cpe_platform_elements

def _get_oval_cpe_tree(self, platform_name):
def _get_oval_cpe_tree(self, platform_name, check_id_ref):
oval_tree = None
oval_cpe_id = None

if platform_name in self.platform_to_oval_cpe_id:
oval_cpe_id = self.platform_to_oval_cpe_id[platform_name]
oval_cpe_definition = self.oval_cpe_definitions.get(oval_cpe_id, None)
oval_tree = oval_cpe_definition.oval_tree if oval_cpe_definition is not None else None

if check_id_ref is not None:
oval_cpe_id = check_id_ref

oval_cpe_definition = self.oval_cpe_definitions.get(oval_cpe_id, None)
oval_tree = oval_cpe_definition.oval_tree if oval_cpe_definition is not None else None
return oval_tree

def get_logical_test(self, logical_test_el):
operator = logical_test_el.get("operator")
negation = logical_test_el.get("negation")
logical_test = LogicalTest(operator, negation)
negation = logical_test_el.get("negate", "")
logical_test = LogicalTest(operator, negation=TEXT_TO_BOOL[negation])
for child_logical_test_el in logical_test_el:
if "fact-ref" in child_logical_test_el.tag:
platform_name = child_logical_test_el.get("name")
check_id_ref = child_logical_test_el.get("id-ref")
logical_test.children.append(
LogicalTest(
node_type="frac-ref",
value=platform_name,
oval_tree=self._get_oval_cpe_tree(platform_name))
value=platform_name if platform_name is not None else check_id_ref,
oval_tree=self._get_oval_cpe_tree(platform_name, check_id_ref))
)
if child_logical_test_el.get('operator') is not None:
logical_test.children.append(self.get_logical_test(child_logical_test_el))
Expand Down
28 changes: 27 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
from functools import cache
except ImportError:
from functools import lru_cache

cache = lru_cache(maxsize=None)

from lxml import etree

from openscap_report.scap_results_parser import SCAPResultsParser
from openscap_report.scap_results_parser.data_structures import OvalDefinition
from openscap_report.scap_results_parser.namespaces import NAMESPACES
from openscap_report.scap_results_parser.parsers import RuleParser
from openscap_report.scap_results_parser.parsers import (
CPEApplicabilityLanguageParser, RuleParser)

from .constants import (PATH_TO_ARF,
PATH_TO_ARF_REPRODUCING_DANGLING_REFERENCE_TO)
from .unit_tests.test_oval_tree_eval import OVAL_TREE_TRUE


@cache
Expand Down Expand Up @@ -78,3 +82,25 @@ def get_rules(file_path=None):
ref_values = get_ref_values(root)
rule_parser = RuleParser(root, test_results, ref_values)
return rule_parser.get_rules()


def get_cpe_al_parser(file_path=PATH_TO_ARF):
root = get_root(file_path)
return CPEApplicabilityLanguageParser(root)


def get_dummy_cpe_oval_definition():
dummy_oval_definition = OvalDefinition(
definition_id="dummy_oval_def",
title="dummy OVAL definition",
oval_tree=OVAL_TREE_TRUE,
)
return {
"oval:ssg-installed_env_is_a_machine:def:1": dummy_oval_definition,
"oval:ssg-installed_env_has_chrony_package:def:1": dummy_oval_definition,
"oval:ssg-installed_env_has_ntp_package:def:1": dummy_oval_definition,
"oval:ssg-installed_env_has_gdm_package:def:1": dummy_oval_definition,
"oval:ssg-installed_OS_is_fedora:def:1": dummy_oval_definition,
"oval:ssg-installed_env_has_zipl_package:def:1": dummy_oval_definition,
"oval:ssg-system_boot_mode_is_uefi:def:1": dummy_oval_definition,
}
109 changes: 109 additions & 0 deletions tests/unit_tests/test_cpe_al_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Copyright 2022, Red Hat, Inc.
# SPDX-License-Identifier: LGPL-2.1-or-later

import pytest
from lxml import etree

from ..test_utils import get_cpe_al_parser, get_dummy_cpe_oval_definition


@pytest.mark.unit_test
@pytest.mark.parametrize(
"str_xml_element, evaluation_result",
[
(
(
'<cpe-lang:logical-test operator="AND" negate="false">'
' <cpe-lang:fact-ref name="cpe:/a:machine"/>'
'</cpe-lang:logical-test>'
),
"true",
),
(
(
'<cpe-lang:logical-test operator="AND" negate="true">'
' <cpe-lang:fact-ref name="cpe:/a:machine"/>'
'</cpe-lang:logical-test>'
),
"false",
),
(
(
'<cpe-lang:logical-test operator="AND" negate="false">'
' <cpe-lang:logical-test operator="OR" negate="false">'
' <cpe-lang:fact-ref name="cpe:/a:chrony"/>'
' <cpe-lang:fact-ref name="cpe:/a:ntp"/>'
' </cpe-lang:logical-test>'
' <cpe-lang:fact-ref name="cpe:/a:machine"/>'
'</cpe-lang:logical-test>'
),
"true",
),
(
(
'<cpe-lang:logical-test operator="AND" negate="true">'
' <cpe-lang:logical-test operator="OR" negate="false">'
' <cpe-lang:logical-test operator="AND" negate="false">'
' <cpe-lang:fact-ref name="cpe:/o:fedoraproject:fedora:32"/>'
' <cpe-lang:fact-ref name="cpe:/a:gdm"/>'
' </cpe-lang:logical-test>'
' <cpe-lang:logical-test operator="AND" negate="false">'
' <cpe-lang:fact-ref name="cpe:/o:fedoraproject:fedora:32"/>'
' <cpe-lang:fact-ref name="cpe:/a:uefi"/>'
' </cpe-lang:logical-test>'
' <cpe-lang:logical-test operator="AND" negate="true">'
' <cpe-lang:fact-ref name="cpe:/a:zipl"/>'
' <cpe-lang:fact-ref name="cpe:/o:fedoraproject:fedora:32"/>'
' </cpe-lang:logical-test>'
' </cpe-lang:logical-test>'
'</cpe-lang:logical-test>'
),
"false",
),
(
(
'<cpe-lang:logical-test operator="AND" negate="false">'
' <cpe-lang:check-fact-ref'
' system="http://oval.mitre.org/XMLSchema/oval-definitions-5"'
' href="ssg-rhel9-cpe-oval.xml"'
' id-ref="oval:ssg-installed_env_is_a_machine:def:1"/>'
'</cpe-lang:logical-test>'
),
"true",
),
(
(
'<cpe-lang:logical-test operator="AND" negate="true">'
' <cpe-lang:check-fact-ref'
' system="http://oval.mitre.org/XMLSchema/oval-definitions-5"'
' href="ssg-rhel9-cpe-oval.xml"'
' id-ref="oval:ssg-installed_env_is_a_machine:def:1"/>'
'</cpe-lang:logical-test>'
),
"false",
),
(
(
'<cpe-lang:logical-test operator="OR" negate="false">'
' <cpe-lang:check-fact-ref'
' system="http://oval.mitre.org/XMLSchema/oval-definitions-5"'
' href="ssg-rhel9-cpe-oval.xml"'
' id-ref="oval:ssg-installed_env_has_chrony_package:def:1"/>'
' <cpe-lang:check-fact-ref'
' system="http://oval.mitre.org/XMLSchema/oval-definitions-5"'
' href="ssg-rhel9-cpe-oval.xml"'
' id-ref="oval:ssg-installed_env_has_ntp_package:def:1"/>'
'</cpe-lang:logical-test>'
),
"true",
),
],
)
def test_get_logical_test(str_xml_element, evaluation_result):
parser = get_cpe_al_parser()
parser.oval_cpe_definitions = get_dummy_cpe_oval_definition()
xml_element = etree.XML(
f'<con xmlns:cpe-lang="http://cpe.mitre.org/language/2.0">{str_xml_element}</con>'
)
logical_test = parser.get_logical_test(xml_element[0])
assert logical_test.evaluate_tree() == evaluation_result