ssg/parse_oval.py
from __future__ import absolute_import
from __future__ import print_function
from .xml import ElementTree as ET
REFERENCE_TO_GROUP = dict(
var_ref="variables",
test_ref="tests",
object_ref="objects",
state_ref="states",
)
CONTAINER_GROUPS = set((
"definitions",
"objects",
"states",
"tests",
"variables",
))
class ElementFinder(object):
def __init__(self, oval_groups):
self.oval_groups = oval_groups
self.target = None
self.attrib = None
self.result = set()
def find_element(self, start_element, target_element_name, sought_attrib):
self.target = target_element_name
self.attrib = sought_attrib
self.result = set()
self._recurse(start_element)
def _recurse(self, element):
if element.tag.endswith(self.target):
self.result.add(element.attrib[self.attrib])
return
self._examine_element(element)
for child in element:
self._recurse(child)
def _examine_element(self, element):
name = _strip_ns_from_tag(element.tag)
new_root = None
if name in REFERENCE_TO_GROUP:
reference_target = REFERENCE_TO_GROUP[name]
new_root = self.oval_groups[reference_target][element.text]
else:
_attr_group = _search_element_for_reference_attributes(element)
if _attr_group is not None:
ref_attribute_name, entity_id = _attr_group
reference_target = REFERENCE_TO_GROUP[ref_attribute_name]
assert entity_id in self.oval_groups[reference_target], \
('Missing definition: "%s" in "%s" "%s"' %
(entity_id, reference_target, element))
new_root = self.oval_groups[reference_target][entity_id]
if new_root is not None:
self._recurse(new_root)
def _sort_by_id(elements):
ret = dict()
for element in elements:
ret[element.attrib["id"]] = element
return ret
def _search_dict_for_items_that_end_with(dic, what_to_look_for):
for item in dic:
if item.endswith(what_to_look_for):
return dic[item]
return None
def _search_element_for_reference_attributes(element):
for ref_attribute_name in REFERENCE_TO_GROUP:
occurence = _search_dict_for_items_that_end_with(
element.attrib, ref_attribute_name)
if occurence is not None:
return ref_attribute_name, occurence
return None
def _find_attr(oval_groups, defn, elem, attr):
finder = ElementFinder(oval_groups)
finder.find_element(defn, elem, attr)
return finder.result
def resolve_definition(oval_groups, defn):
return _find_attr(oval_groups, defn, "external_variable", "id")
def find_extending_defs(oval_groups, defn):
return _find_attr(oval_groups, defn, "extend_definition", "definition_ref")
def get_container_groups(fname):
return _get_container_oval_groups_from_tree(ET.parse(fname))
def _strip_ns_from_tag(tag_name):
return tag_name.split("}", 1)[1]
def _get_container_oval_groups_from_tree(element_tree):
root = element_tree.getroot()
oval_groups = {}
for child in root:
group_name = _strip_ns_from_tag(child.tag)
if group_name in CONTAINER_GROUPS:
oval_groups[group_name] = _sort_by_id(child)
return oval_groups
def _get_resolved_definitions(oval_groups):
def_id_to_vars_ids = {}
for def_id, def_el in oval_groups["definitions"].items():
def_id_to_vars_ids[def_id] = resolve_definition(oval_groups, def_el)
return def_id_to_vars_ids
def _check_sanity(oval_groups, resolved_defns):
all_external_variables = set()
for var_id, var_el in oval_groups["variables"].items():
if var_el.tag.endswith("external_variable"):
all_external_variables.add(var_id)
all_caught_variables = set()
for var in resolved_defns.values():
all_caught_variables.update(var)
skipped_variables = all_external_variables.difference(all_caught_variables)
if skipped_variables:
print("These variables managed to slip past:", skipped_variables)
strange_variables = all_caught_variables.difference(
all_external_variables)
assert not strange_variables, \
("There were unexpected caught variables: {}"
.format(str(strange_variables)))
def _check_sanity_on_file(fname):
oval_groups = get_container_groups(fname)
resolved_defns = _get_resolved_definitions(oval_groups)
_check_sanity(oval_groups, resolved_defns)