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