Issues (70)

utils/mod_fixes.py (3 issues)

1
#!/usr/bin/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
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
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
66
    if "multi_platform_all" in current_platforms:
67
        return
68
69
    new_platforms = set(current_platforms)
70
    new_platforms.update(platforms)
71
72
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
73
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
74
75
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
76
                                                      new_platforms)
77
    ssg.utils.write_list_file(fix_file, new_contents)
78
79
80
def remove_platforms(rule_obj, lang, platforms):
81
    fix_file, fix_contents = ssg.fixes.get_fix_contents(rule_obj, lang, 'shared')
82
    current_platforms = ssg.fixes.applicable_platforms(fix_file)
83
    new_platforms = set(current_platforms).difference(platforms)
84
85
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
86
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
87
88
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
89
                                                      new_platforms)
90
    ssg.utils.write_list_file(fix_file, new_contents)
91
92
93 View Code Duplication
def replace_platforms(rule_obj, lang, platforms):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
94
    fix_file, fix_contents = ssg.fixes.get_fix_contents(rule_obj, lang, 'shared')
95
    current_platforms = ssg.fixes.applicable_platforms(fix_file)
96
    new_platforms = set(current_platforms)
97
98
    for platform in platforms:
99
        parsed_platform = platform.split('~')
100
        if not len(parsed_platform) == 2:
101
            print("Invalid platform replacement description: %s" % platform,
102
                  file=sys.stderr)
103
            sys.exit(1)
104
105
        match = ssg.rule_yaml.parse_prodtype(parsed_platform[0])
106
        replacement = ssg.rule_yaml.parse_prodtype(parsed_platform[1])
107
108
        if match.issubset(current_platforms):
109
            new_platforms.difference_update(match)
110
            new_platforms.update(replacement)
111
112
    print("Current platforms: %s" % ','.join(sorted(current_platforms)))
113
    print("New platforms: %s" % ','.join(sorted(new_platforms)))
114
115
    new_contents = ssg.fixes.set_applicable_platforms(fix_contents,
116
                                                      new_platforms)
117
    ssg.utils.write_list_file(fix_file, new_contents)
118
119
120
def delete_fixes(rule_obj, lang, products):
121
    for product in products:
122
        fix_file = ssg.fixes.get_fix_path(rule_obj, lang, product)
123
        os.remove(fix_file)
124
        print("Removed: %s" % fix_file)
125
126
127
def make_shared_fix(rule_obj, lang, products):
128
    if not products or len(products) > 1:
129
        raise ValueError("Must pass exactly one product for the make_shared option.")
130
    if 'remediations' not in rule_obj or lang not in rule_obj['remediations']:
131
        raise ValueError("Rule is missing fixes.")
132
133
    lang_ext = ssg.build_remediations.REMEDIATION_TO_EXT_MAP[lang]
134
    shared_name = "shared" + lang_ext
135
    if shared_name in rule_obj['remediations'][lang]:
136
        raise ValueError("Already have shared fix for rule_id:%s; refusing "
137
                         "to continue." % rule_obj['id'])
138
139
    fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[0])
140
    shared_fix_file = os.path.join(rule_obj['dir'], lang, shared_name)
141
    os.rename(fix_file, shared_fix_file)
142
    print("Moved %s -> %s" % (fix_file, shared_fix_file))
143
144
145
def diff_fixes(rule_obj, lang, products):
146
    if not products or len(products) != 2 or products[0] == products[1]:
147
        raise ValueError("Must pass exactly two products for the diff option.")
148
    if 'remediations' not in rule_obj or lang not in rule_obj['remediations']:
149
        raise ValueError("Rule is missing fixes.")
150
151
    left_fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[0])
152
    right_fix_file = ssg.fixes.get_fix_path(rule_obj, lang, products[1])
153
154
    subprocess.run(['diff', '--color=always', left_fix_file, right_fix_file])
155
156
157
def main():
158
    args = parse_args()
159
160
    json_file = open(args.json, 'r')
161
    known_rules = json.load(json_file)
162
163
    if args.rule_id not in known_rules:
164
        print("Error: rule_id:%s is not known!" % args.rule_id, file=sys.stderr)
165
        print("If you think this is an error, try regenerating the JSON.", file=sys.stderr)
166
        sys.exit(1)
167
168
    if args.action != "list" and not args.products:
169
        print("Error: expected a list of products or replace transformations but "
170
              "none given.", file=sys.stderr)
171
        sys.exit(1)
172
173
    rule_obj = known_rules[args.rule_id]
174
    print("rule_id:%s\n" % args.rule_id)
175
176
    if args.action == "list":
177
        list_platforms(rule_obj, args.fix_lang)
178
    elif args.action == "add":
179
        add_platforms(rule_obj, args.fix_lang, args.products)
180
    elif args.action == "remove":
181
        remove_platforms(rule_obj, args.fix_lang, args.products)
182
    elif args.action == "replace":
183
        replace_platforms(rule_obj, args.fix_lang, args.products)
184
    elif args.action == 'delete':
185
        delete_fixes(rule_obj, args.fix_lang, args.products)
186
    elif args.action == 'make_shared':
187
        make_shared_fix(rule_obj, args.fix_lang, args.products)
188
    elif args.action == 'diff':
189
        diff_fixes(rule_obj, args.fix_lang, args.products)
190
    else:
191
        print("Unknown option: %s" % args.action)
192
193
194
if __name__ == "__main__":
195
    main()
196