-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathmodify-bugs
More file actions
executable file
·192 lines (174 loc) · 7.95 KB
/
modify-bugs
File metadata and controls
executable file
·192 lines (174 loc) · 7.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/python3
import os, sys, re, argparse
import bugzilla
from bugzilla.utils import check_being_logged_in, make_url, get_bugzilla_api
# modify-bugs script - is based on python-bugzilla (our in-tree patched copy) and requests libraries
# for now this script should be kept Python 3.6 compatible (SLE15-SP7)
CVE_PATTERN = re.compile(r"CVE-[0-9]{4}-[0-9]{4,}")
def handle_bugs(bug_string):
if not bug_string:
return None
ret = []
for b in bug_string.split(','):
try:
if b.startswith('bsc#'):
b = b[4:]
bz_number = int(b)
if bz_number < 1:
raise Exception()
ret.append(bz_number)
except:
print(f'{b} is not a valid bz number', file=sys.stderr)
if not ret:
sys.exit(1)
return ret
def handle_cves(cve_string):
if not cve_string:
return None
ret = []
for c in cve_string.split(','):
m = re.match(CVE_PATTERN, c)
if not m:
print(f'{c} is not a valid CVE number', file=sys.stderr)
continue
ret.append(c)
if not ret:
sys.exit(1)
return ret
# this scripts supports both comma separated values for -V, -B and --cc options and multiple such options
# this is where everything is collected into one array
class BugActions(argparse.Action):
bug_list = []
cve_list = []
cc_list = []
def __call__(self, parser, namespace, values, option_string = None):
if option_string in ["-V", "--cves"]:
cves = handle_cves(values)
if cves:
self.cve_list.extend(cves)
elif option_string in ["-B", "--bugs"]:
bugs = handle_bugs(values)
if bugs:
self.bug_list.extend(bugs)
elif option_string == '--cc':
if values:
self.cc_list.extend([ handle_email(e) for e in values.split(',') ])
def handle_email(email):
if not email:
return None
if '@suse.' not in email:
print(f'{email} is not a valid BZ email', file=sys.stderr)
sys.exit(1)
return email
def parse_args():
parser = argparse.ArgumentParser("modify-bugs")
parser.add_argument("-f", "--file", help="path to a file containing the text of comments", default=None, type=str)
parser.add_argument("-c", "--comment", help="the text of comments", default=None, type=str)
parser.add_argument("-p", "--public", help="shall the comments be public; by default they are private", action="store_true", default=False)
parser.add_argument("-V", "--cves", help="comma separated list of cves; can be use multiple times; can be used with --bugs", action=BugActions)
parser.add_argument("-B", "--bugs", help="comma separated list of bugs; can be use multiple times; can be used with --cves", action=BugActions)
resolved_group = parser.add_mutually_exclusive_group()
resolved_group.add_argument("--resolved-fixed", help="make bug RESOLVED FIXED", action="store_true", default=False)
resolved_group.add_argument("--resolved-invalid", help="make bug RESOLVED INVALID", action="store_true", default=False)
resolved_group.add_argument("--resolved-wontfix", help="make bug RESOLVED WONTFIX", action="store_true", default=False)
resolved_group.add_argument("--resolved-worksforme", help="make bug RESOLVED WORKSFORME", action="store_true", default=False)
resolved_group.add_argument("--resolved-feature", help="make bug RESOLVED FEATURE", action="store_true", default=False)
resolved_group.add_argument("--in-progress", help="swith bug to IN_PROGRESS status", action="store_true", default=False)
arch_group = parser.add_mutually_exclusive_group()
arch_group.add_argument("--arch-s390x", help="set arch to s390x", action="store_true", default=False)
arch_group.add_argument("--arch-ppc64le", help="set arch to ppc64le", action="store_true", default=False)
arch_group.add_argument("--arch-x86_64", help="set arch to x86_64", action="store_true", default=False)
arch_group.add_argument("--arch-aarch64", help="set arch to aarch64", action="store_true", default=False)
arch_group.add_argument("--arch-all", help="set arch to aarch64", action="store_true", default=False)
parser.add_argument("--cc", help="comma separated list of emails; can be use multiple times", action=BugActions)
parser.add_argument("-a", "--assignee", help="email as assignees for the bugs", default=None, type=str)
parser.add_argument("-v", "--verbose", help="be a bit more verbose", action="store_true", default=False)
parser.add_argument("--rest", help="Use REST API instead of XMLRPC API (experimental, for debugging purposes)", action="store_true", default=False)
parser.add_argument("--debug", help="Enable Bugtzilla rpc debugging", action="store_true", default=False)
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
if args.debug:
import logging
logging.basicConfig(level=logging.DEBUG)
if not BugActions.bug_list and not BugActions.cve_list:
print("You must provide either a bug ID or a CVE number", file=sys.stderr)
sys.exit(1)
comment = args.comment + '\n' if args.comment else None
if args.file and not comment:
if not os.path.isfile(args.file):
print(f"'{args.file}' must exists and must be a regular file", file=sys.stderr)
sys.exit(1)
try:
comment = open(args.file, 'r').read()
except:
print(f"failed to read '{args.file}'", file=sys.stderr)
sys.exit(1)
assignee = handle_email(args.assignee)
try:
bzapi = get_bugzilla_api(args.rest)
check_being_logged_in(bzapi)
except Exception as e:
print(f"Failed to connect to bugzilla...: {e}", file=sys.stderr)
sys.exit(1)
bug_ids = { b for b in BugActions.bug_list } if BugActions.bug_list else set()
if BugActions.cve_list:
kvargs = { 'status': ['NEW', 'IN_PROGRESS', 'CONFIRMED', 'REOPENED'],
'product': 'SUSE Security Incidents',
'component': 'Incidents',
'alias': BugActions.cve_list,
'include_fields': ["id"] }
query = bzapi.build_query(**kvargs)
cve_bugs = bzapi.query(query)
bug_ids |= { b.id for b in cve_bugs }
if not bug_ids:
print(f"There's no bug to process...", file=sys.stderr)
sys.exit(1)
bargs= {}
if comment:
bargs['comment'] = comment + '\n'
if not args.public:
bargs['comment_private'] = True
if assignee:
bargs['assigned_to'] = assignee
if BugActions.cc_list:
bargs['cc_add'] = BugActions.cc_list
if args.resolved_fixed:
bargs['status'] = 'RESOLVED'
bargs['resolution'] = 'FIXED'
elif args.resolved_invalid:
bargs['status'] = 'RESOLVED'
bargs['resolution'] = 'INVALID'
elif args.resolved_wontfix:
bargs['status'] = 'RESOLVED'
bargs['resolution'] = 'WONTFIX'
elif args.resolved_worksforme:
bargs['status'] = 'RESOLVED'
bargs['resolution'] = 'WORKSFORME'
elif args.resolved_feature:
bargs['status'] = 'RESOLVED'
bargs['resolution'] = 'FEATURE'
elif args.in_progress:
bargs['status'] = 'IN_PROGRESS'
if args.arch_s390x:
bargs['platform'] = 'S/390-64'
elif args.arch_ppc64le:
bargs['platform'] = 'PowerPC-64'
elif args.arch_x86_64:
bargs['platform'] = 'x86-64'
elif args.arch_aarch64:
bargs['platform'] = 'aarch64'
elif args.arch_all:
bargs['platform'] = 'All'
if bargs:
vals = bzapi.build_update(**bargs)
try:
bzapi.update_bugs([ b for b in bug_ids ], vals)
if args.verbose:
for b in bug_ids:
print(make_url(b))
except Exception as e:
print(f"Failed to update bugs... {bug_ids}: {e}", file=sys.stderr)
sys.exit(1)
else:
print("Nothing to do!", file=sys.stderr)