Passed
Push — master ( 42467a...9d011f )
by Matěj
03:19 queued 11s
created

rule_dir_diff.main()   D

Complexity

Conditions 13

Size

Total Lines 48
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
cc 13
eloc 38
nop 0
dl 0
loc 48
ccs 0
cts 38
cp 0
crap 182
rs 4.2
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like rule_dir_diff.main() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python
2
3
from __future__ import print_function
4
5
import argparse
6
import os
7
import sys
8
9
import json
10
import pprint
11
12
import ssg.build_yaml
13
import ssg.oval
14
import ssg.build_remediations
15
import ssg.rule_dir_stats as rds
16
import ssg.rules
17
import ssg.yaml
18
19
20
SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
21
22
23
def parse_args():
24
    parser = argparse.ArgumentParser()
25
    parser.add_argument("--left", type=str, action="store", default="build/old_rule_dirs.json",
26
                        help="File to read json output of rule_dir_json from (defaults to " +
27
                             "build/old_rule_dirs.json); left such file for diffing")
28
    parser.add_argument("--right", type=str, action="store", default="build/rule_dirs.json",
29
                        help="File to read json output of rule_dir_json from (defaults to " +
30
                             "build/rule_dirs.json); right such file for diffing")
31
32
    parser.add_argument("-p", "--products", type=str, action="store", default="all",
33
                        help="Products to inquire about, as a comma separated list")
34
    parser.add_argument("-t", "--strict", action="store_true",
35
                        help="Enforce strict --products checking against rule.yml prodtype only")
36
    parser.add_argument("-q", "--query", type=str, action="store", default=None,
37
                        help="Limit actions to only act on a comma separated list of rule_ids")
38
39
    parser.add_argument("-m", "--missing", action="store_true",
40
                        help="List rules which are missing OVALs or fixes")
41
    parser.add_argument("-2", "--two-plus", action="store_true",
42
                        help="List rules which have two or more OVALs or fixes")
43
    parser.add_argument("-r", "--prodtypes", action="store_true",
44
                        help="List rules which have different YAML prodtypes from checks+fix prodtypes")
45
    parser.add_argument("-n", "--product-names", action="store_true",
46
                        help="List rules which have product specific objects with broader accepted products")
47
48
    parser.add_argument("-o", "--ovals-only", action="store_true",
49
                        help="Only output information about OVALs")
50
    parser.add_argument("-f", "--fixes-only", action="store_true",
51
                        help="Only output information about fixes")
52
53
    parser.add_argument("--left-only", action="store_true",
54
                        help="Print only information from the left that is " +
55
                             "not in the right")
56
    parser.add_argument("--right-only", action="store_true",
57
                        help="Print only information from the right that is " +
58
                             "not in the left")
59
    parser.add_argument("--show-common", action="store_true",
60
                        help="Also print information that is common to both")
61
62
    parser.add_argument("-s", "--summary-only", action="store_true",
63
                        help="Only output summary information")
64
65
    return parser.parse_args()
66
67
68
def prefixed_print(statement, prefix):
69
    print("%s %s" % (prefix, statement))
70
71
72
def print_specifics(args, headline, data, prefix):
73
    if not args.summary_only and data:
74
        prefixed_print(headline, prefix)
75
        for line in data:
76
            prefixed_print(line, prefix)
77
        print("\n")
78
79
80
def print_summary(args, statements, data, prefix):
81
    affected_rules, affected_ovals, affected_remediations, affected_remediations_type = data
82
83
    prefixed_print(statements[0], prefix)
84
    prefixed_print(statements[1] % affected_rules, prefix)
85
    if not args.fixes_only:
86
        prefixed_print(statements[2] % (affected_ovals, affected_rules), prefix)
87
    if not args.ovals_only:
88
        prefixed_print(statements[3] % (affected_remediations, affected_rules), prefix)
89
        for r_type in ssg.build_remediations.REMEDIATION_TO_EXT_MAP:
90
            r_missing = affected_remediations_type[r_type]
91
            prefixed_print(statements[4] % (r_type, r_missing, affected_rules), prefix)
92
    print("\n")
93
94
95
def select_indices(data, indices):
96
    return [data[index] for index in indices]
97
98
99 View Code Duplication
def process_diff_missing(args, left_rules, right_rules):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
100
    data = rds.walk_rules_diff(args, left_rules, right_rules, rds.missing_oval, rds.missing_remediation)
101
    result = rds.walk_rules_diff_stats(data)
102
    left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result
103
104
    statements = ["Missing Objects Summary",
105
                  "Total affected rules: %d",
106
                  "Rules with no OVALs: %d / %d",
107
                  "Rules without any remediations: %d / %d",
108
                  "Rules with no %s remediations: %d / %d"]
109
110
    if not args.right_only:
111
        print_specifics(args, "Missing Objects Specifics - Left Only:", left_only_data[5], '<')
112
        print_specifics(args, "Missing Objects Specifics - Left Changed:", left_changed_data[5], '<')
113
114
    if args.show_common:
115
        print_specifics(args, "Missing Objects Specifics - Common:", common_data[5], '=')
116
117
    if not args.left_only:
118
        print_specifics(args, "Missing Objects Specifics - Right Changed:", right_changed_data[5], '>')
119
        print_specifics(args, "Missing Objects Specifics - Right Only:", right_only_data[5], '>')
120
121
    data_indices = [0, 1, 3, 4]
122
123
    if not args.right_only:
124
        statements[0] = "Missing Objects Summary - Left Only:"
125
        l_d = select_indices(left_only_data, data_indices)
126
        print_summary(args, statements, l_d, '<')
127
128
        statements[0] = "Missing Objects Summary - Left Changed:"
129
        l_d = select_indices(left_changed_data, data_indices)
130
        print_summary(args, statements, l_d, '<')
131
132
    if args.show_common:
133
        statements[0] = "Missing Objects Summary - Common:"
134
        c_d = select_indices(common_data, data_indices)
135
        print_summary(args, statements, c_d, '=')
136
137
    if not args.left_only:
138
        statements[0] = "Missing Objects Summary - Right Changed:"
139
        r_d = select_indices(right_changed_data, data_indices)
140
        print_summary(args, statements, r_d, '>')
141
142
        statements[0] = "Missing Objects Summary - Right Only:"
143
        r_d = select_indices(right_only_data, data_indices)
144
        print_summary(args, statements, r_d, '>')
145
146
147 View Code Duplication
def process_diff_two_plus(args, left_rules, right_rules):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
148
    data = rds.walk_rules_diff(args, left_rules, right_rules, rds.two_plus_oval, rds.two_plus_remediation)
149
    result = rds.walk_rules_diff_stats(data)
150
    left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result
151
152
    statements = ["Two Plus Objects Summary:",
153
                  "Total affected rules: %d",
154
                  "Rules with two or more OVALs: %d / %d",
155
                  "Rules with two or more remediations: %d / %d",
156
                  "Rules with two or more %s remediations: %d / %d"]
157
158
    if not args.right_only:
159
        print_specifics(args, "Two Plus Objects Specifics - Left Only:", left_only_data[5], '<')
160
        print_specifics(args, "Two Plus Objects Specifics - Left Changed:", left_changed_data[5], '<')
161
162
    if args.show_common:
163
        print_specifics(args, "Two Plus Objects Specifics - Common:", common_data[5], '=')
164
165
    if not args.left_only:
166
        print_specifics(args, "Two Plus Objects Specifics - Right Changed:", right_changed_data[5], '>')
167
        print_specifics(args, "Two Plus Objects Specifics - Right Only:", right_only_data[5], '>')
168
169
    data_indices = [0, 1, 2, 4]
170
171
    if not args.right_only:
172
        statements[0] = "Two Plus Objects Summary - Left Only:"
173
        l_d = select_indices(left_only_data, data_indices)
174
        print_summary(args, statements, l_d, '<')
175
176
        statements[0] = "Two Plus Objects Summary - Left Changed:"
177
        l_d = select_indices(left_changed_data, data_indices)
178
        print_summary(args, statements, l_d, '<')
179
180
    if args.show_common:
181
        statements[0] = "Two Plus Objects Summary - Common:"
182
        c_d = select_indices(common_data, data_indices)
183
        print_summary(args, statements, c_d, '=')
184
185
    if not args.left_only:
186
        statements[0] = "Two Plus Objects Summary - Right Changed:"
187
        r_d = select_indices(right_changed_data, data_indices)
188
        print_summary(args, statements, r_d, '>')
189
190
        statements[0] = "Two Plus Objects Summary - Right Only:"
191
        r_d = select_indices(right_only_data, data_indices)
192
        print_summary(args, statements, r_d, '>')
193
194
195 View Code Duplication
def process_diff_prodtypes(args, left_rules, right_rules):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
196
    data = rds.walk_rules_diff(args, left_rules, right_rules, rds.prodtypes_oval, rds.prodtypes_remediation)
197
    result = rds.walk_rules_diff_stats(data)
198
    left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result
199
200
    statements = ["Prodtypes Objects Summary",
201
                  "Total affected rules: %d",
202
                  "Rules with differing prodtypes between YAML and OVALs: %d / %d",
203
                  "Rules with differing prodtypes between YAML and remediations: %d / %d",
204
                  "Rules with differing prodtypes between YAML and %s remediations: %d / %d"]
205
206
    if not args.right_only:
207
        print_specifics(args, "Prodtypes Objects Specifics - Left Only:", left_only_data[5], '<')
208
        print_specifics(args, "Prodtypes Objects Specifics - Left Changed:", left_changed_data[5], '<')
209
210
    if args.show_common:
211
        print_specifics(args, "Prodtypes Objects Specifics - Common:", common_data[5], '=')
212
213
    if not args.left_only:
214
        print_specifics(args, "Prodtypes Objects Specifics - Right Changed:", right_changed_data[5], '>')
215
        print_specifics(args, "Prodtypes Objects Specifics - Right Only:", right_only_data[5], '>')
216
217
    data_indices = [0, 1, 2, 4]
218
219
    if not args.right_only:
220
        statements[0] = "Prodtypes Objects Summary - Left Only:"
221
        l_d = select_indices(left_only_data, data_indices)
222
        print_summary(args, statements, l_d, '<')
223
224
        statements[0] = "Prodtypes Objects Summary - Left Changed:"
225
        l_d = select_indices(left_changed_data, data_indices)
226
        print_summary(args, statements, l_d, '<')
227
228
    if args.show_common:
229
        statements[0] = "Prodtypes Objects Summary - Common:"
230
        c_d = select_indices(common_data, data_indices)
231
        print_summary(args, statements, c_d, '=')
232
233
    if not args.left_only:
234
        statements[0] = "Prodtypes Objects Summary - Right Changed:"
235
        r_d = select_indices(right_changed_data, data_indices)
236
        print_summary(args, statements, r_d, '>')
237
238
        statements[0] = "Prodtypes Objects Summary - Right Only:"
239
        r_d = select_indices(right_only_data, data_indices)
240
        print_summary(args, statements, r_d, '>')
241
242
243 View Code Duplication
def process_diff_product_names(args, left_rules, right_rules):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
244
    data = rds.walk_rules_diff(args, left_rules, right_rules, rds.product_names_oval, rds.product_names_remediation)
245
    result = rds.walk_rules_diff_stats(data)
246
    left_only_data, right_only_data, left_changed_data, right_changed_data, common_data = result
247
248
    if not args.right_only:
249
        print_specifics(args, "Product Names Objects Specifics - Left Only:", left_only_data[5], '<')
250
        print_specifics(args, "Product Names Objects Specifics - Left Changed:", left_changed_data[5], '<')
251
252
    if args.show_common:
253
        print_specifics(args, "Product Names Objects Specifics - Common:", common_data[5], '=')
254
255
    if not args.left_only:
256
        print_specifics(args, "Product Names Objects Specifics - Right Changed:", right_changed_data[5], '>')
257
        print_specifics(args, "Product Names Objects Specifics - Right Only:", right_only_data[5], '>')
258
259
    data_indices = [0, 1, 2, 4]
260
    statements = ["Product Names Objects Summary:",
261
                  "Total affected rules: %d",
262
                  "Rules with differing products and OVAL names: %d / %d",
263
                  "Rules with differing product and remediation names: %d / %d",
264
                  "Rules with differing product and %s remediation names: %d / %d"]
265
266
    if not args.right_only:
267
        statements[0] = "Product Names Objects Summary - Left Only:"
268
        l_d = select_indices(left_only_data, data_indices)
269
        print_summary(args, statements, l_d, '<')
270
271
        statements[0] = "Product Names Objects Summary - Left Changed:"
272
        l_d = select_indices(left_changed_data, data_indices)
273
        print_summary(args, statements, l_d, '<')
274
275
    if args.show_common:
276
        statements[0] = "Product Names Objects Summary - Common:"
277
        c_d = select_indices(common_data, data_indices)
278
        print_summary(args, statements, c_d, '=')
279
280
    if not args.left_only:
281
        statements[0] = "Product Names Objects Summary - Right Changed:"
282
        r_d = select_indices(right_changed_data, data_indices)
283
        print_summary(args, statements, r_d, '>')
284
285
        statements[0] = "Product Names Objects Summary - Right Only:"
286
        r_d = select_indices(right_only_data, data_indices)
287
        print_summary(args, statements, r_d, '>')
288
289
290
def main():
291
    args = parse_args()
292
293
    linux_products, other_products = ssg.products.get_all(SSG_ROOT)
294
    all_products = linux_products.union(other_products)
295
296
    left_file = open(args.left, 'r')
297
    left_rules = json.load(left_file)
298
299
    right_file = open(args.right, 'r')
300
    right_rules = json.load(right_file)
301
302
    if left_rules == right_rules:
303
        print("No difference. Please use rule_dir_stats to inspect one of these files.")
304
        sys.exit(0)
305
306
    if args.products.lower() == 'all':
307
        args.products = all_products
308
    elif args.products.lower() == 'linux':
309
        args.products = linux_products
310
    elif args.products.lower() == 'other':
311
        args.products = other_products
312
    else:
313
        args.products = args.products.split(',')
314
    args.products = set(args.products)
315
316
    left_query_keys = rds.filter_rule_ids(set(left_rules), args.query)
317
    right_query_keys = rds.filter_rule_ids(set(right_rules), args.query)
318
    args.query = left_query_keys.union(right_query_keys)
319
    print("Total number of queried rules: %d\n" % len(args.query))
320
321
    if not args.missing and not args.two_plus and not args.prodtypes and not args.product_names:
322
        args.missing = True
323
        args.two_plus = True
324
        args.prodtypes = True
325
326
    print("< Total number of known rule directories: %d" % len(left_rules))
327
    print("> Total number of known rule directories: %d\n" % len(right_rules))
328
    print("= Total number of queried rules: %d\n" % len(args.query))
329
330
    if args.missing:
331
        process_diff_missing(args, left_rules, right_rules)
332
    if args.two_plus:
333
        process_diff_two_plus(args, left_rules, right_rules)
334
    if args.prodtypes:
335
        process_diff_prodtypes(args, left_rules, right_rules)
336
    if args.product_names:
337
        process_diff_product_names(args, left_rules, right_rules)
338
339
340
if __name__ == "__main__":
341
    main()
342