Test Failed
Pull Request — master (#7716)
by Matěj
02:51
created

ssg.rules.get_rule_path_by_id()   A

Complexity

Conditions 5

Size

Total Lines 7
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.0729

Importance

Changes 0
Metric Value
cc 5
eloc 7
nop 2
dl 0
loc 7
ccs 6
cts 7
cp 0.8571
crap 5.0729
rs 9.3333
c 0
b 0
f 0
1 2
from __future__ import absolute_import
2 2
from __future__ import print_function
3
4 2
import os
5 2
from glob import glob
6
7
8 2
def get_rule_dir_yaml(dir_path):
9
    """
10
    Returns the path to the yaml metadata for a rule directory,
11
    regardless of if it exists.
12
    """
13 2
    return os.path.join(dir_path, "rule.yml")
14
15
16 2
def get_rule_dir_id(path):
17
    """
18
    Returns the ID of a rule directory; correctly handles being passed
19
    either the directory path or the yaml metadata path.
20
    """
21 2
    dir_path = path
22
23 2
    if path.endswith("rule.yml"):
24 2
        dir_path = os.path.dirname(path)
25
26 2
    return os.path.basename(dir_path)
27
28
29 2
def is_rule_dir(dir_path):
30
    """
31
    Returns True iff dir_path is a valid rule directory which exists
32
33
    To be valid, dir_path must exist and be a directory and the file
34
    returned by get_rule_dir_yaml(dir_path) must exist.
35
    """
36 2
    rule_yaml = get_rule_dir_yaml(dir_path)
37
38 2
    is_dir = os.path.isdir(dir_path)
39 2
    has_rule_yaml = os.path.exists(rule_yaml)
40
41 2
    return is_dir and has_rule_yaml
42
43
44 2
def applies_to_product(file_name, product):
45
    """
46
    A OVAL or fix is filtered by product iff product is Falsy, file_name is
47
    "shared", or file_name is product. Note that this does not filter by
48
    contents of the fix or check, only by the name of the file.
49
    """
50
51 2
    if not product:
52 2
        return True
53
54 2
    return file_name == "shared" or file_name == product or product.startswith(file_name)
55
56
57 2
def get_rule_dir_ovals(dir_path, product=None):
58
    """
59
    Gets a list of OVALs contained in a rule directory. If product is
60
    None, returns all OVALs. If product is not None, returns applicable
61
    OVALs in order of priority:
62
63
        {{{ product }}}.xml -> shared.xml
64
65
    Only returns OVALs which exist.
66
    """
67
68 2
    if not is_rule_dir(dir_path):
69
        return []
70
71 2
    oval_dir = os.path.join(dir_path, "oval")
72 2
    has_oval_dir = os.path.isdir(oval_dir)
73 2
    if not has_oval_dir:
74
        return []
75
76
    # Two categories of results: those for a product and those that are shared
77
    # to multiple products. Within common results, there's two types:
78
    # those shared to multiple versions of the same type (added up front) and
79
    # those shared across multiple product types (e.g., RHEL and Ubuntu).
80 2
    product_results = []
81 2
    common_results = []
82 2
    for oval_file in sorted(os.listdir(oval_dir)):
83 2
        file_name, ext = os.path.splitext(oval_file)
84 2
        oval_path = os.path.join(oval_dir, oval_file)
85
86 2
        if ext == ".xml" and applies_to_product(file_name, product):
87
            # applies_to_product ensures we only have three entries:
88
            # 1. shared
89
            # 2. <product>
90
            # 3. <product><version>
91 2
            if file_name == 'shared':
92
                # Shared are the lowest priority items, add them to the end of
93
                # the common results.
94 2
                common_results.append(oval_path)
95 2
            elif file_name != product:
96
                # Here, the filename is a subset of the product, but isn't
97
                # the full product. Product here is both the product name
98
                # (e.g., ubuntu) and its version (2004). Filename could be
99
                # either "ubuntu" or "ubuntu2004" so we want this branch
100
                # to trigger when it is the former, not the latter. It is
101
                # the highest priority of common results, so insert it
102
                # before any shared ones.
103 2
                common_results.insert(0, oval_path)
104
            else:
105
                # Finally, this must be a product-specific result.
106 2
                product_results.append(oval_path)
107
108
    # Combine the two sets in priority order.
109 2
    return product_results + common_results
110
111
112 2
def get_rule_dir_sces(dir_path, product=None):
113
    """
114
    Get a list of SCEs contained in a rule directory. If product is None,
115
    returns all SCEs. If product is not None, returns applicable SCEs in
116
    order of priority:
117
118
        {{{ product }}}.{{{ ext }}} -> shared.{{{ ext }}}
119
120
    Only returns SCEs which exist.
121
    """
122
123
    if not is_rule_dir(dir_path):
124
        return []
125
126
    sce_dir = os.path.join(dir_path, "sce")
127
    has_sce_dir = os.path.isdir(sce_dir)
128
    if not has_sce_dir:
129
        return []
130
131
    results = []
132
    common_results = []
133
    for sce_file in sorted(os.listdir(sce_dir)):
134
        file_name, ext = os.path.splitext(sce_file)
135
        sce_path = os.path.join(sce_dir, sce_file)
136
137
        if applies_to_product(file_name, product):
138
            if file_name == 'shared':
139
                common_results.append(sce_path)
140
            elif file_name != product:
141
                common_results.insert(0, sce_path)
142
            else:
143
                results.append(sce_path)
144
145
    return results + common_results
146
147
148 2
def find_rule_dirs(base_dir):
149
    """
150
    Generator which yields all rule directories within a given base_dir, recursively
151
    """
152 2
    for root, dirs, _ in os.walk(base_dir):
153 2
        dirs.sort()
154 2
        for dir_name in dirs:
155 2
            dir_path = os.path.join(root, dir_name)
156 2
            if is_rule_dir(dir_path):
157 2
                yield dir_path
158
159
160 2
def find_rule_dirs_in_paths(base_dirs):
161
    """
162
    Generator which yields all rule directories within a given directories list, recursively
163
    """
164
    if base_dirs:
165
        for cur_dir in base_dirs:
166
            for d in find_rule_dirs(cur_dir):
167
                yield d
168