19
19
from google .cloud import storage
20
20
import requests
21
21
22
- from appengine .libs import form
23
- from appengine .libs import gcs
24
- from appengine .libs import helpers
25
22
from clusterfuzz ._internal .config import local_config
26
23
from clusterfuzz ._internal .issue_management .google_issue_tracker import \
27
24
issue_tracker
25
+ from clusterfuzz ._internal .metrics import logs
28
26
29
27
ACCEPTED_FILETYPES = [
30
28
'text/javascript' , 'application/pdf' , 'text/html' , 'application/zip'
31
29
]
32
30
ISSUETRACKER_ACCEPTED_STATE = 'ACCEPTED'
33
31
ISSUETRACKER_WONTFIX_STATE = 'NOT_REPRODUCIBLE'
32
+ _CLUSTERFUZZ_GET_URL = (
33
+ 'https://clusterfuzz.corp.google.com/upload-testcase/get-url-oauth' )
34
+ _UPLOAD_URL_PROPERTY = 'uploadUrl'
35
+ _TESTCASE_ID_PROPERTY = 'id'
36
+
37
+
38
+ class ExternalTestcaseReaderException (Exception ):
39
+ """Error when uploading an externally submitted testcase.."""
40
+
41
+ def __init__ (self , message ):
42
+ super ().__init__ (message )
34
43
35
44
36
45
def get_vrp_uploaders (config ):
@@ -42,19 +51,18 @@ def get_vrp_uploaders(config):
42
51
return members
43
52
44
53
45
- def close_issue_if_invalid (upload_request , attachment_info , description ,
46
- vrp_uploaders ):
54
+ def close_issue_if_invalid (issue , attachment_info , description , vrp_uploaders ):
47
55
"""Closes any invalid upload requests with a helpful message."""
48
56
comment_message = (
49
57
'Hello, this issue is automatically closed. Please file a new bug after'
50
58
' fixing the following issues:\n \n ' )
51
59
invalid = False
52
60
53
61
# TODO(pgrace) Remove after testing.
54
- if upload_request .id == 373893311 :
62
+ if issue .id == 373893311 :
55
63
return False
56
64
57
- if not upload_request .reporter in vrp_uploaders :
65
+ if not issue .reporter in vrp_uploaders :
58
66
comment_message += (
59
67
'You are not authorized to submit testcases to Clusterfuzz.'
60
68
' If you believe you should be, please reach out to'
@@ -90,8 +98,8 @@ def close_issue_if_invalid(upload_request, attachment_info, description,
90
98
comment_message += (
91
99
'\n Please see the new bug template for more information on how to use'
92
100
' Clusterfuzz direct uploads.' )
93
- upload_request .status = ISSUETRACKER_WONTFIX_STATE
94
- upload_request .save (new_comment = comment_message , notify = True )
101
+ issue .status = ISSUETRACKER_WONTFIX_STATE
102
+ issue .save (new_comment = comment_message , notify = True )
95
103
96
104
return invalid
97
105
@@ -116,40 +124,48 @@ def filed_n_days_ago(issue_created_time_string, config):
116
124
117
125
def submit_testcase (issue_id , file , filename , filetype , cmds ):
118
126
"""Uploads the given testcase file to Clusterfuzz."""
127
+ get_url_response = requests .post (_CLUSTERFUZZ_GET_URL , timeout = 10 )
128
+ if _UPLOAD_URL_PROPERTY not in get_url_response :
129
+ logs .error ('Unexpected response (missing uploadUrl): %s' % get_url_response )
130
+ raise ExternalTestcaseReaderException (
131
+ 'Unexpected response (missing uploadUrl): %s' % get_url_response )
132
+ upload_url = get_url_response [_UPLOAD_URL_PROPERTY ]
133
+
134
+ target = None
119
135
if filetype == 'text/javascript' :
120
136
job = 'linux_asan_d8_dbg'
121
137
elif filetype == 'application/pdf' :
122
138
job = 'libfuzzer_pdfium_asan'
139
+ # Only libfuzzer_pdfium_asan needs a fuzzer target specified
140
+ target = 'pdfium_xfa_fuzzer'
123
141
elif filetype == 'text/html' :
124
142
job = 'linux_asan_chrome_mp'
125
143
elif filetype == 'application/zip' :
126
144
job = 'linux_asan_chrome_mp'
127
145
else :
128
146
raise TypeError
129
- upload_info = gcs .prepare_blob_upload ()._asdict ()
130
-
131
147
data = {
132
- # Content provided by uploader.
133
- 'issue' : issue_id ,
148
+ 'platform' : 'Linux' ,
134
149
'job' : job ,
135
- 'file ' : file ,
150
+ 'issue ' : issue_id ,
136
151
'cmd' : cmds ,
152
+ 'file' : file ,
137
153
'x-goog-meta-filename' : filename ,
138
-
139
- # Content generated internally.
140
- 'platform' : 'Linux' ,
141
- 'csrf_token' : form .generate_csrf_token (),
142
- 'upload_key' : upload_info ['key' ],
143
- # TODO(pgrace) Replace with upload_info['bucket'] once testing complete.
144
- 'bucket' : 'clusterfuzz-test-bucket' ,
145
- 'key' : upload_info ['key' ],
146
- 'GoogleAccessId' : upload_info ['google_access_id' ],
147
- 'policy' : upload_info ['policy' ],
148
- 'signature' : upload_info ['signature' ],
149
154
}
150
155
151
- return requests .post (
152
- 'https://clusterfuzz.com/upload-testcase/upload' , data = data , timeout = 10 )
156
+ if target :
157
+ data ['target' ] = target
158
+
159
+ upload_response = requests .post (upload_url , data = data , timeout = 10 )
160
+ is_error_code = upload_response .status_code != 200
161
+ is_missing_testcase_id = _TESTCASE_ID_PROPERTY not in upload_response
162
+ if is_error_code or is_missing_testcase_id :
163
+ reason = 'missing testcase id' if is_missing_testcase_id else 'failure code'
164
+ msg = 'Unexpected response (%s): %s' % (reason , upload_response )
165
+ logs .error (msg )
166
+ raise ExternalTestcaseReaderException (msg )
167
+
168
+ return upload_response
153
169
154
170
155
171
def handle_testcases (tracker , config ):
@@ -163,15 +179,15 @@ def handle_testcases(tracker, config):
163
179
for issue in older_issues :
164
180
# Close out older bugs that may have failed to reproduce.
165
181
if close_issue_if_not_reproducible (issue , config ):
166
- helpers .log ('Closing issue {issue_id} as it failed to reproduce' ,
167
- issue .id )
182
+ logs .info ('Closing issue %s as it failed to reproduce' & issue .id )
168
183
169
184
# Handle new bugs that may need to be submitted.
170
185
issues = tracker .find_issues_with_filters (
171
186
keywords = [],
172
187
query_filters = ['componentid:1600865' , 'status:new' ],
173
188
only_open = True )
174
- if len (issues ) == 0 :
189
+ issues_list = list (issues )
190
+ if len (issues_list ) == 0 :
175
191
return
176
192
177
193
vrp_uploaders = get_vrp_uploaders (config )
@@ -180,7 +196,7 @@ def handle_testcases(tracker, config):
180
196
# Process only a certain number of bugs per reporter for each job run.
181
197
reporters_map = {}
182
198
183
- for issue in issues :
199
+ for issue in issues_list :
184
200
attachment_metadata = tracker .get_attachment_metadata (issue .id )
185
201
commandline_flags = tracker .get_description (issue .id )
186
202
if reporters_map .get (issue .reporter ,
@@ -189,7 +205,7 @@ def handle_testcases(tracker, config):
189
205
reporters_map [issue .reporter ] = reporters_map .get (issue .reporter , 1 ) + 1
190
206
if close_issue_if_invalid (issue , attachment_metadata , commandline_flags ,
191
207
vrp_uploaders ):
192
- helpers . log ('Closing issue {issue_id} as it is invalid' , issue .id )
208
+ logs . info ('Closing issue %s as it is invalid' % issue .id )
193
209
continue
194
210
195
211
# Submit valid testcases.
@@ -202,12 +218,17 @@ def handle_testcases(tracker, config):
202
218
issue .status = ISSUETRACKER_ACCEPTED_STATE
203
219
issue .assignee = 'clusterfuzz@chromium.org'
204
220
issue .save (new_comment = comment_message , notify = True )
205
- helpers .log ('Submitted testcase file for issue {issue_id}' , issue .id )
221
+ logs .info ('Submitted testcase file for issue %s' % issue .id )
222
+
223
+
224
+ _ISSUE_TRACKER_URL = 'https://issues.chromium.org/issues'
206
225
207
226
208
227
def main ():
209
- tracker = issue_tracker .IssueTracker ('chromium' , None ,
210
- {'default_component_id' : 1363614 })
228
+ tracker = issue_tracker .IssueTracker ('chromium' , None , {
229
+ 'default_component_id' : 1363614 ,
230
+ 'url' : _ISSUE_TRACKER_URL
231
+ })
211
232
handle_testcases (tracker , local_config .ExternalTestcaseReaderConfig ())
212
233
213
234
0 commit comments