Passed
Pull Request — master (#3398)
by Matěj
02:34
created

ssg.oval._add_elements()   C

Complexity

Conditions 9

Size

Total Lines 38
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 80.2835

Importance

Changes 0
Metric Value
cc 9
eloc 30
nop 2
dl 0
loc 38
ccs 1
cts 24
cp 0.0417
crap 80.2835
rs 6.6666
c 0
b 0
f 0
1 2
from __future__ import absolute_import
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2 2
from __future__ import print_function
3
4 2
import sys
5 2
import os
6 2
import re
7 2
import argparse
8 2
import tempfile
9 2
import subprocess
10
11 2
from .constants import oval_footer as footer
12 2
from .constants import oval_namespace as ovalns
13 2
from .rules import get_rule_dir_id, get_rule_dir_ovals, find_rule_dirs
14 2
from .xml import ElementTree as ET
15 2
from .xml import oval_generated_header
16 2
from .id_translate import IDTranslator
17
18 2
SHARED_OVAL = re.sub(r'ssg/.*', 'shared', __file__) + '/checks/oval/'
19 2
LINUX_OS_GUIDE = re.sub(r'ssg/.*', 'linux_os', __file__) + '/guide/'
20
21
22
# globals, to make recursion easier in case we encounter extend_definition
23 2
try:
24 2
    ET.register_namespace("oval", ovalns)
25
except AttributeError:
26
    # Legacy Python 2.6 fix, see e.g.
27
    # https://www.programcreek.com/python/example/57552/xml.etree.ElementTree._namespace_map
28
    from xml.etree import ElementTree as ET
29
    ET._namespace_map[ovalns] = "oval"
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _namespace_map was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
30
31 2
definitions = ET.Element("oval:definitions")
0 ignored issues
show
Coding Style Naming introduced by
The name definitions does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
32 2
tests = ET.Element("oval:tests")
0 ignored issues
show
Coding Style Naming introduced by
The name tests does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
33 2
objects = ET.Element("oval:objects")
0 ignored issues
show
Coding Style Naming introduced by
The name objects does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
34 2
states = ET.Element("oval:states")
0 ignored issues
show
Coding Style Naming introduced by
The name states does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
35 2
variables = ET.Element("oval:variables")
0 ignored issues
show
Coding Style Naming introduced by
The name variables does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
36 2
silent_mode = False
0 ignored issues
show
Coding Style Naming introduced by
The name silent_mode does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
37
38
39
# append new child ONLY if it's not a duplicate
40 2
def append(element, newchild):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
41
    global silent_mode
0 ignored issues
show
Coding Style Naming introduced by
The name silent_mode does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
42
    newid = newchild.get("id")
43
    existing = element.find(".//*[@id='" + newid + "']")
44
    if existing is not None:
45
        if not silent_mode:
46
            sys.stderr.write("Notification: this ID is used more than once " +
47
                             "and should represent equivalent elements: " +
48
                             newid + "\n")
49
    else:
50
        element.append(newchild)
51
52
53 2
def _add_elements(body, header):
54
    """Add oval elements to the global Elements defined above"""
55
    global definitions
0 ignored issues
show
Coding Style Naming introduced by
The name definitions does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
56
    global tests
0 ignored issues
show
Coding Style Naming introduced by
The name tests does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
57
    global objects
0 ignored issues
show
Coding Style Naming introduced by
The name objects does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
58
    global states
0 ignored issues
show
Coding Style Naming introduced by
The name states does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
59
    global variables
0 ignored issues
show
Coding Style Naming introduced by
The name variables does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
60
61
    tree = ET.fromstring(header + body + footer)
62
    tree = replace_external_vars(tree)
63
    defname = None
64
    # parse new file(string) as an etree, so we can arrange elements
65
    # appropriately
66
    for childnode in tree.findall("./{%s}def-group/*" % ovalns):
67
        # print "childnode.tag is " + childnode.tag
68
        if childnode.tag is ET.Comment:
69
            continue
70
        if childnode.tag == ("{%s}definition" % ovalns):
71
            append(definitions, childnode)
72
            defname = childnode.get("id")
73
            # extend_definition is a special case:  must include a whole other
74
            # definition
75
            for defchild in childnode.findall(".//{%s}extend_definition"
76
                                              % ovalns):
77
                defid = defchild.get("definition_ref")
78
                extend_ref = find_testfile_or_exit(defid)
79
                includedbody = read_ovaldefgroup_file(extend_ref)
80
                # recursively add the elements in the other file
81
                _add_elements(includedbody, header)
82
        if childnode.tag.endswith("_test"):
83
            append(tests, childnode)
84
        if childnode.tag.endswith("_object"):
85
            append(objects, childnode)
86
        if childnode.tag.endswith("_state"):
87
            append(states, childnode)
88
        if childnode.tag.endswith("_variable"):
89
            append(variables, childnode)
90
    return defname
91
92
93 2
def applicable_platforms(oval_file):
94
    """
95
    Returns the applicable platforms for a given oval file
96
    """
97
98 2
    platforms = []
99 2
    header = oval_generated_header("applicable_platforms", "5.11", "0.0.1")
100 2
    body = read_ovaldefgroup_file(oval_file)
101 2
    oval_tree = ET.fromstring(header + body + footer)
102
103 2
    element_path = "./{%s}def-group/{%s}definition/{%s}metadata/{%s}affected/{%s}platform"
104 2
    element_ns_path = element_path % (ovalns, ovalns, ovalns, ovalns, ovalns)
105 2
    for node in oval_tree.findall(element_ns_path):
106 2
        platforms.append(node.text)
107
108 2
    return platforms
109
110
111 2
def parse_affected(oval_contents):
112
    """
113
    Returns the tuple (start_affected, end_affected, platform_indents) for
114
    the passed oval file contents. start_affected is the line number of
115
    starting tag of the <affected> element, end_affected is the line number of
116
    the closing tag of the </affected> element, and platform_indents is a
117
    string containing the indenting characters before the contents of the
118
    <affected> element.
119
    """
120
121
    start_affected = list(filter(lambda x: "<affected" in oval_contents[x],
122
                                 range(0, len(oval_contents))))
123
    if len(start_affected) != 1:
124
        raise ValueError("OVAL file does not contain a single <affected> "
125
                         "element; counted %d in:\n%s\n\n" %
126
                         (len(start_affected), "\n".join(oval_contents)))
127
128
    start_affected = start_affected[0]
129
130
    end_affected = list(filter(lambda x: "</affected" in oval_contents[x],
131
                               range(0, len(oval_contents))))
132
    if len(end_affected) != 1:
133
        raise ValueError("Malformed OVAL file does not contain a single "
134
                         "closing </affected>; counted %d in:\n%s\n\n" %
135
                         (len(start_affected), "\n".join(oval_contents)))
136
    end_affected = end_affected[0]
137
138
    if start_affected >= end_affected:
139
        raise ValueError("Malformed OVAL file: start affected tag begins "
140
                         "on the same line or after ending affected tag: "
141
                         "start:%d vs end:%d:\n%s\n\n" %
142
                         (start_affected, end_affected, oval_contents))
143
144
    # Validate that start_affected contains only a starting <affected> tag;
145
    # otherwise, using this information to update the <platform> subelements
146
    # would fail.
147
    start_line = oval_contents[start_affected]
148
    start_line = start_line.strip()
149
150
    if not start_line.startswith('<affected'):
151
        raise ValueError("Malformed OVAL file: line with starting affected "
152
                         "tag contains other elements: line:%s\n%s\n\n" %
153
                         (start_line, oval_contents))
154
    if '<' in start_line[1:]:
155
        raise ValueError("Malformed OVAL file: line with starting affected "
156
                         "tag contains other elements: line:%s\n%s\n\n" %
157
                         (start_line, oval_contents))
158
159
    # Validate that end_affected contains only an ending </affected> tag;
160
    # otherwise, using this information to update the <platform> subelements
161
    # would fail.
162
    end_line = oval_contents[end_affected]
163
    end_line = end_line.strip()
164
165
    if not end_line.startswith('</affected>'):
166
        raise ValueError("Malformed OVAL file: line with ending affected "
167
                         "tag contains other elements: line:%s\n%s\n\n" %
168
                         (end_line, oval_contents))
169
    if '<' in end_line[1:]:
170
        raise ValueError("Malformed OVAL file: line with ending affected "
171
                         "tag contains other elements: line:%s\n%s\n\n" %
172
                         (end_line, oval_contents))
173
174
    indents = ""
175
    if start_affected+1 == end_affected:
176
        # Since the affected element is present but empty, the indents should
177
        # be two more spaces than that of the starting <affected> element.
178
        start_index = oval_contents[start_affected].index('<')
179
        indents = oval_contents[start_affected][0:start_index]
180
        indents += "  "
181
    else:
182
        # Otherwise, grab the indents off the next line unmodified, as this is
183
        # likely a platform element tag. We don't validate here that this is
184
        # indeed the case, as other parts of the build infrastructure will
185
        # validate this for us.
186
        start_index = oval_contents[start_affected+1].index('<')
187
        indents = oval_contents[start_affected+1][0:start_index]
188
189
    return start_affected, end_affected, indents
190
191
192 2
def replace_external_vars(tree):
193
    """Replace external_variables with local_variables, so the definition can be
194
       tested independently of an XCCDF file"""
195
196
    # external_variable is a special case: we turn it into a local_variable so
197
    # we can test
198
    for node in tree.findall(".//{%s}external_variable" % ovalns):
199
        print("External_variable with id : " + node.get("id"))
200
        extvar_id = node.get("id")
201
        # for envkey, envval in os.environ.iteritems():
202
        #     print envkey + " = " + envval
203
        # sys.exit()
204
        if extvar_id not in os.environ.keys():
205
            print("External_variable specified, but no value provided via "
206
                  "environment variable", file=sys.stderr)
207
            sys.exit(2)
208
        # replace tag name: external -> local
209
        node.tag = "{%s}local_variable" % ovalns
210
        literal = ET.Element("oval:literal_component")
211
        literal.text = os.environ[extvar_id]
212
        node.append(literal)
213
        # TODO: assignment of external_variable via environment vars, for
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
214
        # testing
215
    return tree
216
217
218 2
def find_testfile_or_exit(testfile):
219
    """Find OVAL files in CWD or shared/oval and calls sys.exit if the file is not found"""
220
    _testfile = find_testfile(testfile)
221
    if _testfile is None:
222
        print("ERROR: %s does not exist! Please specify a valid OVAL file." % testfile,
223
              file=sys.stderr)
224
        sys.exit(1)
225
    else:
226
        return _testfile
227
228
229 2
def find_testfile(oval_id):
230
    """
231
    Find OVAL file by id in CWD, SHARED_OVAL, or LINUX_OS_GUIDE. Understands rule
232
    directories and defaults to returning shared.xml over {{{ product }}}.xml.
233
234
    Returns path to OVAL file or None if not found.
235
    """
236 2
    if os.path.isfile(os.path.abspath(oval_id)):
237
        return os.path.abspath(oval_id)
238
239 2
    if oval_id.endswith(".xml"):
240 2
        oval_id, _ = os.path.splitext(oval_id)
241 2
        oval_id = os.path.basename(oval_id)
242
243 2
    candidates = [oval_id, "%s.xml" % oval_id]
244
245 2
    found_file = None
246 2
    for path in ['.', SHARED_OVAL, LINUX_OS_GUIDE]:
247 2
        for root, _, _ in os.walk(path):
248 2
            for candidate in candidates:
249 2
                search_file = os.path.join(root, candidate).strip()
250 2
                if os.path.isfile(search_file):
251
                    found_file = search_file
252
                    break
253
254 2
        for rule_dir in find_rule_dirs(path):
255 2
            rule_id = get_rule_dir_id(rule_dir)
256 2
            if rule_id == oval_id:
257 2
                ovals = get_rule_dir_ovals(rule_dir, product="shared")
258 2
                if ovals:
259 2
                    found_file = ovals[0]
260 2
                    break
261
262 2
    return found_file
263
264
265 2
def read_ovaldefgroup_file(testfile):
266
    """Read oval files"""
267 2
    with open(testfile, 'r') as test_file:
268 2
        body = test_file.read()
269 2
    return body
270
271
272 2
def get_openscap_supported_oval_version():
0 ignored issues
show
Coding Style Naming introduced by
The name get_openscap_supported_oval_version does not conform to the function naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
273
    try:
274
        from openscap import oscap_get_version
275
        if [int(x) for x in str(oscap_get_version()).split(".")] >= [1, 2, 0]:
276
            return "5.11"
277
    except ImportError:
278
        pass
279
280
    return "5.10"
281
282
283 2
def parse_options():
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
284
    usage = "usage: %(prog)s [options] definition_file.xml"
285
    parser = argparse.ArgumentParser(usage=usage)
286
    # only some options are on by default
287
288
    oscap_oval_version = get_openscap_supported_oval_version()
289
290
    parser.add_argument("--oval_version",
291
                        default=oscap_oval_version,
292
                        dest="oval_version", action="store",
293
                        help="OVAL version to use. Example: 5.11, 5.10, ... "
294
                             "If not supplied the highest version supported by "
295
                             "openscap will be used: %s" % (oscap_oval_version))
296
    parser.add_argument("-q", "--quiet", "--silent", default=False,
297
                        action="store_true", dest="silent_mode",
298
                        help="Don't show any output when testing OVAL files")
299
    parser.add_argument("xmlfile", metavar="XMLFILE", help="OVAL XML file")
300
    args = parser.parse_args()
301
302
    return args
303
304
305 2
def main():
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
306
    global definitions
0 ignored issues
show
Coding Style Naming introduced by
The name definitions does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
307
    global tests
0 ignored issues
show
Coding Style Naming introduced by
The name tests does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
308
    global objects
0 ignored issues
show
Coding Style Naming introduced by
The name objects does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
309
    global states
0 ignored issues
show
Coding Style Naming introduced by
The name states does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
310
    global variables
0 ignored issues
show
Coding Style Naming introduced by
The name variables does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
311
    global silent_mode
0 ignored issues
show
Coding Style Naming introduced by
The name silent_mode does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
312
313
    args = parse_options()
314
    silent_mode = args.silent_mode
315
    oval_version = args.oval_version
316
317
    testfile = args.xmlfile
318
    header = oval_generated_header("testoval.py", oval_version, "0.0.1")
319
    testfile = find_testfile_or_exit(testfile)
320
    body = read_ovaldefgroup_file(testfile)
321
322
    defname = _add_elements(body, header)
323
    if defname is None:
324
        print("Error while evaluating oval: defname not set; missing "
325
              "definitions section?")
326
        sys.exit(1)
327
328
    ovaltree = ET.fromstring(header + footer)
329
330
    # append each major element type, if it has subelements
331
    for element in [definitions, tests, objects, states, variables]:
332
        if list(element):
333
            ovaltree.append(element)
334
335
    # re-map all the element ids from meaningful names to meaningless
336
    # numbers
337
    testtranslator = IDTranslator("scap-security-guide.testing")
338
    ovaltree = testtranslator.translate(ovaltree)
339
    (ovalfile, fname) = tempfile.mkstemp(prefix=defname, suffix=".xml")
340
    os.write(ovalfile, ET.tostring(ovaltree))
341
    os.close(ovalfile)
342
343
    cmd = ['oscap', 'oval', 'eval', '--results', fname + '-results', fname]
344
    if not silent_mode:
345
        print("Evaluating with OVAL tempfile: " + fname)
346
        print("OVAL Schema Version: %s" % oval_version)
347
        print("Writing results to: " + fname + "-results")
348
        print("Running command: %s\n" % " ".join(cmd))
349
350
    oscap_child = subprocess.Popen(cmd, stdout=subprocess.PIPE)
351
    cmd_out = oscap_child.communicate()[0]
352
353
    if isinstance(cmd_out, bytes):
354
        cmd_out = cmd_out.decode('utf-8')
355
356
    if not silent_mode:
357
        print(cmd_out, file=sys.stderr)
358
359
    if oscap_child.returncode != 0:
360
        if not silent_mode:
361
            print("Error launching 'oscap' command: return code %d" % oscap_child.returncode)
362
        sys.exit(2)
363
364
    if 'false' in cmd_out or 'error' in cmd_out:
365
        # at least one from the evaluated OVAL definitions evaluated to
366
        # 'false' result, exit with '1' to indicate OVAL scan FAIL result
367
        sys.exit(1)
368
369
    # perhaps delete tempfile?
370
    definitions = ET.Element("oval:definitions")
371
    tests = ET.Element("oval:tests")
372
    objects = ET.Element("oval:objects")
373
    states = ET.Element("oval:states")
374
    variables = ET.Element("oval:variables")
375
376
    # 'false' keyword wasn't found in oscap's command output
377
    # exit with '0' to indicate OVAL scan TRUE result
378
    sys.exit(0)
379