From f0dd449b2d57856b48aa5255f655253aecb94a08 Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Fri, 20 Sep 2024 14:14:31 +0200 Subject: [PATCH] frontend: fix the 500 for racy creation attempts This is TOCTOU issue. The other checks for duplications (on so many places) seem kinda redundant because nothing but try/except for commit() may catch these concurrency problems. Fixes: #3372 --- .../coprs/views/apiv3_ns/apiv3_projects.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py index 2084d0b1c..70ae60a9b 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py @@ -5,6 +5,7 @@ import flask from flask_restx import Namespace, Resource +from sqlalchemy.exc import IntegrityError from coprs.views.apiv3_ns import ( get_copr, @@ -15,7 +16,7 @@ editable_copr, ) from coprs.views.apiv3_ns.json2form import get_form_compatible_data, get_input_dict -from coprs import db, models, forms, db_session_scope +from coprs import app, db, models, forms, db_session_scope from coprs.views.misc import api_login_required from coprs.views.apiv3_ns import rename_fields_helper, api, query_to_parameters from coprs.views.apiv3_ns.schema.schemas import ( @@ -228,13 +229,14 @@ def post(self, ownername, exist_ok=False): if form.bootstrap.data is not None: bootstrap = form.bootstrap.data + projectname = form.name.data.strip() try: def _form_field_repos(form_field): return " ".join(form_field.data.split()) copr = CoprsLogic.add( - name=form.name.data.strip(), + name=projectname, repos=_form_field_repos(form.repos), user=user, selected_chroots=form.selected_chroots, @@ -265,6 +267,16 @@ def _form_field_repos(form_field): storage=form.storage.data, ) db.session.commit() + except IntegrityError as ierr: + app.log.debug("Racy attempt to create %s/%s", ownername, projectname) + db.session.rollback() + if exist_ok: + copr = get_copr(ownername, projectname) + return to_dict(copr) + raise DuplicateException( + f"Copr '{ownername}/{projectname}' has not been created " + "(race condition)" + ) from ierr except ( DuplicateException, NonAdminCannotCreatePersistentProject,