-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently, the "Show test details" section displays definition of OVAL Object and OVAL State. This patch will add also displaying OVAL Items collected from the system for the given OVAL Object. This is a very popular feature of the old report which I think will be useful also in the new report because it gives detailed information about the actual state of the target.
- Loading branch information
Showing
9 changed files
with
264 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
openscap_report/scap_results_parser/data_structures/oval_items.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Copyright 2024, Red Hat, Inc. | ||
# SPDX-License-Identifier: LGPL-2.1-or-later | ||
|
||
from typing import List, Tuple | ||
from openscap_report.dataclasses import asdict, dataclass, field | ||
|
||
|
||
@dataclass | ||
class OVALItems: | ||
header: Tuple[str] = field(default_factory=tuple) | ||
entries: List[Tuple[str]] = field(default_factory=list) | ||
message: str = None | ||
|
||
def as_dict(self): | ||
return asdict(self) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
openscap_report/scap_results_parser/parsers/oval_items_parser.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Copyright 2024, Red Hat, Inc. | ||
# SPDX-License-Identifier: LGPL-2.1-or-later | ||
|
||
from .shared_static_methods_of_parser import SharedStaticMethodsOfParser | ||
from ..data_structures import OVALItems | ||
from ..namespaces import NAMESPACES | ||
|
||
PROCURED_ITEMS_LIMIT = 100 | ||
|
||
|
||
class OVALItemsParser: | ||
def __init__(self, collected_objects, system_data): | ||
self.collected_objects = collected_objects | ||
self.system_data = system_data | ||
|
||
def _get_item(self, item_ref): | ||
item_el = self.system_data.get(item_ref) | ||
item_data = {} | ||
for child_el in item_el: | ||
if child_el.text and child_el.text.strip(): | ||
key = SharedStaticMethodsOfParser.get_key_of_xml_element(child_el) | ||
item_data[key] = child_el.text | ||
return item_data | ||
|
||
def _get_items(self, references): | ||
items = [] | ||
for reference_el in references: | ||
item_ref = reference_el.get("item_ref") | ||
item = self._get_item(item_ref) | ||
items.append(item) | ||
return items | ||
|
||
@staticmethod | ||
def _get_header(items): | ||
header = [] | ||
for item in items: | ||
for key in item.keys(): | ||
if key not in header: | ||
header.append(key) | ||
return tuple(header) | ||
|
||
@staticmethod | ||
def _get_entries(header, items): | ||
entries = [] | ||
for item in items: | ||
entry = [] | ||
for key in header: | ||
entry.append(item.get(key, "")) | ||
entries.append(tuple(entry)) | ||
return entries | ||
|
||
def get_oval_items(self, object_id): | ||
collected_object_el = self.collected_objects.get(object_id) | ||
if collected_object_el is None: | ||
return None | ||
references = collected_object_el.findall( | ||
"oval-characteristics:reference", NAMESPACES | ||
) | ||
if len(references) == 0: | ||
return None | ||
items = self._get_items(references) | ||
header = self._get_header(items) | ||
entries = self._get_entries(header, items) | ||
message = None | ||
len_entries = len(entries) | ||
if len_entries > PROCURED_ITEMS_LIMIT: | ||
entries = entries[:PROCURED_ITEMS_LIMIT] | ||
message = f"Collected {len_entries} items, showing only first {PROCURED_ITEMS_LIMIT} items" | ||
return OVALItems(header=header, entries=entries, message=message) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# Copyright 2024, Red Hat, Inc. | ||
# SPDX-License-Identifier: LGPL-2.1-or-later | ||
|
||
import pytest | ||
from lxml import etree | ||
|
||
from openscap_report.scap_results_parser.namespaces import NAMESPACES | ||
from openscap_report.scap_results_parser.parsers.oval_items_parser import OVALItemsParser | ||
|
||
|
||
@pytest.fixture | ||
def parser(): | ||
sc_ns = NAMESPACES["oval-characteristics"] | ||
is_ns = NAMESPACES["ind-sys"] | ||
|
||
o1_id = "oval:example:obj:1" | ||
o2_id = "oval:example:obj:2" | ||
o3_id = "oval:example:obj:3" | ||
i1_id = "11117777" | ||
i2_id = "11117777" | ||
i3_id = "33339999" | ||
|
||
o1 = etree.Element("{%s}object" % sc_ns, nsmap=NAMESPACES, id=o1_id, version="1", flag="complete") | ||
o1_r1 = etree.Element("{%s}reference" % sc_ns, nsmap=NAMESPACES, item_ref=i1_id) | ||
o1.append(o1_r1) | ||
|
||
o2 = etree.Element("{%s}object" % sc_ns, nsmap=NAMESPACES, id=o2_id, version="1", flag="complete") | ||
o2_r1 = etree.Element("{%s}reference" % sc_ns, nsmap=NAMESPACES, item_ref=i2_id) | ||
o2.append(o2_r1) | ||
o2_r2 = etree.Element("{%s}reference" % sc_ns, nsmap=NAMESPACES, item_ref=i3_id) | ||
o2.append(o2_r2) | ||
|
||
o3 = etree.Element("{%s}object" % sc_ns, nsmap=NAMESPACES, id=o3_id, version="1", flag="does not exist") | ||
|
||
collected_objects = { | ||
o1_id: o1, | ||
o2_id: o2, | ||
o3_id: o3 | ||
} | ||
|
||
i1 = etree.Element("{%s}textfilecontent_item" % is_ns, nsmap=NAMESPACES, id=i1_id, status="exists") | ||
i1_filepath = etree.Element("{%s}filepath" % is_ns, nsmap=NAMESPACES) | ||
i1_filepath.text = "/var/cities" | ||
i1.append(i1_filepath) | ||
i1_text = etree.Element("{%s}text" % is_ns, nsmap=NAMESPACES) | ||
i1_text.text = "Paris" | ||
i1.append(i1_text) | ||
|
||
i2 = etree.Element("{%s}textfilecontent_item" % is_ns, nsmap=NAMESPACES, id=i2_id, status="exists") | ||
i2_filepath = etree.Element("{%s}filepath" % is_ns, nsmap=NAMESPACES) | ||
i2_filepath.text = "/var/cities" | ||
i2.append(i2_filepath) | ||
i2_text = etree.Element("{%s}text" % is_ns, nsmap=NAMESPACES) | ||
i2_text.text = "London" | ||
i2.append(i2_text) | ||
|
||
i3 = etree.Element("{%s}textfilecontent_item" % is_ns, nsmap=NAMESPACES, id=i3_id, status="exists") | ||
i3_filepath = etree.Element("{%s}filepath" % is_ns, nsmap=NAMESPACES) | ||
i3_filepath.text = "/var/cities" | ||
i3.append(i3_filepath) | ||
i3_text = etree.Element("{%s}text" % is_ns, nsmap=NAMESPACES) | ||
i3_text.text = "Prague" | ||
i3.append(i3_text) | ||
|
||
system_data = { | ||
i1_id: i1, | ||
i2_id: i2, | ||
i3_id: i3, | ||
} | ||
|
||
return OVALItemsParser(collected_objects, system_data) | ||
|
||
|
||
@pytest.mark.unit_test | ||
def test_oval_items_parser_single(parser): | ||
oi = parser.get_oval_items("oval:example:obj:1") | ||
assert oi is not None | ||
assert oi.header == ("filepath", "text") | ||
assert len(oi.entries) == 1 | ||
assert oi.entries[0] == ("/var/cities", "London") | ||
|
||
@pytest.mark.unit_test | ||
def test_oval_items_parser_multiple(parser): | ||
oi = parser.get_oval_items("oval:example:obj:2") | ||
assert oi is not None | ||
assert oi.header == ("filepath", "text") | ||
assert len(oi.entries) == 2 | ||
assert oi.entries[0] == ("/var/cities", "London") | ||
assert oi.entries[1] == ("/var/cities", "Prague") | ||
|
||
@pytest.mark.unit_test | ||
def test_oval_items_parser_dne(parser): | ||
oi = parser.get_oval_items("oval:example:obj:3") | ||
assert oi is None | ||
|
||
@pytest.mark.unit_test | ||
def test_oval_items_parser_wrong_object_id(parser): | ||
oi = parser.get_oval_items("oval:example:obj:666") | ||
assert oi is None |