ssg.oval   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 84
dl 0
loc 147
rs 10
c 0
b 0
f 0
ccs 0
cts 73
cp 0
wmc 16

2 Functions

Rating   Name   Duplication   Size   Complexity  
B applicable_platforms() 0 39 5
C parse_affected() 0 79 11
1
from __future__ import absolute_import
2
from __future__ import print_function
3
4
import sys
5
import os
6
7
from .constants import oval_footer as footer
8
from .constants import oval_namespace as ovalns
9
from .xml import ElementTree as ET
10
from .xml import oval_generated_header
11
12
from .jinja import process_file_with_macros
13
from .products import _get_implied_properties
14
15
16
ASSUMED_OVAL_VERSION_STRING = "5.11"
17
# globals, to make recursion easier in case we encounter extend_definition
18
try:
19
    ET.register_namespace("oval", ovalns)
20
except AttributeError:
21
    # Legacy Python 2.6 fix, see e.g.
22
    # https://www.programcreek.com/python/example/57552/xml.etree.ElementTree._namespace_map
23
    from xml.etree import ElementTree as ET
24
    ET._namespace_map[ovalns] = "oval"
25
26
27
def applicable_platforms(oval_file, oval_version_string=None):
28
    """
29
    Returns the applicable platforms for a given oval file
30
    """
31
32
    platforms = []
33
34
    if not oval_version_string:
35
        oval_version_string = ASSUMED_OVAL_VERSION_STRING
36
    header = oval_generated_header("applicable_platforms", oval_version_string, "0.0.1")
37
38
    oval_version_list = [int(num) for num in oval_version_string.split(".")]
39
    subst_dict = dict(target_oval_version=oval_version_list)
40
41
    oval_filename_components = oval_file.split(os.path.sep)
42
    if len(oval_filename_components) > 3:
43
        subst_dict["rule_id"] = oval_filename_components[-3]
44
    else:
45
        msg = "Unable to get rule ID from OVAL path '{path}'".format(path=oval_file)
46
        print(msg, file=sys.stderr)
47
48
    subst_dict = _get_implied_properties(subst_dict)
49
    subst_dict['target_oval_version'] = [999, 999.999]
50
51
    body = process_file_with_macros(oval_file, subst_dict)
52
53
    try:
54
        oval_tree = ET.fromstring(header + body + footer)
55
    except Exception as e:
56
        msg = "Error while loading " + oval_file
57
        print(msg, file=sys.stderr)
58
        raise e
59
60
    element_path = "./{%s}def-group/{%s}definition/{%s}metadata/{%s}affected/{%s}platform"
61
    element_ns_path = element_path % (ovalns, ovalns, ovalns, ovalns, ovalns)
62
    for node in oval_tree.findall(element_ns_path):
63
        platforms.append(node.text)
64
65
    return platforms
66
67
68
def parse_affected(oval_contents):
69
    """
70
    Returns the tuple (start_affected, end_affected, platform_indents) for
71
    the passed oval file contents. start_affected is the line number of
72
    starting tag of the <affected> element, end_affected is the line number of
73
    the closing tag of the </affected> element, and platform_indents is a
74
    string containing the indenting characters before the contents of the
75
    <affected> element.
76
    """
77
78
    start_affected = list(filter(lambda x: "<affected" in oval_contents[x],
79
                                 range(0, len(oval_contents))))
80
    if len(start_affected) != 1:
81
        raise ValueError("OVAL file does not contain a single <affected> "
82
                         "element; counted %d in:\n%s\n\n" %
83
                         (len(start_affected), "\n".join(oval_contents)))
84
85
    start_affected = start_affected[0]
86
87
    end_affected = list(filter(lambda x: "</affected" in oval_contents[x],
88
                               range(0, len(oval_contents))))
89
    if len(end_affected) != 1:
90
        raise ValueError("Malformed OVAL file does not contain a single "
91
                         "closing </affected>; counted %d in:\n%s\n\n" %
92
                         (len(start_affected), "\n".join(oval_contents)))
93
    end_affected = end_affected[0]
94
95
    if start_affected >= end_affected:
96
        raise ValueError("Malformed OVAL file: start affected tag begins "
97
                         "on the same line or after ending affected tag: "
98
                         "start:%d vs end:%d:\n%s\n\n" %
99
                         (start_affected, end_affected, oval_contents))
100
101
    # Validate that start_affected contains only a starting <affected> tag;
102
    # otherwise, using this information to update the <platform> subelements
103
    # would fail.
104
    start_line = oval_contents[start_affected]
105
    start_line = start_line.strip()
106
107
    if not start_line.startswith('<affected'):
108
        raise ValueError("Malformed OVAL file: line with starting affected "
109
                         "tag contains other elements: line:%s\n%s\n\n" %
110
                         (start_line, oval_contents))
111
    if '<' in start_line[1:]:
112
        raise ValueError("Malformed OVAL file: line with starting affected "
113
                         "tag contains other elements: line:%s\n%s\n\n" %
114
                         (start_line, oval_contents))
115
116
    # Validate that end_affected contains only an ending </affected> tag;
117
    # otherwise, using this information to update the <platform> subelements
118
    # would fail.
119
    end_line = oval_contents[end_affected]
120
    end_line = end_line.strip()
121
122
    if not end_line.startswith('</affected>'):
123
        raise ValueError("Malformed OVAL file: line with ending affected "
124
                         "tag contains other elements: line:%s\n%s\n\n" %
125
                         (end_line, oval_contents))
126
    if '<' in end_line[1:]:
127
        raise ValueError("Malformed OVAL file: line with ending affected "
128
                         "tag contains other elements: line:%s\n%s\n\n" %
129
                         (end_line, oval_contents))
130
131
    indents = ""
132
    if start_affected+1 == end_affected:
133
        # Since the affected element is present but empty, the indents should
134
        # be two more spaces than that of the starting <affected> element.
135
        start_index = oval_contents[start_affected].index('<')
136
        indents = oval_contents[start_affected][0:start_index]
137
        indents += "  "
138
    else:
139
        # Otherwise, grab the indents off the next line unmodified, as this is
140
        # likely a platform element tag. We don't validate here that this is
141
        # indeed the case, as other parts of the build infrastructure will
142
        # validate this for us.
143
        start_index = oval_contents[start_affected+1].index('<')
144
        indents = oval_contents[start_affected+1][0:start_index]
145
146
    return start_affected, end_affected, indents
147