Passed
Pull Request — master (#3513)
by Alexander
04:42 queued 02:00
created

ssg.oval.read_ovaldefgroup_file()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 3.6875

Importance

Changes 0
Metric Value
cc 2
eloc 4
nop 1
dl 0
loc 5
ccs 1
cts 4
cp 0.25
crap 3.6875
rs 10
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 .yaml import process_file
17 2
from .id_translate import IDTranslator
18
19 2
SHARED_OVAL = re.sub(r'ssg/.*', 'shared', __file__) + '/checks/oval/'
20 2
LINUX_OS_GUIDE = re.sub(r'ssg/.*', 'linux_os', __file__) + '/guide/'
21
22
23
# globals, to make recursion easier in case we encounter extend_definition
24 2
try:
25 2
    ET.register_namespace("oval", ovalns)
26
except AttributeError:
27
    # Legacy Python 2.6 fix, see e.g.
28
    # https://www.programcreek.com/python/example/57552/xml.etree.ElementTree._namespace_map
29
    from xml.etree import ElementTree as ET
30
    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...
31
32 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...
33 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...
34 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...
35 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...
36 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...
37 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...
38
39
40
# append new child ONLY if it's not a duplicate
41 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...
42
    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...
43
    newid = newchild.get("id")
44
    existing = element.find(".//*[@id='" + newid + "']")
45
    if existing is not None:
46
        if not silent_mode:
47
            sys.stderr.write("Notification: this ID is used more than once " +
48
                             "and should represent equivalent elements: " +
49
                             newid + "\n")
50
    else:
51
        element.append(newchild)
52
53
54 2
def _add_elements(body, header):
55
    """Add oval elements to the global Elements defined above"""
56
    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...
57
    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...
58
    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...
59
    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...
60
    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...
61
62
    tree = ET.fromstring(header + body + footer)
63
    tree = replace_external_vars(tree)
64
    defname = None
65
    # parse new file(string) as an etree, so we can arrange elements
66
    # appropriately
67
    for childnode in tree.findall("./{%s}def-group/*" % ovalns):
68
        # print "childnode.tag is " + childnode.tag
69
        if childnode.tag is ET.Comment:
70
            continue
71
        if childnode.tag == ("{%s}definition" % ovalns):
72
            append(definitions, childnode)
73
            defname = childnode.get("id")
74
            # extend_definition is a special case:  must include a whole other
75
            # definition
76
            for defchild in childnode.findall(".//{%s}extend_definition"
77
                                              % ovalns):
78
                defid = defchild.get("definition_ref")
79
                extend_ref = find_testfile_or_exit(defid)
80
                includedbody = read_ovaldefgroup_file(extend_ref)
81
                # recursively add the elements in the other file
82
                _add_elements(includedbody, header)
83
        if childnode.tag.endswith("_test"):
84
            append(tests, childnode)
85
        if childnode.tag.endswith("_object"):
86
            append(objects, childnode)
87
        if childnode.tag.endswith("_state"):
88
            append(states, childnode)
89
        if childnode.tag.endswith("_variable"):
90
            append(variables, childnode)
91
    return defname
92
93
94 2
def applicable_platforms(oval_file):
95
    """
96
    Returns the applicable platforms for a given oval file
97
    """
98
99 2
    platforms = []
100 2
    header = oval_generated_header("applicable_platforms", "5.11", "0.0.1")
101 2
    body = process_file(oval_file, {})
102 2
    oval_tree = ET.fromstring(header + body + footer)
103
104 2
    element_path = "./{%s}def-group/{%s}definition/{%s}metadata/{%s}affected/{%s}platform"
105 2
    element_ns_path = element_path % (ovalns, ovalns, ovalns, ovalns, ovalns)
106 2
    for node in oval_tree.findall(element_ns_path):
107 2
        platforms.append(node.text)
108
109 2
    return platforms
110
111
112 2
def parse_affected(oval_contents):
113
    """
114
    Returns the tuple (start_affected, end_affected, platform_indents) for
115
    the passed oval file contents. start_affected is the line number of
116
    starting tag of the <affected> element, end_affected is the line number of
117
    the closing tag of the </affected> element, and platform_indents is a
118
    string containing the indenting characters before the contents of the
119
    <affected> element.
120
    """
121
122
    start_affected = list(filter(lambda x: "<affected" in oval_contents[x],
123
                                 range(0, len(oval_contents))))
124
    if len(start_affected) != 1:
125
        raise ValueError("OVAL file does not contain a single <affected> "
126
                         "element; counted %d in:\n%s\n\n" %
127
                         (len(start_affected), "\n".join(oval_contents)))
128
129
    start_affected = start_affected[0]
130
131
    end_affected = list(filter(lambda x: "</affected" in oval_contents[x],
132
                               range(0, len(oval_contents))))
133
    if len(end_affected) != 1:
134
        raise ValueError("Malformed OVAL file does not contain a single "
135
                         "closing </affected>; counted %d in:\n%s\n\n" %
136
                         (len(start_affected), "\n".join(oval_contents)))
137
    end_affected = end_affected[0]
138
139
    if start_affected >= end_affected:
140
        raise ValueError("Malformed OVAL file: start affected tag begins "
141
                         "on the same line or after ending affected tag: "
142
                         "start:%d vs end:%d:\n%s\n\n" %
143
                         (start_affected, end_affected, oval_contents))
144
145
    # Validate that start_affected contains only a starting <affected> tag;
146
    # otherwise, using this information to update the <platform> subelements
147
    # would fail.
148
    start_line = oval_contents[start_affected]
149
    start_line = start_line.strip()
150
151
    if not start_line.startswith('<affected'):
152
        raise ValueError("Malformed OVAL file: line with starting affected "
153
                         "tag contains other elements: line:%s\n%s\n\n" %
154
                         (start_line, oval_contents))
155
    if '<' in start_line[1:]:
156
        raise ValueError("Malformed OVAL file: line with starting affected "
157
                         "tag contains other elements: line:%s\n%s\n\n" %
158
                         (start_line, oval_contents))
159
160
    # Validate that end_affected contains only an ending </affected> tag;
161
    # otherwise, using this information to update the <platform> subelements
162
    # would fail.
163
    end_line = oval_contents[end_affected]
164
    end_line = end_line.strip()
165
166
    if not end_line.startswith('</affected>'):
167
        raise ValueError("Malformed OVAL file: line with ending affected "
168
                         "tag contains other elements: line:%s\n%s\n\n" %
169
                         (end_line, oval_contents))
170
    if '<' in end_line[1:]:
171
        raise ValueError("Malformed OVAL file: line with ending affected "
172
                         "tag contains other elements: line:%s\n%s\n\n" %
173
                         (end_line, oval_contents))
174
175
    indents = ""
176
    if start_affected+1 == end_affected:
177
        # Since the affected element is present but empty, the indents should
178
        # be two more spaces than that of the starting <affected> element.
179
        start_index = oval_contents[start_affected].index('<')
180
        indents = oval_contents[start_affected][0:start_index]
181
        indents += "  "
182
    else:
183
        # Otherwise, grab the indents off the next line unmodified, as this is
184
        # likely a platform element tag. We don't validate here that this is
185
        # indeed the case, as other parts of the build infrastructure will
186
        # validate this for us.
187
        start_index = oval_contents[start_affected+1].index('<')
188
        indents = oval_contents[start_affected+1][0:start_index]
189
190
    return start_affected, end_affected, indents
191
192
193 2
def replace_external_vars(tree):
194
    """Replace external_variables with local_variables, so the definition can be
195
       tested independently of an XCCDF file"""
196
197
    # external_variable is a special case: we turn it into a local_variable so
198
    # we can test
199
    for node in tree.findall(".//{%s}external_variable" % ovalns):
200
        print("External_variable with id : " + node.get("id"))
201
        extvar_id = node.get("id")
202
        # for envkey, envval in os.environ.iteritems():
203
        #     print envkey + " = " + envval
204
        # sys.exit()
205
        if extvar_id not in os.environ.keys():
206
            print("External_variable specified, but no value provided via "
207
                  "environment variable", file=sys.stderr)
208
            sys.exit(2)
209
        # replace tag name: external -> local
210
        node.tag = "{%s}local_variable" % ovalns
211
        literal = ET.Element("oval:literal_component")
212
        literal.text = os.environ[extvar_id]
213
        node.append(literal)
214
        # 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...
215
        # testing
216
    return tree
217
218
219 2
def find_testfile_or_exit(testfile):
220
    """Find OVAL files in CWD or shared/oval and calls sys.exit if the file is not found"""
221
    _testfile = find_testfile(testfile)
222
    if _testfile is None:
223
        print("ERROR: %s does not exist! Please specify a valid OVAL file." % testfile,
224
              file=sys.stderr)
225
        sys.exit(1)
226
    else:
227
        return _testfile
228
229
230 2
def find_testfile(oval_id):
231
    """
232
    Find OVAL file by id in CWD, SHARED_OVAL, or LINUX_OS_GUIDE. Understands rule
233
    directories and defaults to returning shared.xml over {{{ product }}}.xml.
234
235
    Returns path to OVAL file or None if not found.
236
    """
237 2
    if os.path.isfile(os.path.abspath(oval_id)):
238
        return os.path.abspath(oval_id)
239
240 2
    if oval_id.endswith(".xml"):
241 2
        oval_id, _ = os.path.splitext(oval_id)
242 2
        oval_id = os.path.basename(oval_id)
243
244 2
    candidates = [oval_id, "%s.xml" % oval_id]
245
246 2
    found_file = None
247 2
    for path in ['.', SHARED_OVAL, LINUX_OS_GUIDE]:
248 2
        for root, _, _ in os.walk(path):
249 2
            for candidate in candidates:
250 2
                search_file = os.path.join(root, candidate).strip()
251 2
                if os.path.isfile(search_file):
252
                    found_file = search_file
253
                    break
254
255 2
        for rule_dir in find_rule_dirs(path):
256 2
            rule_id = get_rule_dir_id(rule_dir)
257 2
            if rule_id == oval_id:
258 2
                ovals = get_rule_dir_ovals(rule_dir, product="shared")
259 2
                if ovals:
260 2
                    found_file = ovals[0]
261 2
                    break
262
263 2
    return found_file
264
265
266 2
def read_ovaldefgroup_file(testfile):
267
    """Read oval files"""
268
    with open(testfile, 'r') as test_file:
269
        body = test_file.read()
270
    return body
271
272
273 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...
274
    try:
275
        from openscap import oscap_get_version
276
        if [int(x) for x in str(oscap_get_version()).split(".")] >= [1, 2, 0]:
277
            return "5.11"
278
    except ImportError:
279
        pass
280
281
    return "5.10"
282
283
284 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...
285
    usage = "usage: %(prog)s [options] definition_file.xml"
286
    parser = argparse.ArgumentParser(usage=usage)
287
    # only some options are on by default
288
289
    oscap_oval_version = get_openscap_supported_oval_version()
290
291
    parser.add_argument("--oval_version",
292
                        default=oscap_oval_version,
293
                        dest="oval_version", action="store",
294
                        help="OVAL version to use. Example: 5.11, 5.10, ... "
295
                             "If not supplied the highest version supported by "
296
                             "openscap will be used: %s" % (oscap_oval_version))
297
    parser.add_argument("-q", "--quiet", "--silent", default=False,
298
                        action="store_true", dest="silent_mode",
299
                        help="Don't show any output when testing OVAL files")
300
    parser.add_argument("xmlfile", metavar="XMLFILE", help="OVAL XML file")
301
    args = parser.parse_args()
302
303
    return args
304
305
306 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...
307
    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...
308
    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...
309
    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...
310
    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...
311
    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...
312
    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...
313
314
    args = parse_options()
315
    silent_mode = args.silent_mode
316
    oval_version = args.oval_version
317
318
    testfile = args.xmlfile
319
    header = oval_generated_header("testoval.py", oval_version, "0.0.1")
320
    testfile = find_testfile_or_exit(testfile)
321
    body = read_ovaldefgroup_file(testfile)
322
323
    defname = _add_elements(body, header)
324
    if defname is None:
325
        print("Error while evaluating oval: defname not set; missing "
326
              "definitions section?")
327
        sys.exit(1)
328
329
    ovaltree = ET.fromstring(header + footer)
330
331
    # append each major element type, if it has subelements
332
    for element in [definitions, tests, objects, states, variables]:
333
        if list(element):
334
            ovaltree.append(element)
335
336
    # re-map all the element ids from meaningful names to meaningless
337
    # numbers
338
    testtranslator = IDTranslator("scap-security-guide.testing")
339
    ovaltree = testtranslator.translate(ovaltree)
340
    (ovalfile, fname) = tempfile.mkstemp(prefix=defname, suffix=".xml")
341
    os.write(ovalfile, ET.tostring(ovaltree))
342
    os.close(ovalfile)
343
344
    cmd = ['oscap', 'oval', 'eval', '--results', fname + '-results', fname]
345
    if not silent_mode:
346
        print("Evaluating with OVAL tempfile: " + fname)
347
        print("OVAL Schema Version: %s" % oval_version)
348
        print("Writing results to: " + fname + "-results")
349
        print("Running command: %s\n" % " ".join(cmd))
350
351
    oscap_child = subprocess.Popen(cmd, stdout=subprocess.PIPE)
352
    cmd_out = oscap_child.communicate()[0]
353
354
    if isinstance(cmd_out, bytes):
355
        cmd_out = cmd_out.decode('utf-8')
356
357
    if not silent_mode:
358
        print(cmd_out, file=sys.stderr)
359
360
    if oscap_child.returncode != 0:
361
        if not silent_mode:
362
            print("Error launching 'oscap' command: return code %d" % oscap_child.returncode)
363
        sys.exit(2)
364
365
    if 'false' in cmd_out or 'error' in cmd_out:
366
        # at least one from the evaluated OVAL definitions evaluated to
367
        # 'false' result, exit with '1' to indicate OVAL scan FAIL result
368
        sys.exit(1)
369
370
    # perhaps delete tempfile?
371
    definitions = ET.Element("oval:definitions")
372
    tests = ET.Element("oval:tests")
373
    objects = ET.Element("oval:objects")
374
    states = ET.Element("oval:states")
375
    variables = ET.Element("oval:variables")
376
377
    # 'false' keyword wasn't found in oscap's command output
378
    # exit with '0' to indicate OVAL scan TRUE result
379
    sys.exit(0)
380