From 5e28d342afcb567a49e1d7169cea2cd2a85166eb Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 17 2024 13:25:01 +0000
Subject: [PATCH 1/14] tests: bump container version to f40


---

diff --git a/dev/containers/base-fedora-pip-py3 b/dev/containers/base-fedora-pip-py3
index c5c9c94..2775956 100644
--- a/dev/containers/base-fedora-pip-py3
+++ b/dev/containers/base-fedora-pip-py3
@@ -1,4 +1,4 @@
-FROM quay.io/fedora/fedora:39-x86_64
+FROM quay.io/fedora/fedora:40-x86_64
 
 LABEL org.opencontainers.image.authors="pagure community"
 LABEL org.opencontainers.image.url="https://pagure.io/pagure"
diff --git a/dev/containers/base-fedora-rpms-py3 b/dev/containers/base-fedora-rpms-py3
index 6533155..6c409ec 100644
--- a/dev/containers/base-fedora-rpms-py3
+++ b/dev/containers/base-fedora-rpms-py3
@@ -1,4 +1,4 @@
-FROM quay.io/fedora/fedora:39-x86_64
+FROM quay.io/fedora/fedora:40-x86_64
 
 LABEL org.opencontainers.image.authors="pagure community"
 LABEL org.opencontainers.image.url="https://pagure.io/pagure"
diff --git a/dev/containers/fedora-pip-py3 b/dev/containers/fedora-pip-py3
index 1473aea..636518f 100644
--- a/dev/containers/fedora-pip-py3
+++ b/dev/containers/fedora-pip-py3
@@ -1,4 +1,4 @@
-FROM quay.io/fedora/fedora:39-x86_64
+FROM quay.io/fedora/fedora:40-x86_64
 
 ARG repo=https://pagure.io/pagure.git
 ARG branch=master
diff --git a/dev/containers/fedora-rpms-py3 b/dev/containers/fedora-rpms-py3
index 4a33252..0125bf1 100644
--- a/dev/containers/fedora-rpms-py3
+++ b/dev/containers/fedora-rpms-py3
@@ -1,4 +1,4 @@
-FROM quay.io/fedora/fedora:39-x86_64
+FROM quay.io/fedora/fedora:40-x86_64
 
 ARG repo=https://pagure.io/pagure.git
 ARG branch=master

From 8d26e881edca3756afe16f9ca9337bfcc75f4f77 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 17 2024 13:26:23 +0000
Subject: [PATCH 2/14] fix(sqlalchemy): ImportError: cannot import name 'relation' from 'sqlalchemy.orm'


---

diff --git a/pagure/hooks/fedmsg_hook.py b/pagure/hooks/fedmsg_hook.py
index 8454804..49a31c3 100644
--- a/pagure/hooks/fedmsg_hook.py
+++ b/pagure/hooks/fedmsg_hook.py
@@ -18,7 +18,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 from pagure.hooks import BaseHook, BaseRunner
 from pagure.lib.model import BASE, Project
diff --git a/pagure/hooks/irc.py b/pagure/hooks/irc.py
index 3b62f99..659ea43 100644
--- a/pagure/hooks/irc.py
+++ b/pagure/hooks/irc.py
@@ -19,7 +19,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 from pagure.hooks import BaseHook, RequiredIf
 from pagure.lib.model import BASE, Project
diff --git a/pagure/hooks/mail.py b/pagure/hooks/mail.py
index 44f5e31..64ef7f0 100644
--- a/pagure/hooks/mail.py
+++ b/pagure/hooks/mail.py
@@ -22,7 +22,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 from pagure.config import config as pagure_config
 from pagure.hooks import BaseHook, BaseRunner, RequiredIf
diff --git a/pagure/hooks/mirror_hook.py b/pagure/hooks/mirror_hook.py
index f0bd47d..9308997 100644
--- a/pagure/hooks/mirror_hook.py
+++ b/pagure/hooks/mirror_hook.py
@@ -17,7 +17,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.config
 import pagure.lib.tasks_mirror
diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py
index d2418c4..819b2a1 100644
--- a/pagure/hooks/pagure_ci.py
+++ b/pagure/hooks/pagure_ci.py
@@ -19,7 +19,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.lib.login
 from pagure.hooks import BaseHook, BaseRunner, RequiredIf
diff --git a/pagure/hooks/pagure_force_commit.py b/pagure/hooks/pagure_force_commit.py
index 313021a..9d5b770 100644
--- a/pagure/hooks/pagure_force_commit.py
+++ b/pagure/hooks/pagure_force_commit.py
@@ -18,7 +18,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.lib.git
 from pagure.hooks import BaseHook, BaseRunner, RequiredIf
diff --git a/pagure/hooks/pagure_hook.py b/pagure/hooks/pagure_hook.py
index c401a71..654152f 100644
--- a/pagure/hooks/pagure_hook.py
+++ b/pagure/hooks/pagure_hook.py
@@ -22,7 +22,7 @@ except ImportError:
     from flask_wtf import Form as FlaskForm
 
 from sqlalchemy.exc import SQLAlchemyError
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.config
 import pagure.lib.git
diff --git a/pagure/hooks/pagure_no_new_branches.py b/pagure/hooks/pagure_no_new_branches.py
index dadc8fb..644ccef 100644
--- a/pagure/hooks/pagure_no_new_branches.py
+++ b/pagure/hooks/pagure_no_new_branches.py
@@ -18,7 +18,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 from pagure.hooks import BaseHook, BaseRunner
 from pagure.lib.model import BASE, Project
diff --git a/pagure/hooks/pagure_request_hook.py b/pagure/hooks/pagure_request_hook.py
index 646dc51..1ed70ed 100644
--- a/pagure/hooks/pagure_request_hook.py
+++ b/pagure/hooks/pagure_request_hook.py
@@ -18,7 +18,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.lib.git
 import pagure.lib.tasks_services
diff --git a/pagure/hooks/pagure_ticket_hook.py b/pagure/hooks/pagure_ticket_hook.py
index 69dec93..88c3a4d 100644
--- a/pagure/hooks/pagure_ticket_hook.py
+++ b/pagure/hooks/pagure_ticket_hook.py
@@ -20,7 +20,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.lib.git
 import pagure.lib.tasks_services
diff --git a/pagure/hooks/pagure_unsigned_commits.py b/pagure/hooks/pagure_unsigned_commits.py
index 99ba714..6f1fbd9 100644
--- a/pagure/hooks/pagure_unsigned_commits.py
+++ b/pagure/hooks/pagure_unsigned_commits.py
@@ -18,7 +18,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure.config
 import pagure.lib.git
diff --git a/pagure/hooks/rtd.py b/pagure/hooks/rtd.py
index 75b9be9..bcf3a7e 100644
--- a/pagure/hooks/rtd.py
+++ b/pagure/hooks/rtd.py
@@ -20,7 +20,7 @@ try:
 except ImportError:
     from flask_wtf import Form as FlaskForm
 
-from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm import backref, relationship as relation
 
 import pagure
 from pagure.hooks import BaseHook, BaseRunner
diff --git a/pagure/lib/model.py b/pagure/lib/model.py
index 3e595d3..4fa0d85 100644
--- a/pagure/lib/model.py
+++ b/pagure/lib/model.py
@@ -26,7 +26,7 @@ from sqlalchemy import create_engine
 from sqlalchemy.exc import SQLAlchemyError
 from sqlalchemy.orm import (
     backref,
-    relation,
+    relationship as relation,
     scoped_session,
     sessionmaker,
     validates,

From feda79277d4f4e90ed220acfbae1153af051458a Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 17 2024 14:00:21 +0000
Subject: [PATCH 3/14] fix(pagure): ImportError: cannot import name 'Markup' from 'flask'. Solution: 'flask.Markup' is deprecated and will be removed in Flask 2.4. Import use 'markupsafe.Markup' instead.


---

diff --git a/pagure/docs_server.py b/pagure/docs_server.py
index 21faf4e..4c38773 100644
--- a/pagure/docs_server.py
+++ b/pagure/docs_server.py
@@ -188,7 +188,7 @@ def view_docs(repo, username=None, namespace=None, filename=None):
     else:
         flask.abort(
             404,
-            flask.Markup(
+            markupsafe.Markup(
                 "No content found in the repository, you may want to read "
                 'the <a href="'
                 'https://docs.pagure.org/pagure/usage/using_doc.html">'
diff --git a/pagure/ui/fas_login.py b/pagure/ui/fas_login.py
index 119b67c..532f67e 100644
--- a/pagure/ui/fas_login.py
+++ b/pagure/ui/fas_login.py
@@ -15,7 +15,7 @@ from base64 import b64decode
 
 import flask
 import flask_fas_openid
-from flask import Markup
+from markupsafe import Markup
 from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.lib.query
diff --git a/pagure/ui/oidc_login.py b/pagure/ui/oidc_login.py
index 07dd70a..d475d05 100644
--- a/pagure/ui/oidc_login.py
+++ b/pagure/ui/oidc_login.py
@@ -15,7 +15,7 @@ from base64 import b64decode
 
 import flask
 import munch
-from flask import Markup
+from markupsafe import Markup
 from flask_oidc import OpenIDConnect
 from sqlalchemy.exc import SQLAlchemyError
 
diff --git a/pagure/ui/plugins.py b/pagure/ui/plugins.py
index a7133ec..81c1512 100644
--- a/pagure/ui/plugins.py
+++ b/pagure/ui/plugins.py
@@ -16,7 +16,7 @@ from __future__ import absolute_import, unicode_literals
 import logging
 
 import flask
-from flask import Markup
+from markupsafe import Markup
 from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.exceptions
diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py
index 697bcc0..aad9cef 100644
--- a/pagure/ui/repo.py
+++ b/pagure/ui/repo.py
@@ -2487,7 +2487,7 @@ def revoke_api_token(repo, token_id, username=None, namespace=None):
         except SQLAlchemyError as err:  # pragma: no cover
             flask.g.session.rollback()
             _log.exception(err)
-            message = flask.Markup(
+            message = markupsafe.Markup(
                 "Token could not be revoked,"
                 ' please <a href="/about">contact an administrator</a>'
             )
diff --git a/pagure/utils.py b/pagure/utils.py
index 61693f9..a395d74 100644
--- a/pagure/utils.py
+++ b/pagure/utils.py
@@ -385,7 +385,7 @@ def login_required(function):
         elif auth_method == "fas" and not flask.g.fas_user.cla_done:
             flask.session["_requires_fpca"] = True
             flask.flash(
-                flask.Markup(
+                markupsafe.Markup(
                     'You must <a href="https://accounts.fedoraproject'
                     '.org/">sign the FPCA</a> (Fedora Project '
                     "Contributor Agreement) to use pagure"

From aa69decb9fa2f65f7034a7f88a9f8871e0879531 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 17 2024 14:47:55 +0000
Subject: [PATCH 4/14] fix(pagure): TypeError: unsupported operand type(s) for +: 'frozenset' and 'list'.


Since bleach v6.0.0 ALLOWED_* is are frozenset instead of a list

---

diff --git a/pagure/lib/query.py b/pagure/lib/query.py
index 839d2ae..dccc173 100644
--- a/pagure/lib/query.py
+++ b/pagure/lib/query.py
@@ -4370,7 +4370,8 @@ def clean_input(text, ignore=None):
         else:
             attrs["img"] = filter_img_src
 
-    tags = bleach.ALLOWED_TAGS + [
+    tags = list(bleach.ALLOWED_TAGS)
+    tags.extend([
         "p",
         "br",
         "div",
@@ -4400,7 +4401,7 @@ def clean_input(text, ignore=None):
         "cite",
         "noscript",
         "colgroup",
-    ]
+    ])
     if ignore:
         for tag in ignore:
             if tag in tags:
@@ -4410,7 +4411,10 @@ def clean_input(text, ignore=None):
 
     # newer bleach allow to customize the protocol supported
     if tuple(bleach_v) >= (1, 5, 0):  # pragma: no cover
-        protocols = bleach.ALLOWED_PROTOCOLS + ["irc", "ircs"]
+        protocols = list(bleach.ALLOWED_PROTOCOLS)
+        protocols.extend(["irc", "ircs"])
+        print(type(protocols))
+        print(protocols)
         kwargs["protocols"] = protocols
 
     return bleach.clean(text, **kwargs)

From 36ad180701db66014258a80cc13c9208dddc5d09 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 5/14] fix(pkg_resources): Don't parse requirements.txt


Dynamically loading classes shouldn't parse the requirements.txt.
In case of pinned versions that differ from an rpm installation this will otherwise
raise an 'pkg_resources.VersionConflict' error.

---

diff --git a/files/pagure.spec b/files/pagure.spec
index 16c84b8..892fa7b 100644
--- a/files/pagure.spec
+++ b/files/pagure.spec
@@ -51,6 +51,7 @@ Requires:           python%{python_pkgversion}-flask-wtf
 Requires:           python%{python_pkgversion}-flask-oidc
 Requires:           python%{python_pkgversion}-kitchen
 Requires:           python%{python_pkgversion}-markdown
+Requires:           python%{python_pkgversion}-markupsafe
 Requires:           python%{python_pkgversion}-munch
 Requires:           python%{python_pkgversion}-pillow
 Requires:           python%{python_pkgversion}-psutil
diff --git a/pagure/docs_server.py b/pagure/docs_server.py
index 4c38773..4aa422d 100644
--- a/pagure/docs_server.py
+++ b/pagure/docs_server.py
@@ -18,6 +18,8 @@ import pygit2
 from binaryornot.helpers import is_binary_string
 from whitenoise import WhiteNoise
 
+import markupsafe
+
 import pagure.config
 import pagure.doc_utils
 import pagure.exceptions
diff --git a/pagure/lib/git_auth.py b/pagure/lib/git_auth.py
index 97654bd..0936de3 100644
--- a/pagure/lib/git_auth.py
+++ b/pagure/lib/git_auth.py
@@ -66,7 +66,7 @@ def get_git_auth_helper(backend=None):
             "pagure_authorized_keys": PagureGitAuth,
         }[backend]
     else:
-        cls = classes[backend].load()
+        cls = classes[backend].load(False)
     _log.debug("Returning helper %r from backend key %r" % (cls, backend))
 
     GIT_AUTH_BACKEND_NAME = backend
diff --git a/pagure/utils.py b/pagure/utils.py
index a395d74..e15fed0 100644
--- a/pagure/utils.py
+++ b/pagure/utils.py
@@ -19,6 +19,7 @@ import re
 from functools import wraps
 
 import flask
+import markupsafe
 import pygit2
 import six
 import werkzeug.utils
diff --git a/requirements.txt b/requirements.txt
index d259c3a..c2e1a92 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -38,6 +38,8 @@ straight.plugin
 whitenoise <= 6.2.0
 wtforms <= 3.0.1
 
+markupsafe
+
 # Required only for the `oidc` authentication backend
 # Important: Until https://github.com/puiterwijk/flask-oidc/pull/144 is merged and a new version of flask-oidc is released, 
 # it's necessary to ensure `itsdangerous` is pinned to a version lower as 2.1 as well.

From 1a101456d54d1f42e0a6ae847321cae53ea4fe3a Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 6/14] feat(dev): Add spec file argument to container build


Optional: Define spec file from different url / path to use during container build. Default: https://pagure.io/pagure/raw/master/f/files/pagure.spec.

---

diff --git a/dev/run-tests-container.py b/dev/run-tests-container.py
index 3b5ab22..dd7db58 100755
--- a/dev/run-tests-container.py
+++ b/dev/run-tests-container.py
@@ -169,6 +169,15 @@ def setup_parser():
              "branch in current directory, can also be overridden by "
              "using the BRANCH environment variable",
     )
+    parser.add_argument(
+        "--specfile",
+        dest="specfile",
+        default="https://pagure.io/pagure/raw/master/f/files/pagure.spec",
+        help="Specfile to use when installing RPM packages during container build. "
+             "Defaults to https://pagure.io/pagure/raw/master/f/files/pagure.spec. "
+             "Can also be overridden by using the SPECFILE environment variable "
+             "Use spec file from current pagure folder: file:///wrkdir/files/pagure.spec",
+    )
 
     return parser
 
@@ -261,6 +270,7 @@ if __name__ == "__main__":
                 container_volume,
                 branch="{}".format(os.environ.get("BRANCH") or args.branch),
                 repo="{}".format(os.environ.get("REPO") or args.repo),
+                specfile="{}".format(os.environ.get("SPECFILE") or args.specfile),
             ):
                 base_build = True
             else:

From 50c49a5fde76f00d116830a57fc315f914886845 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 7/14] tests: Fix AssertionError: 'ISO-8859-9' != 'ISO-8859-2'


---

diff --git a/tests/test_pagure_lib_encoding_utils.py b/tests/test_pagure_lib_encoding_utils.py
index 7b06620..137b198 100644
--- a/tests/test_pagure_lib_encoding_utils.py
+++ b/tests/test_pagure_lib_encoding_utils.py
@@ -40,7 +40,7 @@ class TestGuessEncoding(unittest.TestCase):
         """
         Test that strings that could be UTF-8 or ISO-8859-* result in UTF-8.
 
-        python-chardet-3.0.4-2.fc27.noarch detects it as ISO-8859-9
+        python-chardet-3.0.4-2.fc27.noarch and above detects it as ISO-8859-9
         python-chardet-2.2.1-1.el7_1.noarch detects it as ISO-8859-2
         """
         data = "Šabata".encode("utf-8")
@@ -50,7 +50,7 @@ class TestGuessEncoding(unittest.TestCase):
             self.assertEqual(result, "WINDOWS-1250")
         else:
             self.assertEqual(result, "utf-8")
-            if chardet.__version__[0] in ("3", "4"):
+            if chardet.__version__[0] in ("3", "4", "5"):
                 self.assertEqual(chardet_result["encoding"], "ISO-8859-9")
             else:
                 self.assertEqual(chardet_result["encoding"], "ISO-8859-2")

From 86a42ecdee4d9f1f47b9dfdaf80815464874af4b Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 8/14] tests: Fix AssertionError: 'TIS-620' != 'windows-1255' and AssertionError: Lists differ


Issues caused by changes in chadet 5.0.0 and 5.1.0

---

diff --git a/tests/test_pagure_lib_encoding_utils.py b/tests/test_pagure_lib_encoding_utils.py
index 137b198..1559333 100644
--- a/tests/test_pagure_lib_encoding_utils.py
+++ b/tests/test_pagure_lib_encoding_utils.py
@@ -75,7 +75,11 @@ class TestGuessEncodings(unittest.TestCase):
                 # The first three have different confidence values
                 expexted_list = ["utf-8", "ISO-8859-9", "ISO-8859-1"]
                 # This is the one with the least confidence
-                self.assertEqual(result[-1].encoding, "windows-1255")
+                print(result)
+                if chardet.__version__ >= '5.1.0':
+                    self.assertEqual(result[-1].encoding, "TIS-620")
+                else:
+                    self.assertEqual(result[-1].encoding, "windows-1255")
                 self.assertListEqual(
                     [encoding.encoding for encoding in result][:3],
                     expexted_list,
@@ -83,30 +87,58 @@ class TestGuessEncodings(unittest.TestCase):
 
                 # The values in the middle of the list all have the same confidence
                 # value and can't be sorted reliably: use sets.
-                expected_list = sorted(
-                    [
-                        "utf-8",
-                        "ISO-8859-9",
-                        "ISO-8859-1",
-                        "MacCyrillic",
-                        "IBM866",
-                        "TIS-620",
-                        "EUC-JP",
-                        "EUC-KR",
-                        "GB2312",
-                        "KOI8-R",
-                        "Big5",
-                        "IBM855",
-                        "ISO-8859-7",
-                        "SHIFT_JIS",
-                        "windows-1253",
-                        "CP949",
-                        "EUC-TW",
-                        "ISO-8859-5",
-                        "windows-1251",
-                        "windows-1255",
-                    ]
-                )
+                if chardet.__version__ >= '5.1.0':
+                    expected_list = sorted(
+                        [
+                            "utf-8",
+                            "ISO-8859-9",
+                            "ISO-8859-1",
+                            "MacCyrillic",
+                            "IBM866",
+                            "TIS-620",
+                            "EUC-JP",
+                            "EUC-KR",
+                            "GB2312",
+                            "KOI8-R",
+                            "Big5",
+                            "IBM855",
+                            "ISO-8859-7",
+                            "SHIFT_JIS",
+                            "windows-1253",
+                            "CP949",
+                            "EUC-TW",
+                            "ISO-8859-5",
+                            "windows-1251",
+                            "windows-1255",
+                            "Johab",  # Added in 5.0.0
+                            "MacRoman",  # Added in 5.1.0
+                        ]
+                    )
+                else:
+                    expected_list = sorted(
+                        [
+                            "utf-8",
+                            "ISO-8859-9",
+                            "ISO-8859-1",
+                            "MacCyrillic",
+                            "IBM866",
+                            "TIS-620",
+                            "EUC-JP",
+                            "EUC-KR",
+                            "GB2312",
+                            "KOI8-R",
+                            "Big5",
+                            "IBM855",
+                            "ISO-8859-7",
+                            "SHIFT_JIS",
+                            "windows-1253",
+                            "CP949",
+                            "EUC-TW",
+                            "ISO-8859-5",
+                            "windows-1251",
+                            "windows-1255",
+                        ]
+                    )
                 self.assertListEqual(
                     sorted(set([encoding.encoding for encoding in result])),
                     expected_list,

From cadff23f68f43563d3d3a4abca2e0256002e9f42 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 9/14] fix(flask-oidc): Make tests and code functional with >= 2.0.0


Code changes and fixes in tests and pagure code because of deprecations and changes in flask-oidc >= 2.0.0
- Decorator 'oidc.require_login' replaced method 'redirect_to_auth_server'
- 'flask.session["oidc_auth_profile"]' used instead of 'flask.g._oidc_userinfo'

---

diff --git a/pagure/flask_app.py b/pagure/flask_app.py
index 3481e95..ada0f4e 100644
--- a/pagure/flask_app.py
+++ b/pagure/flask_app.py
@@ -458,8 +458,17 @@ def auth_login():  # pragma: no cover
         # execution will go through the else clause, making the Pagure
         # authentication machinery pick the user up
         if not oidc.user_loggedin:
-            return oidc.redirect_to_auth_server(flask.request.url)
+            if "redirect_to_auth_server" in dir(oidc):  # Available in flask-oidc < 2.0.0
+                return oidc.redirect_to_auth_server(flask.request.url)
+            else:
+                # flask-oidc >= 2.0.0 offers decorator 'oidc.require_login' and removed method 'redirect_to_auth_server'
+                @oidc.require_login
+                def _oidc_redirect_to_auth_server():
+                    pass
+
+                return _oidc_redirect_to_auth_server()
         else:
+            flask.g.test["test"] = "oidc.user_loggedin - TRUE"
             flask.session["oidc_logintime"] = time.time()
             fas_user_from_oidc()
             authenticated = pagure.utils.authenticated()
diff --git a/pagure/ui/oidc_login.py b/pagure/ui/oidc_login.py
index d475d05..4ed4cdb 100644
--- a/pagure/ui/oidc_login.py
+++ b/pagure/ui/oidc_login.py
@@ -43,10 +43,15 @@ def fas_user_from_oidc():
             pagure_config["OIDC_PAGURE_SSH_KEY"],
             pagure_config["OIDC_PAGURE_GROUPS"],
         ]
+
+        # flask-oidc >= 2.0.0, < 3.0.0
+        # The user_getinfo method is deprecated, please use session['oidc_auth_profile']
+        # Requires attention on next major release
         info = oidc.user_getinfo(
             [email_key, fulln_key, usern_key, ssh_key, groups_key]
         )
         username = info.get(usern_key)
+
         if not username:
             fb = pagure_config["OIDC_PAGURE_USERNAME_FALLBACK"]
             if fb == "email":
diff --git a/tests/test_pagure_flask_ui_oidc_login.py b/tests/test_pagure_flask_ui_oidc_login.py
index 4a33e13..99cdc43 100644
--- a/tests/test_pagure_flask_ui_oidc_login.py
+++ b/tests/test_pagure_flask_ui_oidc_login.py
@@ -39,6 +39,7 @@ CLIENT_SECRETS = {
         "token_uri": "dummy-uri://",
         "userinfo_uri": "dummy-uri://",
         "redirect_uris": ["http://localhost:5000/oidc"],
+        "issuer": "http://localhost:5000/oidc/"  # Additional field, required since flask-oidc v2.0.0
     }
 }
 
@@ -75,19 +76,22 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         with open(secrets_path, "w") as secrets:
             secrets.write(json.dumps(CLIENT_SECRETS))
 
-        oidc.init_app(self.app)
-
         self.request_context = self.app.test_request_context("/")
         self.request_context.push()
         flask.session["oidc_logintime"] = "dummy-logintime"
         flask.g.session = Mock()  # the DB session should be here
-        flask.g.oidc_id_token = {"sub": "dummy"}
+
+        flask.g.oidc_id_token = {"sub": "dummy"}  # Used in flask-oidc < 2.0.0
+        flask.session["oidc_auth_token"] = {"sub": "dummy"}  # Used in flask-oidc >= 2.0.0
+
         self.user_info = {
             "email": "dummy@example.com",
             "name": "Dummy User",
             "preferred_username": "dummy",
         }
 
+        oidc.init_app(self.app)
+
     def tearDown(self):
         self.request_context.pop()
         self.config_patcher.stop()
@@ -95,7 +99,10 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
     def test_fas_user_from_oidc(self):
         """Test the user creation function."""
         user_info = self.user_info.copy()
-        flask.g._oidc_userinfo = user_info
+
+        flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
+        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+
         fas_user_from_oidc()
         self.assertIsNotNone(getattr(flask.g, "fas_user", None))
         self.assertEqual(flask.g.fas_user.username, "dummy")
@@ -107,7 +114,10 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         """Test the user creation function."""
         user_info = self.user_info.copy()
         user_info["groups"] = ["group1", "group2"]
-        flask.g._oidc_userinfo = user_info
+
+        flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
+        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.groups, ["group1", "group2"])
 
@@ -115,7 +125,10 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         """Test the user creation function."""
         user_info = self.user_info.copy()
         user_info["ssh_key"] = "dummy ssh key"
-        flask.g._oidc_userinfo = user_info
+
+        flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
+        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.ssh_key, "dummy ssh key")
 
@@ -123,7 +136,10 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         """The SSH key may be base64-encoded"""
         user_info = self.user_info.copy()
         user_info["ssh_key"] = "ZHVtbXkgc3NoIGtleQ=="
-        flask.g._oidc_userinfo = user_info
+
+        flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
+        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.ssh_key, "dummy ssh key")
 

From e45f8fb64583a202e0570c4f2023f39984bf6f0e Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 10/14] build(pip): version pins align with f40 rpm packages


Until tech depts are sorted out, we need some version stability

---

diff --git a/requirements-ci.txt b/requirements-ci.txt
index 0f7f53a..d03f1fd 100644
--- a/requirements-ci.txt
+++ b/requirements-ci.txt
@@ -1,2 +1,2 @@
-cryptography <= 36.0.0
-python-jenkins <= 1.7.0
+cryptography <= 41.0.7
+python-jenkins <= 1.8.2
diff --git a/requirements-testing.txt b/requirements-testing.txt
index 7f3f50f..4d52f1a 100644
--- a/requirements-testing.txt
+++ b/requirements-testing.txt
@@ -1,15 +1,13 @@
-bcrypt <= 3.2.2
-beautifulsoup4 <= 4.11.1
-black <= 22.8.0
-cryptography <= 36.0.0
-eventlet <= 0.33.2
+beautifulsoup4 <= 4.12.3
+black <= 24.4.2
+eventlet <= 0.35.1
 fedmsg <= 1.1.2
-flake8
+flake8 <= 6.0.0
 
-# Important: Until https://github.com/puiterwijk/flask-oidc/pull/144 is merged and a new version of flask-oidc is released,
-# it's necessary to ensure `itsdangerous` is pinned to a version lower as 2.1 as well.
-flask-oidc <= 1.4.0
-itsdangerous < 2.1          
+# fedora-infra maintains its own flask-oidc fork: https://github.com/fedora-infra/flask-oidc
+# previous upstream PR (https://github.com/puiterwijk/flask-oidc/pull/144) fixed in fork.
+flask-oidc <= 2.1.1
+itsdangerous >=2.1.2
 
 mock <= 4.0.3
 pagure-messages >= 0.0.1
diff --git a/requirements.txt b/requirements.txt
index c2e1a92..aa0bbba 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,53 +1,53 @@
 # Used for when working from a virtualenv.
 # Use this file by running "$ pip install -r requirements.txt"
-alembic <= 1.8.1
+alembic <= 1.13.2
 arrow <= 1.2.3
-bcrypt <= 3.2.2
+bcrypt <= 4.0.1
 binaryornot == 0.4.4
-bleach <= 5.0.1
-blinker <= 1.5
-celery
-chardet <= 4.0.0
-cryptography <= 36.0.0
-docutils <= 0.17.1
+bleach <= 6.1.0
+blinker <= 1.7.0
+celery <= 5.3.5
+chardet <= 5.2.0
+cryptography <= 41.0.7
+docutils <= 0.20.1
 
 # required for backward compatibility
 email_validator
 
-flask <= 2.2.2
-werkzeug < 3.0.0
-flask-wtf <= 1.0.0
+flask <= 3.0.3
+werkzeug <= 3.0.3
+flask-wtf <= 1.2.1
 kitchen == 1.2.6
-markdown
+markdown <= 3.5.2
 munch <= 2.5.0
-Pillow <= 9.2.0
-psutil <= 5.9.2
+Pillow <= 10.3.0
+psutil <= 5.9.8
 pygit2 < 1.15.0
 python3-openid <= 3.2.0
 python-openid-cla == 1.2
 python-openid-teams == 1.1
 redis
-requests <= 2.28.1
+requests <= 2.31.0
 six <= 1.16.0
 
 # required for backward compatibility
 setuptools
 
-sqlalchemy < 2.0.0
+sqlalchemy <= 2.0.34
 straight.plugin
-whitenoise <= 6.2.0
+whitenoise <= 6.4.0
 wtforms <= 3.0.1
 
 markupsafe
 
 # Required only for the `oidc` authentication backend
-# Important: Until https://github.com/puiterwijk/flask-oidc/pull/144 is merged and a new version of flask-oidc is released, 
-# it's necessary to ensure `itsdangerous` is pinned to a version lower as 2.1 as well.
-# flask-oidc <= 1.4.0
-# itsdangerous < 2.1
+# fedora-infra maintains its own flask-oidc fork: https://github.com/fedora-infra/flask-oidc
+# previous upstream PR (https://github.com/puiterwijk/flask-oidc/pull/144) fixed in fork.
+# flask-oidc <= 2.1.1
+# itsdangerous >=2.1.2
 
 # Required only if `USE_FLASK_SESSION_EXT` is set to `True`
-# flask-session
+# flask-session <= 0.5.0
 
 # Required only for the `fas` and `openid` authentication backends
 # python-fedora == 1.1.1

From e5fb497ebc671b137200f34e7cfc1a1c7917913f Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 11/14] tests(tox): Drop Python 3.10 from tox env and testing


---

diff --git a/tox.ini b/tox.ini
index c662fd2..7173457 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{39,310,311,312}
+envlist = py{39,311,312}
 skipsdist = True
 # If the user is missing an interpreter, don't fail
 skip_missing_interpreters = True

From 8ae26614293685c3386782a8b1f4eaa4772a27df Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 12/14] refactor: Address flake8 findings


---

diff --git a/pagure/cli/admin.py b/pagure/cli/admin.py
index c8a7834..2f7487d 100644
--- a/pagure/cli/admin.py
+++ b/pagure/cli/admin.py
@@ -893,7 +893,7 @@ def do_sanitize_spam_user(args):
             session.add(user)
             session.commit()
 
-    print(f"\n\n# Activity by {user.user} that needs to be removed manually:")
+    print(f"\n\n# Activity by {user.user} that needs to be removed manually: ")
 
     print("## Issue Comments")
     if comments:
diff --git a/pagure/flask_app.py b/pagure/flask_app.py
index ada0f4e..e9baa50 100644
--- a/pagure/flask_app.py
+++ b/pagure/flask_app.py
@@ -458,10 +458,12 @@ def auth_login():  # pragma: no cover
         # execution will go through the else clause, making the Pagure
         # authentication machinery pick the user up
         if not oidc.user_loggedin:
-            if "redirect_to_auth_server" in dir(oidc):  # Available in flask-oidc < 2.0.0
+            # Available in flask-oidc < 2.0.0
+            if "redirect_to_auth_server" in dir(oidc):
                 return oidc.redirect_to_auth_server(flask.request.url)
             else:
-                # flask-oidc >= 2.0.0 offers decorator 'oidc.require_login' and removed method 'redirect_to_auth_server'
+                # flask-oidc >= 2.0.0 offers decorator 'oidc.require_login'
+                # and removed method 'redirect_to_auth_server'
                 @oidc.require_login
                 def _oidc_redirect_to_auth_server():
                     pass
diff --git a/pagure/ui/oidc_login.py b/pagure/ui/oidc_login.py
index 4ed4cdb..60e2111 100644
--- a/pagure/ui/oidc_login.py
+++ b/pagure/ui/oidc_login.py
@@ -45,7 +45,8 @@ def fas_user_from_oidc():
         ]
 
         # flask-oidc >= 2.0.0, < 3.0.0
-        # The user_getinfo method is deprecated, please use session['oidc_auth_profile']
+        # "The user_getinfo method is deprecated
+        # please use session['oidc_auth_profile']"
         # Requires attention on next major release
         info = oidc.user_getinfo(
             [email_key, fulln_key, usern_key, ssh_key, groups_key]
diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py
index aad9cef..6978ff7 100644
--- a/pagure/ui/repo.py
+++ b/pagure/ui/repo.py
@@ -28,6 +28,7 @@ from math import ceil
 
 import flask
 import kitchen.text.converters as ktc
+import markupsafe
 import pygit2
 import six
 import werkzeug.utils

From db9886e41d72200de92fc23fc6084fc48b2d6c2b Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Sep 27 2024 09:27:37 +0000
Subject: [PATCH 13/14] refactor: Address black findings


---

diff --git a/pagure/api/fork.py b/pagure/api/fork.py
index f8bd223..3376d14 100644
--- a/pagure/api/fork.py
+++ b/pagure/api/fork.py
@@ -701,9 +701,11 @@ def api_pull_request_rebase(repo, requestid, username=None, namespace=None):
     if not ((is_repo_committer(repo) and request.allow_rebase) or can_rebase):
         raise pagure.exceptions.APIError(
             403,
-            error_code=APIERROR.EREBASENOTALLOWED
-            if not request.allow_rebase
-            else APIERROR.ENOPRCLOSE,
+            error_code=(
+                APIERROR.EREBASENOTALLOWED
+                if not request.allow_rebase
+                else APIERROR.ENOPRCLOSE
+            ),
         )
 
     task = pagure.lib.tasks.rebase_pull_request.delay(
diff --git a/pagure/api/plugins.py b/pagure/api/plugins.py
index 6e7cf96..51aa916 100644
--- a/pagure/api/plugins.py
+++ b/pagure/api/plugins.py
@@ -294,7 +294,7 @@ def api_view_plugins_project(repo, username=None, namespace=None):
 
     output["plugins"] = []
 
-    for (plugin, dbobj) in plugins.items():
+    for plugin, dbobj in plugins.items():
         if dbobj:
             form = plugin.form(obj=dbobj)
             fields = _filter_fields(plugin)
diff --git a/pagure/api/project.py b/pagure/api/project.py
index d2db558..80e0f22 100644
--- a/pagure/api/project.py
+++ b/pagure/api/project.py
@@ -545,10 +545,10 @@ def api_project_watchers(repo, username=None, namespace=None):
     # Get the explicit watch statuses
     for watcher in repo.watchers:
         if watcher.watch_issues or watcher.watch_commits:
-            watching_users_to_watch_level[
-                watcher.user.username
-            ] = pagure.lib.query.get_watch_level_on_repo(
-                flask.g.session, watcher.user.username, repo
+            watching_users_to_watch_level[watcher.user.username] = (
+                pagure.lib.query.get_watch_level_on_repo(
+                    flask.g.session, watcher.user.username, repo
+                )
             )
         else:
             if watcher.user.username in watching_users_to_watch_level:
@@ -1228,9 +1228,11 @@ def api_projects():
             {
                 "name": p.name,
                 "namespace": p.namespace,
-                "fullname": p.fullname.replace("forks/", "fork/", 1)
-                if p.fullname.startswith("forks/")
-                else p.fullname,
+                "fullname": (
+                    p.fullname.replace("forks/", "fork/", 1)
+                    if p.fullname.startswith("forks/")
+                    else p.fullname
+                ),
                 "description": p.description,
             }
             for p in projects
diff --git a/pagure/config.py b/pagure/config.py
index 9f5b4c9..61f81c1 100644
--- a/pagure/config.py
+++ b/pagure/config.py
@@ -34,9 +34,9 @@ def reload_config():
     if config["ENABLE_DOCS"]:
         config["DOCS_FOLDER"] = os.path.join(config["GIT_FOLDER"], "docs")
     else:
-        config[
-            "DOCS_FOLDER"
-        ] = None  # Avoid 'KeyError' Exception down the line
+        config["DOCS_FOLDER"] = (
+            None  # Avoid 'KeyError' Exception down the line
+        )
     if config["ENABLE_TICKETS"]:
         config["TICKETS_FOLDER"] = os.path.join(
             config["GIT_FOLDER"], "tickets"
diff --git a/pagure/forms.py b/pagure/forms.py
index c8f586f..bedee7f 100644
--- a/pagure/forms.py
+++ b/pagure/forms.py
@@ -609,7 +609,7 @@ class AddSSHKeyForm(PagureForm):
 
     ssh_key = wtforms.StringField(
         "SSH Key",
-        [wtforms.validators.DataRequired()]
+        [wtforms.validators.DataRequired()],
         # TODO: Add an ssh key validator?
     )
 
diff --git a/pagure/hooks/default.py b/pagure/hooks/default.py
index fbda401..d149dba 100644
--- a/pagure/hooks/default.py
+++ b/pagure/hooks/default.py
@@ -141,9 +141,11 @@ def send_action_notification(
     msg = dict(
         authors=[author],
         agent=user,
-        repo=project.to_json(public=True)
-        if not isinstance(project, six.string_types)
-        else project,
+        repo=(
+            project.to_json(public=True)
+            if not isinstance(project, six.string_types)
+            else project
+        ),
     )
     if subject == "branch":
         msg["branch"] = refname
@@ -209,9 +211,11 @@ def send_notifications(
             authors=list(authors),
             changed_files=changed_files,
             agent=user,
-            repo=project.to_json(public=True)
-            if not isinstance(project, six.string_types)
-            else project,
+            repo=(
+                project.to_json(public=True)
+                if not isinstance(project, six.string_types)
+                else project
+            ),
             pull_request_id=pr_id,
         )
 
diff --git a/pagure/lib/git.py b/pagure/lib/git.py
index 7bf40fa..e10e738 100644
--- a/pagure/lib/git.py
+++ b/pagure/lib/git.py
@@ -1596,9 +1596,11 @@ def merge_pull_request(session, request, username, domerge=True):
                     "Branch %s could not be found in the repo %s"
                     % (
                         request.branch_from,
-                        request.project_from.fullname
-                        if request.project_from
-                        else request.remote_git,
+                        (
+                            request.project_from.fullname
+                            if request.project_from
+                            else request.remote_git
+                        ),
                     )
                 )
 
diff --git a/pagure/lib/model.py b/pagure/lib/model.py
index 4fa0d85..9f54e5f 100644
--- a/pagure/lib/model.py
+++ b/pagure/lib/model.py
@@ -1039,9 +1039,11 @@ class Project(BASE):
             "full_url": self.full_url,
             "description": self.description,
             "namespace": self.namespace,
-            "parent": self.parent.to_json(public=public, api=api)
-            if self.parent
-            else None,
+            "parent": (
+                self.parent.to_json(public=public, api=api)
+                if self.parent
+                else None
+            ),
             "date_created": arrow_ts(self.date_created),
             "date_modified": arrow_ts(self.date_modified),
             "user": self.user.to_json(public=public),
@@ -1507,20 +1509,22 @@ class Issue(BASE):
             "tags": self.tags_text,
             "depends": ["%s" % item for item in self.depending_text],
             "blocks": ["%s" % item for item in self.blocking_text],
-            "assignee": self.assignee.to_json(public=public)
-            if self.assignee
-            else None,
+            "assignee": (
+                self.assignee.to_json(public=public) if self.assignee else None
+            ),
             "priority": self.priority,
             "milestone": self.milestone,
             "custom_fields": custom_fields,
-            "closed_by": self.closed_by.to_json(public=public)
-            if self.closed_by
-            else None,
-            "related_prs": [
-                {"id": pr.id, "title": pr.title} for pr in self.related_prs
-            ]
-            if self.related_prs
-            else [],
+            "closed_by": (
+                self.closed_by.to_json(public=public)
+                if self.closed_by
+                else None
+            ),
+            "related_prs": (
+                [{"id": pr.id, "title": pr.title} for pr in self.related_prs]
+                if self.related_prs
+                else []
+            ),
             "full_url": self.full_url,
         }
 
@@ -1683,9 +1687,9 @@ class IssueComment(BASE):
             "date_created": arrow_ts(self.date_created),
             "user": self.user.to_json(public=public),
             "edited_on": arrow_ts(self.edited_on) if self.edited_on else None,
-            "editor": self.editor.to_json(public=public)
-            if self.editor_id
-            else None,
+            "editor": (
+                self.editor.to_json(public=public) if self.editor_id else None
+            ),
             "notification": self.notification,
             "reactions": self.reactions,
         }
@@ -2212,24 +2216,28 @@ class PullRequest(BASE):
             "branch": self.branch,
             "project": self.project.to_json(public=public, api=api),
             "branch_from": self.branch_from,
-            "repo_from": self.project_from.to_json(public=public, api=api)
-            if self.project_from
-            else None,
+            "repo_from": (
+                self.project_from.to_json(public=public, api=api)
+                if self.project_from
+                else None
+            ),
             "remote_git": self.remote_git,
             "date_created": arrow_ts(self.date_created),
             "updated_on": arrow_ts(self.updated_on),
             "last_updated": arrow_ts(self.last_updated),
             "closed_at": arrow_ts(self.closed_at) if self.closed_at else None,
             "user": self.user.to_json(public=public),
-            "assignee": self.assignee.to_json(public=public)
-            if self.assignee
-            else None,
+            "assignee": (
+                self.assignee.to_json(public=public) if self.assignee else None
+            ),
             "status": self.status,
             "commit_start": self.commit_start,
             "commit_stop": self.commit_stop,
-            "closed_by": self.closed_by.to_json(public=public)
-            if self.closed_by
-            else None,
+            "closed_by": (
+                self.closed_by.to_json(public=public)
+                if self.closed_by
+                else None
+            ),
             "initial_comment": self.initial_comment,
             "cached_merge_status": self.merge_status or "unknown",
             "threshold_reached": self.threshold_reached,
@@ -2358,9 +2366,9 @@ class PullRequestComment(BASE):
             "date_created": arrow_ts(self.date_created),
             "user": self.user.to_json(public=public),
             "edited_on": arrow_ts(self.edited_on) if self.edited_on else None,
-            "editor": self.editor.to_json(public=public)
-            if self.editor_id
-            else None,
+            "editor": (
+                self.editor.to_json(public=public) if self.editor_id else None
+            ),
             "notification": self.notification,
             "reactions": self.reactions,
         }
diff --git a/pagure/lib/query.py b/pagure/lib/query.py
index dccc173..73c5547 100644
--- a/pagure/lib/query.py
+++ b/pagure/lib/query.py
@@ -4371,37 +4371,39 @@ def clean_input(text, ignore=None):
             attrs["img"] = filter_img_src
 
     tags = list(bleach.ALLOWED_TAGS)
-    tags.extend([
-        "p",
-        "br",
-        "div",
-        "h1",
-        "h2",
-        "h3",
-        "h4",
-        "h5",
-        "h6",
-        "table",
-        "td",
-        "tr",
-        "th",
-        "thead",
-        "tbody",
-        "col",
-        "pre",
-        "img",
-        "hr",
-        "dl",
-        "dt",
-        "dd",
-        "span",
-        "kbd",
-        "var",
-        "del",
-        "cite",
-        "noscript",
-        "colgroup",
-    ])
+    tags.extend(
+        [
+            "p",
+            "br",
+            "div",
+            "h1",
+            "h2",
+            "h3",
+            "h4",
+            "h5",
+            "h6",
+            "table",
+            "td",
+            "tr",
+            "th",
+            "thead",
+            "tbody",
+            "col",
+            "pre",
+            "img",
+            "hr",
+            "dl",
+            "dt",
+            "dd",
+            "span",
+            "kbd",
+            "var",
+            "del",
+            "cite",
+            "noscript",
+            "colgroup",
+        ]
+    )
     if ignore:
         for tag in ignore:
             if tag in tags:
diff --git a/pagure/lib/tasks_services.py b/pagure/lib/tasks_services.py
index 1bef240..070dab1 100644
--- a/pagure/lib/tasks_services.py
+++ b/pagure/lib/tasks_services.py
@@ -415,7 +415,6 @@ def trigger_ci_build(
     project_name=None,
     pr_uid=None,
 ):
-
     """Triggers a new run of the CI system on the specified pull-request."""
     pagure.lib.plugins.get_plugin("Pagure CI")
 
diff --git a/pagure/pfmarkdown.py b/pagure/pfmarkdown.py
index 5cf8baa..59bc0c9 100644
--- a/pagure/pfmarkdown.py
+++ b/pagure/pfmarkdown.py
@@ -445,9 +445,9 @@ class PagureExtension(markdown.extensions.Extension):
             md.inlinePatterns["striked"] = StrikeThroughPattern(
                 STRIKE_THROUGH_RE
             )
-            md.postprocessors[
-                "encapsulate"
-            ] = EncapsulateMarkdownPostprocessor()
+            md.postprocessors["encapsulate"] = (
+                EncapsulateMarkdownPostprocessor()
+            )
 
         def _new_markdown_way():
             idx = md.inlinePatterns.get_index_for_name("autolink")
diff --git a/pagure/ui/app.py b/pagure/ui/app.py
index 9c9528c..d29245d 100644
--- a/pagure/ui/app.py
+++ b/pagure/ui/app.py
@@ -610,9 +610,9 @@ def view_projects(pattern=None, namespace=None):
                 "ui_ns.view_repo",
                 repo=projects[0].name,
                 namespace=projects[0].namespace,
-                username=projects[0].user.username
-                if projects[0].is_fork
-                else None,
+                username=(
+                    projects[0].user.username if projects[0].is_fork else None
+                ),
             )
         )
 
diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py
index 0618bd0..4786d3a 100644
--- a/pagure/ui/filters.py
+++ b/pagure/ui/filters.py
@@ -242,9 +242,11 @@ def format_loc(
                         flask.url_for(
                             "ui_ns.view_file",
                             repo=prequest.project_from.name,
-                            username=prequest.project_from.user.username
-                            if prequest.project_from.is_fork
-                            else None,
+                            username=(
+                                prequest.project_from.user.username
+                                if prequest.project_from.is_fork
+                                else None
+                            ),
                             namespace=prequest.project_from.namespace,
                             identifier=prequest.branch_from,
                             filename=filename,
@@ -328,9 +330,11 @@ def format_loc(
                                 namespace=comment.parent.project.namespace,
                                 requestid=comment.parent.id,
                                 commentid=comment.id,
-                                username=comment.parent.user.user
-                                if comment.parent.project.is_fork
-                                else None,
+                                username=(
+                                    comment.parent.user.user
+                                    if comment.parent.project.is_fork
+                                    else None
+                                ),
                             ),
                             "requestid": comment.parent.id,
                             "commentid": comment.id,
diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py
index 6978ff7..8d8d26a 100644
--- a/pagure/ui/repo.py
+++ b/pagure/ui/repo.py
@@ -2344,9 +2344,11 @@ def add_token(repo, username=None, namespace=None):
             pagure.lib.query.add_token_to_user(
                 flask.g.session,
                 repo,
-                description=form.description.data.strip()
-                if form.description.data
-                else None,
+                description=(
+                    form.description.data.strip()
+                    if form.description.data
+                    else None
+                ),
                 acls=form.acls.data,
                 username=flask.g.fas_user.username,
                 expiration_date=form.expiration_date.data,
diff --git a/tests/test_pagure_flask_ui_app.py b/tests/test_pagure_flask_ui_app.py
index 9f50fe3..dce6cde 100644
--- a/tests/test_pagure_flask_ui_app.py
+++ b/tests/test_pagure_flask_ui_app.py
@@ -729,9 +729,9 @@ class PagureFlaskApptests(tests.Modeltests):
             self.assertIn("SSH key invalid", output_text)
 
             # Next up, multiple SSH keys
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            )
             output = self.app.post(
                 "/settings/usersettings/addkey",
                 data=data,
@@ -742,9 +742,9 @@ class PagureFlaskApptests(tests.Modeltests):
             self.assertIn("Please add single SSH keys.", output_text)
 
             # Now, a valid SSH key
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            )
             output = self.app.post(
                 "/settings/usersettings/addkey",
                 data=data,
@@ -769,9 +769,9 @@ class PagureFlaskApptests(tests.Modeltests):
             self.assertIn("SSH key already exists", output_text)
 
             # And next, a key with push access
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9Xwc2RDzPBhlEDARfHldGjudIVoa04tqT1JVKGQmyllTFz7Rb8CngQL3e7zyNzotnhwYKHdoiLlPkVEiDee4dWMUe48ilqId+FJZQGhyv8fu4BoFdE1AJUVylzmltbLg14VqG5gjTpXgtlrEva9arKwBMHJjRYc8ScaSn3OgyQw=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9Xwc2RDzPBhlEDARfHldGjudIVoa04tqT1JVKGQmyllTFz7Rb8CngQL3e7zyNzotnhwYKHdoiLlPkVEiDee4dWMUe48ilqId+FJZQGhyv8fu4BoFdE1AJUVylzmltbLg14VqG5gjTpXgtlrEva9arKwBMHJjRYc8ScaSn3OgyQw=="
+            )
             output = self.app.post(
                 "/settings/usersettings/addkey",
                 data=data,
diff --git a/tests/test_pagure_flask_ui_oidc_login.py b/tests/test_pagure_flask_ui_oidc_login.py
index 99cdc43..19da600 100644
--- a/tests/test_pagure_flask_ui_oidc_login.py
+++ b/tests/test_pagure_flask_ui_oidc_login.py
@@ -39,7 +39,7 @@ CLIENT_SECRETS = {
         "token_uri": "dummy-uri://",
         "userinfo_uri": "dummy-uri://",
         "redirect_uris": ["http://localhost:5000/oidc"],
-        "issuer": "http://localhost:5000/oidc/"  # Additional field, required since flask-oidc v2.0.0
+        "issuer": "http://localhost:5000/oidc/",  # Additional field, required since flask-oidc v2.0.0
     }
 }
 
@@ -82,7 +82,9 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         flask.g.session = Mock()  # the DB session should be here
 
         flask.g.oidc_id_token = {"sub": "dummy"}  # Used in flask-oidc < 2.0.0
-        flask.session["oidc_auth_token"] = {"sub": "dummy"}  # Used in flask-oidc >= 2.0.0
+        flask.session["oidc_auth_token"] = {
+            "sub": "dummy"
+        }  # Used in flask-oidc >= 2.0.0
 
         self.user_info = {
             "email": "dummy@example.com",
@@ -101,7 +103,9 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         user_info = self.user_info.copy()
 
         flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
-        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+        flask.session["oidc_auth_profile"] = (
+            user_info  # Used in flask-oidc >= 2.0.0
+        )
 
         fas_user_from_oidc()
         self.assertIsNotNone(getattr(flask.g, "fas_user", None))
@@ -116,7 +120,9 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         user_info["groups"] = ["group1", "group2"]
 
         flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
-        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+        flask.session["oidc_auth_profile"] = (
+            user_info  # Used in flask-oidc >= 2.0.0
+        )
 
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.groups, ["group1", "group2"])
@@ -127,7 +133,9 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         user_info["ssh_key"] = "dummy ssh key"
 
         flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
-        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+        flask.session["oidc_auth_profile"] = (
+            user_info  # Used in flask-oidc >= 2.0.0
+        )
 
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.ssh_key, "dummy ssh key")
@@ -138,7 +146,9 @@ class PagureFlaskOIDCLogintests(tests.SimplePagureTest):
         user_info["ssh_key"] = "ZHVtbXkgc3NoIGtleQ=="
 
         flask.g._oidc_userinfo = user_info  # Used in flask-oidc < 2.0.0
-        flask.session["oidc_auth_profile"] = user_info  # Used in flask-oidc >= 2.0.0
+        flask.session["oidc_auth_profile"] = (
+            user_info  # Used in flask-oidc >= 2.0.0
+        )
 
         fas_user_from_oidc()
         self.assertEqual(flask.g.fas_user.ssh_key, "dummy ssh key")
diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py
index ee1da57..a01c6b5 100644
--- a/tests/test_pagure_flask_ui_repo.py
+++ b/tests/test_pagure_flask_ui_repo.py
@@ -174,9 +174,9 @@ class PagureFlaskRepotests(tests.Modeltests):
             self.assertIn("SSH key invalid", output_text)
 
             # Next up, multiple SSH keys
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q==\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            )
             output = self.app.post(
                 "/test/adddeploykey", data=data, follow_redirects=True
             )
@@ -185,9 +185,9 @@ class PagureFlaskRepotests(tests.Modeltests):
             self.assertIn("Please add single SSH keys.", output_text)
 
             # Now, a valid SSH key
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAzBMSIlvPRaEiLOTVInErkRIw9CzQQcnslDekAn1jFnGf+SNa1acvbTiATbCX71AA03giKrPxPH79dxcC7aDXerc6zRcKjJs6MAL9PrCjnbyxCKXRNNZU5U9X/DLaaL1b3caB+WD6OoorhS3LTEtKPX8xyjOzhf3OQSzNjhJp5Q=="
+            )
             output = self.app.post(
                 "/test/adddeploykey", data=data, follow_redirects=True
             )
@@ -212,9 +212,9 @@ class PagureFlaskRepotests(tests.Modeltests):
             self.assertIn("SSH key already exists", output_text)
 
             # And next, a key with push access
-            data[
-                "ssh_key"
-            ] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9Xwc2RDzPBhlEDARfHldGjudIVoa04tqT1JVKGQmyllTFz7Rb8CngQL3e7zyNzotnhwYKHdoiLlPkVEiDee4dWMUe48ilqId+FJZQGhyv8fu4BoFdE1AJUVylzmltbLg14VqG5gjTpXgtlrEva9arKwBMHJjRYc8ScaSn3OgyQw=="
+            data["ssh_key"] = (
+                "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9Xwc2RDzPBhlEDARfHldGjudIVoa04tqT1JVKGQmyllTFz7Rb8CngQL3e7zyNzotnhwYKHdoiLlPkVEiDee4dWMUe48ilqId+FJZQGhyv8fu4BoFdE1AJUVylzmltbLg14VqG5gjTpXgtlrEva9arKwBMHJjRYc8ScaSn3OgyQw=="
+            )
             data["pushaccess"] = "true"
             output = self.app.post(
                 "/test/adddeploykey", data=data, follow_redirects=True
diff --git a/tests/test_pagure_lib.py b/tests/test_pagure_lib.py
index b404f88..c3b6eff 100644
--- a/tests/test_pagure_lib.py
+++ b/tests/test_pagure_lib.py
@@ -4288,9 +4288,11 @@ class PagureLibtests(tests.Modeltests):
             # and the version 1.4.3 that we have won't let us adjust the
             # list of supported protocols
             # '<p><a href="ircs://pagure.io">ircs://pagure.io</a></p>',
-            '<div class="markdown"><p><a href="ircs://pagure.io">ircs://pagure.io</a></p></div>'
-            if tuple(bleach_v) >= (1, 5, 0)
-            else '<div class="markdown"><p><a>ircs://pagure.io</a></p></div>',
+            (
+                '<div class="markdown"><p><a href="ircs://pagure.io">ircs://pagure.io</a></p></div>'
+                if tuple(bleach_v) >= (1, 5, 0)
+                else '<div class="markdown"><p><a>ircs://pagure.io</a></p></div>'
+            ),
             # 'http://pagure.io'
             '<div class="markdown"><p><a href="http://pagure.io">http://pagure.io</a></p></div>',
             # 'https://pagure.io'
diff --git a/tests/test_pagure_lib_encoding_utils.py b/tests/test_pagure_lib_encoding_utils.py
index 1559333..3d040cd 100644
--- a/tests/test_pagure_lib_encoding_utils.py
+++ b/tests/test_pagure_lib_encoding_utils.py
@@ -76,7 +76,7 @@ class TestGuessEncodings(unittest.TestCase):
                 expexted_list = ["utf-8", "ISO-8859-9", "ISO-8859-1"]
                 # This is the one with the least confidence
                 print(result)
-                if chardet.__version__ >= '5.1.0':
+                if chardet.__version__ >= "5.1.0":
                     self.assertEqual(result[-1].encoding, "TIS-620")
                 else:
                     self.assertEqual(result[-1].encoding, "windows-1255")
@@ -87,7 +87,7 @@ class TestGuessEncodings(unittest.TestCase):
 
                 # The values in the middle of the list all have the same confidence
                 # value and can't be sorted reliably: use sets.
-                if chardet.__version__ >= '5.1.0':
+                if chardet.__version__ >= "5.1.0":
                     expected_list = sorted(
                         [
                             "utf-8",
diff --git a/tests/test_pagure_lib_mimetype.py b/tests/test_pagure_lib_mimetype.py
index 11b079d..e7f7d68 100644
--- a/tests/test_pagure_lib_mimetype.py
+++ b/tests/test_pagure_lib_mimetype.py
@@ -68,9 +68,11 @@ class TestMIMEType(unittest.TestCase):
             (
                 "hello",
                 b"#!",
-                "text/plain; charset=ascii"
-                if cchardet is None
-                else "text/plain; charset=ASCII",
+                (
+                    "text/plain; charset=ascii"
+                    if cchardet is None
+                    else "text/plain; charset=ASCII"
+                ),
             ),
             ("hello.jpg", None, "image/jpeg"),
             ("hello.jpg", b"#!", "image/jpeg"),

From a86c509eb0fb1f3b393ce52a42d99d879704a836 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Nov 18 2024 11:12:07 +0000
Subject: [PATCH 14/14] tests: Drop mock 'pagure.lib.git._maybe_wait'


An unknown Async / wait / timing issue caused the following test to fail:
    FAILED
    tests/test_pagure_flask_dump_load_ticket.py::PagureFlaskDumpLoadTicketTests::test_dumping_reloading_ticket
    - Exception: Unable to find object

This came from the override of 'pagure.lib.git._maybe_wait', default behavior is 'pass', mock made it a 'result.get()'.
Likely that the version bump to a newer Celery major release was the root cause.
Without this enforced wait, the test passes.

---

diff --git a/tests/test_pagure_flask_dump_load_ticket.py b/tests/test_pagure_flask_dump_load_ticket.py
index 828a668..358adbe 100644
--- a/tests/test_pagure_flask_dump_load_ticket.py
+++ b/tests/test_pagure_flask_dump_load_ticket.py
@@ -37,10 +37,8 @@ class PagureFlaskDumpLoadTicketTests(tests.Modeltests):
     """
 
     @patch("pagure.lib.notify.send_email")
-    @patch("pagure.lib.git._maybe_wait")
-    def test_dumping_reloading_ticket(self, mw, send_email):
+    def test_dumping_reloading_ticket(self, send_email):
         """Test dumping a ticket into a JSON blob."""
-        mw.side_effect = lambda result: result.get()
         send_email.return_value = True
 
         tests.create_projects(self.session)

