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):
112
113
114 @webhooks_ns.route("/github/<int:copr_id>/<uuid>/", methods=["POST"])
115 -def webhooks_git_push(copr_id, uuid):
116 if flask.request.headers["X-GitHub-Event"] == "ping":
117 return "OK", 200
118
119
120 try:
121 copr = ComplexLogic.get_copr_by_id_safe(copr_id)
122 except ObjectNotFound:
123 return page_not_found("Project does not exist")
124
125 if copr.webhook_secret != uuid:
126 return access_restricted("This webhook is not valid")
127
128 try:
129 payload = flask.request.json
130 clone_url = payload['repository']['clone_url']
131 commits = []
132 payload_commits = payload.get('commits', [])
133 for payload_commit in payload_commits:
134 commits.append({
135 'added': payload_commit['added'],
136 'modified': payload_commit['modified'],
137 'removed': payload_commit['removed'],
138 })
139
140 ref_type = payload.get('ref_type', '')
141 ref = payload.get('ref', '')
142 except KeyError:
143 return "Bad Request", 400
144
145 packages = PackagesLogic.get_for_webhook_rebuild(copr_id, uuid, clone_url, commits, ref_type, ref)
146
147 committish = (ref if ref_type == 'tag' else payload.get('after', ''))
148 for package in packages:
149 BuildsLogic.rebuild_package(package, {'committish': committish})
150
151 db.session.commit()
152
153 return "OK", 200
154
155
156 @webhooks_ns.route("/gitlab/<int:copr_id>/<uuid>/", methods=["POST"])
157 -def webhooks_gitlab_push(copr_id, uuid):
158
159
160 try:
161 copr = ComplexLogic.get_copr_by_id_safe(copr_id)
162 except ObjectNotFound:
163 return page_not_found("Project does not exist")
164
165 if copr.webhook_secret != uuid:
166 return access_restricted("This webhook is not valid")
167
168 try:
169 payload = flask.request.json
170 clone_url = payload['project']['git_http_url']
171 commits = []
172 payload_commits = payload.get('commits', [])
173 for payload_commit in payload_commits:
174 commits.append({
175 'added': payload_commit['added'],
176 'modified': payload_commit['modified'],
177 'removed': payload_commit['removed'],
178 })
179 if payload['object_kind'] == 'tag_push':
180 ref_type = 'tag'
181 ref = os.path.basename(payload.get('ref', ''))
182 else:
183 ref_type = None
184 ref = payload.get('ref', '')
185 except KeyError:
186 return "Bad Request", 400
187
188 packages = PackagesLogic.get_for_webhook_rebuild(copr_id, uuid, clone_url, commits, ref_type, ref)
189
190 committish = (ref if ref_type == 'tag' else payload.get('after', ''))
191 for package in packages:
192 BuildsLogic.rebuild_package(package, {'committish': committish})
193
194 db.session.commit()
195
196 return "OK", 200
197
198
199 -class HookContentStorage(object):
200 tmp = None
201
202 - def __init__(self):
203 if not flask.request.json:
204 return
205 self.tmp = tempfile.mkdtemp(dir=app.config["STORAGE_DIR"])
206 log.debug("storing hook content under %s", self.tmp)
207 try:
208 with open(os.path.join(self.tmp, 'hook_payload'), "w") as f:
209
210 f.write(flask.request.data.decode('ascii'))
211
212 except Exception:
213 log.exception('can not store hook payload')
214 self.delete()
215
216 - def rebuild_dict(self):
217 if self.tmp:
218 return {'tmp': os.path.basename(self.tmp), 'hook_data': True }
219 return {}
220
222 if self.tmp:
223 shutil.rmtree(self.tmp)
224
225
226 @webhooks_ns.route("/custom/<int:copr_id>/<uuid>/", methods=["POST"])
227 @webhooks_ns.route("/custom/<int:copr_id>/<uuid>/<package_name>/", methods=["POST"])
228 @copr_id_and_uuid_required
229 @package_name_required
230 @skip_invalid_calls
231 -def webhooks_package_custom(copr, package, flavor=None):
248