Passed
Push — master ( 8b9f7f...914492 )
by Marek
02:15
created

mod_fixes.diff_fixes()   B

Complexity

Conditions 6

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 8
nop 3
dl 0
loc 10
rs 8.6666
c 0
b 0
f 0
ccs 0
cts 8
cp 0
crap 42
1
#!/usr/bin/env python3
2
3
import sys
4
import os
5
import argparse
6
import subprocess
7
import json
8
9
import ssg.build_remediations
10
import ssg.fixes
11
import ssg.rule_yaml
12
import ssg.utils
13
14
SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
15
REMEDIATION_LANGS = list(ssg.build_remediations.REMEDIATION_TO_EXT_MAP)
16
17
18 View Code Duplication
def parse_args():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
19
    parser = argparse.ArgumentParser()
20
    parser.add_argument("-j", "--json", type=str, action="store", default="build/rule_dirs.json",
21
                        help="File to read json output of rule_dir_json from (defaults "
22
                             "to build/rule_dirs.json)")
23
    parser.add_argument("rule_id", type=str, help="Rule to change, by id")
24
    parser.add_argument("fix_lang", choices=REMEDIATION_LANGS, help="Remediation to change")
25
    parser.add_argument("action", choices=['add', 'remove', 'list', 'replace', 'delete', 'make_shared', 'diff'],
26
                        help="Rule to change, by id")
27
    parser.add_argument("products", type=str, nargs='*',
28
                        help="Products or platforms to perform action with on rule_id. For replace, "
29
                             "the expected format is "
30
                             "platform[,other_platform]~platform[,other_platform] "
31
                             "where the first half is the platforms that are required to "
32
                             "match, and are replaced by the platforms in the second half "
33
                             "if all match. Add and remove require platforms and only apply "
34
                             "to the shared OVAL; delete, make_shared, and diff require products.")
35
    return parser.parse_args()
36
37
38
def list_platforms(rule_obj, lang):
39
    print("Computed products:")
40
    for fix_id in sorted(rule_obj['remediations'].get(lang, {})):
41
        fix = rule_obj['remediations'][lang][fix_id]
42
43
        print(" - %s" % fix_id)
44
        for product in sorted(fix.get('products', [])):
45
            print("   - %s" % product)
46
47
    print("")
48
49
    print("Actual platforms:")
50
    for rule_id in sorted(rule_obj['remediations'].get(lang, {})):
51
        fix = rule_obj['remediations'][lang][rule_id]
52
        fix_file = ssg.fixes.get_fix_path(rule_obj, lang, rule_id)
53
        platforms = ssg.fixes.applicable_platforms(fix_file)
54
55
        print(" - %s" % fix_id)
0 ignored issues
show
introduced by
The variable fix_id does not seem to be defined in case the for loop on line 40 is not entered. Are you sure this can never be the case?
Loading history...
56
        for platform in platforms:
57
            print("   - %s" % platform)
58
59
    print("")
60
61
62
def add_platforms(rule_obj, lang, platforms):
63
    fix_file, fix_contents = ssg.fixes.get_fix_contents(rule_obj, lang, 'shared')
64
    current_platforms = ssg.fixes.applicable_platforms(fix_file)
65
    new_platforms = set(current_platforms)
66
    new_platforms.update(platforms)
67
68
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
69
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
70
71
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
72
                                                      new_platforms)
73
    ssg.utils.write_list_file(fix_file, new_contents)
74
75
76
def remove_platforms(rule_obj, lang, platforms):
77
    fix_file, fix_contents = ssg.fixes.get_fix_contents(rule_obj, lang, 'shared')
78
    current_platforms = ssg.fixes.applicable_platforms(fix_file)
79
    new_platforms = set(current_platforms).difference(platforms)
80
81
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
82
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
83
84
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
85
                                                      new_platforms)
86
    ssg.utils.write_list_file(fix_file, new_contents)
87
88
89 View Code Duplication
def replace_platforms(rule_obj, lang, platforms):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
90
    fix_file, fix_contents = ssg.fixes.get_fix_contents(rule_obj, lang, 'shared')
91
    current_platforms = ssg.fixes.applicable_platforms(fix_file)
92
    new_platforms = set(current_platforms)
93
94
    for platform in platforms:
95
        parsed_platform = platform.split('~')
96
        if not len(parsed_platform) == 2:
97
            print("Invalid platform replacement description: %s" % product,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable product does not seem to be defined.
Loading history...
98
                  file=sys.stderr)
99
            sys.exit(1)
100
101
        match = ssg.rule_yaml.parse_prodtype(parsed_platform[0])
102
        replacement = ssg.rule_yaml.parse_prodtype(parsed_platform[1])
103
104
        if match.issubset(current_platforms):
105
            new_platforms.difference_update(match)
106
            new_platforms.update(replacement)
107
108
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
109
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
110
111
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
112
                                                      new_platforms)
113
    ssg.utils.write_list_file(fix_file, new_contents)
114
115
116
def delete_fixes(rule_obj, lang, products):
117
    for product in products:
118
        fix_file = ssg.fixes.get_fix_path(rule_obj, lang, product)
119
        os.remove(fix_file)
120
        print("Removed: %s" % fix_file)
121
122
123
def make_shared_fix(rule_obj, lang, products):
124
    if not products or len(products) > 1:
125
        raise ValueError("Must pass exactly one product for the make_shared option.")
126
    if 'remediations' not in rule_obj or lang not in rule_obj['remediations']:
127
        raise ValueError("Rule is missing fixes.")
128
129
    lang_ext = ssg.build_remediations.REMEDIATION_TO_EXT_MAP[lang]
130
    shared_name = "shared" + lang_ext
131
    if shared_name in rule_obj['remediations'][lang]:
132
        raise ValueError("Already have shared fix for rule_id:%s; refusing "
133
                         "to continue." % rule_obj['id'])
134
135
    fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[0])
136
    shared_fix_file = os.path.join(rule_obj['dir'], lang, shared_name)
137
    os.rename(fix_file, shared_fix_file)
138
    print("Moved %s -> %s" % (fix_file, shared_fix_file))
139
140
141
def diff_fixes(rule_obj, lang, products):
142
    if not products or len(products) != 2 or products[0] == products[1]:
143
        raise ValueError("Must pass exactly two products for the diff option.")
144
    if 'remediations' not in rule_obj or lang not in rule_obj['remediations']:
145
        raise ValueError("Rule is missing fixes.")
146
147
    left_fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[0])
148
    right_fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[1])
149
150
    subprocess.run(['diff', '--color=always', left_fix_file, right_fix_file])
151
152
153
def main():
154
    args = parse_args()
155
156
    json_file = open(args.json, 'r')
157
    known_rules = json.load(json_file)
158
159
    if not args.rule_id in known_rules:
160
        print("Error: rule_id:%s is not known!" % args.rule_id, file=sys.stderr)
161
        print("If you think this is an error, try regenerating the JSON.", file=sys.stderr)
162
        sys.exit(1)
163
164
    if args.action != "list" and not args.products:
165
        print("Error: expected a list of products or replace transformations but "
166
              "none given.", file=sys.stderr)
167
        sys.exit(1)
168
169
    rule_obj = known_rules[args.rule_id]
170
    print("rule_id:%s\n" % args.rule_id)
171
172
    if args.action == "list":
173
        list_platforms(rule_obj, args.fix_lang)
174
    elif args.action == "add":
175
        add_platforms(rule_obj, args.fix_lang, args.products)
176
    elif args.action == "remove":
177
        remove_platforms(rule_obj, args.fix_lang, args.products)
178
    elif args.action == "replace":
179
        replace_platforms(rule_obj, args.fix_lang, args.products)
180
    elif args.action == 'delete':
181
        delete_fixes(rule_obj, args.fix_lang, args.products)
182
    elif args.action == 'make_shared':
183
        make_shared_fix(rule_obj, args.fix_lang, args.products)
184
    elif args.action == 'diff':
185
        diff_fixes(rule_obj, args.fix_lang, args.products)
186
    else:
187
        print("Unknown option: %s" % args.action)
188
189
190
if __name__ == "__main__":
191
    main()
192