Source code for ssg.id_translate

"""
Common functions for processing ID Translations in SSG
"""

from __future__ import absolute_import

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
    )


[docs] 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
[docs] 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) )
[docs] 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
[docs] 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