1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
"""
Common functions for processing ID Translations in SSG
"""
from __future__ import absolute_import
from __future__ import print_function
from .xml import ElementTree
from .constants import oval_namespace as oval_ns
from .constants import ocil_namespace as ocil_ns
from .constants import OVALTAG_TO_ABBREV, OCILTAG_TO_ABBREV
from .constants import OVALREFATTR_TO_TAG, OCILREFATTR_TO_TAG
def _split_namespace(tag):
"""
Splits an XML tag into its namespace and name components.
Args:
tag (str): The XML tag to split. If the tag contains a namespace, it should be in the
format '{namespace}name'.
Returns:
tuple: A tuple containing the namespace and the tag name. If the tag does not contain a
namespace, the namespace will be None. Any fragment identifier in the namespace
will be removed.
"""
if tag[0] == "{":
namespace, name = tag[1:].split("}", 1)
return (namespace.split("#", 1)[0], name)
return (None, tag)
def _namespace_to_prefix(tag):
"""
Convert a namespace in a tag to its corresponding prefix.
Args:
tag (str): The tag containing the namespace to be converted.
Returns:
str: The prefix corresponding to the namespace.
Raises:
RuntimeError: If the namespace in the tag is unknown.
"""
namespace, _ = _split_namespace(tag)
if namespace == ocil_ns:
return "ocil"
if namespace == oval_ns:
return "oval"
raise RuntimeError(
"Error: unknown checksystem referenced in tag : %s" % tag
)
def _tagname_to_abbrev(tag):
"""
Convert a tag name to its abbreviated form based on its namespace.
Args:
tag (str): The tag name to be converted, which may include a namespace.
Returns:
str: The abbreviated form of the tag name.
Raises:
RuntimeError: If the tag's namespace is unknown.
Notes:
- If the tag is "extend_definition", it is returned as is.
- The tag name is split by the last underscore to determine its type.
- The namespace is used to look up the abbreviation in the corresponding dictionary.
"""
namespace, tag = _split_namespace(tag)
if tag == "extend_definition":
return tag
# grab the last part of the tag name to determine its type
tag = tag.rsplit("_", 1)[-1]
if namespace == ocil_ns:
return OCILTAG_TO_ABBREV[tag]
if namespace == oval_ns:
return OVALTAG_TO_ABBREV[tag]
raise RuntimeError(
"Error: unknown checksystem referenced in tag : %s" % tag
)
class IDTranslator(object):
"""
IDTranslator is a class designed to handle the mapping of meaningful, human-readable names to
IDs in the formats required by the SCAP checking systems, such as OVAL and OCIL.
Attributes:
content_id (str): The content identifier used in generating IDs.
"""
def __init__(self, content_id):
self.content_id = content_id
def generate_id(self, tagname, name):
"""
Generates a unique identifier string based on the provided tag name and name.
Args:
tagname (str): The tag name to be used in the identifier.
name (str): The name to be used in the identifier.
Returns:
str: A unique identifier string in the format
"<namespace_prefix>:<content_id>-<name>:<tagname_abbrev>:1".
"""
return "%s:%s-%s:%s:1" % (
_namespace_to_prefix(tagname),
self.content_id, name,
_tagname_to_abbrev(tagname)
)
def translate(self, tree, store_defname=False):
"""
Translates the IDs of elements in an XML tree to new identifiers.
Args:
tree (ElementTree.Element): The XML tree to be processed.
store_defname (bool, optional): If True, stores the old name in the metadata for OVAL
definitions. Defaults to False.
Returns:
ElementTree.Element: The processed XML tree with updated IDs.
The function iterates through each element in the provided XML tree and performs the
following actions based on the element's tag and attributes:
- If the element has an "id" attribute, it generates a new ID and sets it.
- If `store_defname` is True and the element is an OVAL definition, it stores the old ID
in the metadata.
- For specific tags like "filter", "var_ref", and "object_reference", it updates the text
content with a new ID.
- For attributes that match keys in `OVALREFATTR_TO_TAG` or `OCILREFATTR_TO_TAG`, it
updates the attribute value with a new ID.
- For the "test_action_ref" tag, it updates the text content with a new ID.
"""
for element in tree.iter():
idname = element.get("id")
if idname:
# store the old name if requested (for OVAL definitions)
if store_defname and \
element.tag == "{%s}definition" % oval_ns:
metadata = element.find("{%s}metadata" % oval_ns)
if metadata is None:
metadata = ElementTree.SubElement(element, "metadata")
defnam = ElementTree.Element(
"{%s}reference" % oval_ns, ref_id=idname, source=self.content_id)
metadata.append(defnam)
# set the element to the new identifier
element.set("id", self.generate_id(element.tag, idname))
# continue
if element.tag == "{%s}filter" % oval_ns:
element.text = self.generate_id("{%s}state" % oval_ns,
element.text)
continue
if element.tag == "{%s#independent}var_ref" % oval_ns:
element.text = self.generate_id("{%s}variable" % oval_ns,
element.text)
continue
if element.tag == "{%s}object_reference" % oval_ns:
element.text = self.generate_id("{%s}object" % oval_ns,
element.text)
continue
for attr in element.keys():
if attr in OVALREFATTR_TO_TAG.keys():
element.set(attr, self.generate_id(
"{%s}%s" % (oval_ns, OVALREFATTR_TO_TAG[attr]),
element.get(attr)))
if attr in OCILREFATTR_TO_TAG.keys():
element.set(attr, self.generate_id(
"{%s}%s" % (ocil_ns, OCILREFATTR_TO_TAG[attr]),
element.get(attr)))
if element.tag == "{%s}test_action_ref" % ocil_ns:
element.text = self.generate_id("{%s}action" % ocil_ns,
element.text)
return tree
def translate_oval_document(self, oval_document, store_defname=False):
"""
Translates and validates an OVAL document.
This method translates the IDs in the given OVAL document and validates its references.
Args:
oval_document: The OVAL document to be translated and validated.
store_defname (bool, optional): If True, stores the definition name during
translation. Defaults to False.
Returns:
The translated and validated OVAL document.
"""
oval_document.translate_id(self, store_defname)
oval_document.validate_references()
return oval_document
|