1 import flask
2 from functools import wraps
3
4 from coprs import db, app
5
6 from coprs.logic.builds_logic import BuildsLogic
7 from coprs.logic.complex_logic import ComplexLogic
8 from coprs.logic.packages_logic import PackagesLogic
9
10 from coprs.exceptions import ObjectNotFound
11
12 from coprs.views.webhooks_ns import webhooks_ns
13 from coprs.views.misc import page_not_found, access_restricted
14
15 import logging
16 import os
17 import tempfile
18 import shutil
19
20 log = logging.getLogger(__name__)
24 """
25 A best effort attempt to drop hook callswhich should not obviously end up
26 with new build request (thus allocated build-id).
27 """
28 @wraps(route)
29 def decorated_function(*args, **kwargs):
30 if 'X-GitHub-Event' in flask.request.headers:
31 event = flask.request.headers["X-GitHub-Event"]
32 if event == "ping":
33 return "SKIPPED\n", 200
34 return route(*args, **kwargs)
35
36 return decorated_function
37
40 @wraps(route)
41 def decorated_function(**kwargs):
42 if not 'copr_id' in kwargs or not 'uuid' in kwargs:
43 return 'COPR_ID_OR_UUID_TOKEN_MISSING\n', 400
44
45 copr_id = kwargs.pop('copr_id')
46 try:
47 copr = ComplexLogic.get_copr_by_id_safe(copr_id)
48 except ObjectNotFound:
49 return "PROJECT_NOT_FOUND\n", 404
50
51 if copr.webhook_secret != kwargs.pop('uuid'):
52 return "BAD_UUID\n", 403
53
54 return route(copr, **kwargs)
55
56 return decorated_function
57
72
73 return decorated_function
74
75
76 @webhooks_ns.route("/bitbucket/<int:copr_id>/<uuid>/", methods=["POST"])
77 -def webhooks_bitbucket_push(copr_id, uuid):
118
119
120 @webhooks_ns.route("/github/<int:copr_id>/<uuid>/", methods=["POST"])
121 -def webhooks_git_push(copr_id, uuid):
122 if flask.request.headers["X-GitHub-Event"] == "ping":
123 return "OK", 200
124
125
126 try:
127 copr = ComplexLogic.get_copr_by_id_safe(copr_id)
128 except ObjectNotFound:
129 return page_not_found("Project does not exist")
130
131 if copr.webhook_secret != uuid:
132 return access_restricted("This webhook is not valid")
133
134 try:
135 payload = flask.request.json
136 clone_url = payload['repository']['clone_url']
137 commits = []
138 payload_commits = payload.get('commits', [])
139 for payload_commit in payload_commits:
140 commits.append({
141 'added': payload_commit['added'],
142 'modified': payload_commit['modified'],
143 'removed': payload_commit['removed'],
144 })
145
146 ref_type = payload.get('ref_type', '')
147 ref = payload.get('ref', '')
148 try:
149 sender = payload['sender']['url']
150 except KeyError:
151 sender = None
152 except KeyError:
153 return "Bad Request", 400
154
155 packages = PackagesLogic.get_for_webhook_rebuild(copr_id, uuid, clone_url, commits, ref_type, ref)
156
157 committish = (ref if ref_type == 'tag' else payload.get('after', ''))
158 for package in packages:
159 BuildsLogic.rebuild_package(package, {'committish': committish},
160 submitted_by=sender)
161
162 db.session.commit()
163
164 return "OK", 200
165
166
167 @webhooks_ns.route("/gitlab/<int:copr_id>/<uuid>/", methods=["POST"])
168 -def webhooks_gitlab_push(copr_id, uuid):
169
170
171 try:
172 copr = ComplexLogic.get_copr_by_id_safe(copr_id)
173 except ObjectNotFound:
174 return page_not_found("Project does not exist")
175
176 if copr.webhook_secret != uuid:
177 return access_restricted("This webhook is not valid")
178
179 try:
180 payload = flask.request.json
181 clone_url = payload['project']['git_http_url']
182 commits = []
183 payload_commits = payload.get('commits', [])
184 for payload_commit in payload_commits:
185 commits.append({
186 'added': payload_commit['added'],
187 'modified': payload_commit['modified'],
188 'removed': payload_commit['removed'],
189 })
190 if payload['object_kind'] == 'tag_push':
191 ref_type = 'tag'
192 ref = os.path.basename(payload.get('ref', ''))
193 else:
194 ref_type = None
195 ref = payload.get('ref', '')
196
197 try:
198 submitter = 'gitlab.com:{}'.format(str(payload["user_username"]))
199 except KeyError:
200 submitter = None
201
202 except KeyError:
203 return "Bad Request", 400
204
205 packages = PackagesLogic.get_for_webhook_rebuild(copr_id, uuid, clone_url, commits, ref_type, ref)
206
207 committish = (ref if ref_type == 'tag' else payload.get('after', ''))
208 for package in packages:
209 BuildsLogic.rebuild_package(package, {'committish': committish},
210 submitted_by=submitter)
211
212 db.session.commit()
213
214 return "OK", 200
215
216
217 -class HookContentStorage(object):
218 tmp = None
219
220 - def __init__(self):
221 if not flask.request.json:
222 return
223 self.tmp = tempfile.mkdtemp(dir=app.config["STORAGE_DIR"])
224 log.debug("storing hook content under %s", self.tmp)
225 try:
226 with open(os.path.join(self.tmp, 'hook_payload'), "w") as f:
227
228 f.write(flask.request.data.decode(errors='replace'))
229
230 except Exception:
231 log.exception('can not store hook payload')
232 self.delete()
233
234 - def rebuild_dict(self):
235 if self.tmp:
236 return {'tmp': os.path.basename(self.tmp), 'hook_data': True }
237 return {}
238
240 if self.tmp:
241 shutil.rmtree(self.tmp)
242
243
244 @webhooks_ns.route("/custom/<int:copr_id>/<uuid>/", methods=["POST"])
245 @webhooks_ns.route("/custom/<int:copr_id>/<uuid>/<package_name>/", methods=["POST"])
246 @copr_id_and_uuid_required
247 @package_name_required
248 @skip_invalid_calls
249 -def webhooks_package_custom(copr, package, flavor=None):
266