diff options
author | CoprDistGit <infra@openeuler.org> | 2025-03-23 04:09:17 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-03-23 04:09:17 +0000 |
commit | 7dd0b309f06098eaea3584e5a2bd1e21b4830ed3 (patch) | |
tree | 4fd7c64fdc34624f85491f1e0bf14d8afb4bdbef | |
parent | bed3ab1ed2c9a92b20bae1d0f11f17d9051bfff9 (diff) |
automatic import of copr-backend
-rw-r--r-- | copr-backend.spec | 2 | ||||
-rw-r--r-- | support_signatrust_backend.patch | 749 |
2 files changed, 277 insertions, 474 deletions
diff --git a/copr-backend.spec b/copr-backend.spec index ae9f5f4..93c763f 100644 --- a/copr-backend.spec +++ b/copr-backend.spec @@ -40,7 +40,7 @@ BuildRequires: python3-setuptools BuildRequires: python3-copr BuildRequires: python3-kafka-python -BuildRequires: python3-copr-common = %copr_common_version +BuildRequires: python3-copr-common >= %copr_common_version BuildRequires: python3-daemon BuildRequires: python3-dateutil BuildRequires: python3-distro diff --git a/support_signatrust_backend.patch b/support_signatrust_backend.patch index d803d26..adcbf1e 100644 --- a/support_signatrust_backend.patch +++ b/support_signatrust_backend.patch @@ -1,116 +1,3 @@ -diff --git a/copr_backend/actions.py b/backend/copr_backend/actions.py -index 39722b843..6da2dfb65 100644 ---- a/copr_backend/actions.py -+++ b/copr_backend/actions.py -@@ -21,13 +21,13 @@ from copr_common.worker_manager import WorkerManager - - from copr_backend.worker_manager import BackendQueueTask - --from .sign import create_user_keys, CoprKeygenRequestError -+from .sign import CoprKeygenRequestError - from .exceptions import CreateRepoError, CoprSignError, FrontendClientException - from .helpers import (get_redis_logger, silent_remove, ensure_dir_exists, - get_chroot_arch, format_filename, - uses_devel_repo, call_copr_repo, build_chroot_log_name, - copy2_but_hardlink_rpms) --from .sign import sign_rpms_in_dir, unsign_rpms_in_dir, get_pubkey -+from .sign import new_signer - - - class Action(object): -@@ -92,6 +92,8 @@ class Action(object): - - self.log = log if log else get_redis_logger(self.opts, "backend.actions", "actions") - -+ self.signer = new_signer(opts) -+ - def __str__(self): - return "<{}(Action): {}>".format(self.__class__.__name__, self.data) - -@@ -147,7 +149,7 @@ class GPGMixin(object): - # skip key creation, most probably sign component is unused - return True - try: -- create_user_keys(ownername, projectname, self.opts) -+ self.signer.create_user_keys(ownername, projectname, self.opts) - return True - except CoprKeygenRequestError as e: - self.log.exception(e) -@@ -176,7 +178,7 @@ class Fork(Action, GPGMixin): - # Generate brand new gpg key. - self.generate_gpg_key(data["user"], data["copr"]) - # Put the new public key into forked build directory. -- get_pubkey(data["user"], data["copr"], self.log, self.opts.sign_domain, pubkey_path) -+ self.signer.get_pubkey(data["user"], data["copr"], self.log, self.opts.sign_domain, pubkey_path) - - chroot_paths = set() - for chroot, src_dst_dir in builds_map.items(): -@@ -206,9 +208,9 @@ class Fork(Action, GPGMixin): - continue - - # Drop old signatures coming from original repo and re-sign. -- unsign_rpms_in_dir(dst_path, opts=self.opts, log=self.log) -+ self.signer.unsign_rpms_in_dir(dst_path, opts=self.opts, log=self.log) - if sign: -- sign_rpms_in_dir(data["user"], data["copr"], dst_path, -+ self.signer.sign_rpms_in_dir(data["user"], data["copr"], dst_path, - chroot, opts=self.opts, log=self.log) - - self.log.info("Forked build %s as %s", src_path, dst_path) -diff --git a/copr_backend/background_worker.py b/backend/copr_backend/background_worker.py -index 4b5f13135..bc05edbd7 100644 ---- a/copr_backend/background_worker.py -+++ b/copr_backend/background_worker.py -@@ -9,7 +9,7 @@ import logging - from copr_common.background_worker import BackgroundWorker - from copr_backend.frontend import FrontendClient - from copr_backend.helpers import (BackendConfigReader, get_redis_logger) -- -+from copr_backend.sign import new_signer - - class BackendBackgroundWorker(BackgroundWorker): - """ -@@ -28,6 +28,7 @@ class BackendBackgroundWorker(BackgroundWorker): - - self.frontend_client = FrontendClient(self.opts, self.log, - try_indefinitely=True) -+ self.signer = new_signer(self.opts) - - def _switch_logger_to_redis(self): - logger_name = '{}.{}.pid-{}'.format( -diff --git a/copr_backend/background_worker_build.py b/backend/copr_backend/background_worker_build.py -index 0eee39ab8..c12d4921d 100644 ---- a/copr_backend/background_worker_build.py -+++ b/copr_backend/background_worker_build.py -@@ -27,8 +27,8 @@ from copr_backend.helpers import ( - call_copr_repo, run_cmd, register_build_result, format_evr, - ) - from copr_backend.job import BuildJob --from copr_backend.msgbus import MessageSender --from copr_backend.sign import sign_rpms_in_dir, get_pubkey -+from copr_backend.euler_msgbus import MessageSender -+from copr_backend.sign import new_signer - from copr_backend.sshcmd import SSHConnection, SSHConnectionError - from copr_backend.vm_alloc import ResallocHostFactory - -@@ -622,7 +622,7 @@ class BuildBackgroundWorker(BackendBackgroundWorker): - self.log.info("Going to sign pkgs from source: %s in chroot: %s", - self.job.task_id, self.job.chroot_dir) - -- sign_rpms_in_dir( -+ self.signer.sign_rpms_in_dir( - self.job.project_owner, - self.job.project_name, - os.path.join(self.job.chroot_dir, self.job.target_dir_name), -@@ -736,7 +736,7 @@ class BuildBackgroundWorker(BackendBackgroundWorker): - # TODO: uncomment this when key revoke/change will be implemented - # if os.path.exists(pubkey_path): - # return -- get_pubkey(user, project, self.log, self.opts.sign_domain, pubkey_path) -+ self.signer.get_pubkey(user, project, self.log, self.opts.sign_domain, pubkey_path) - self.log.info("Added pubkey for user %s project %s into: %s", - user, project, pubkey_path) - diff --git a/copr_backend/constants.py b/backend/copr_backend/constants.py index a529be28a..83bcb8fbe 100644 --- a/copr_backend/constants.py @@ -171,15 +58,35 @@ index 75fa5e62d..291228912 100644 for group_id in range(opts.build_groups_count): archs = _get_conf(cp, "backend", diff --git a/copr_backend/sign.py b/backend/copr_backend/sign.py -index e21653e78..95f674255 100644 +index e21653e78..599d209ee 100644 --- a/copr_backend/sign.py +++ b/copr_backend/sign.py -@@ -25,78 +25,6 @@ def create_gpg_email(username, projectname, domain): +@@ -7,17 +7,16 @@ Wrapper for /bin/sign from obs-sign package + from subprocess import Popen, PIPE, SubprocessError + import os + import time ++import functools + + from packaging import version + + from copr_common.request import SafeRequest +-from copr_backend.helpers import get_redis_logger ++from copr_backend.helpers import get_redis_logger, get_backend_opts + from .exceptions import CoprSignError, CoprSignNoKeyError, \ + CoprKeygenRequestError + + +-SIGN_BINARY = "/bin/sign" +- + def create_gpg_email(username, projectname, domain): + """ + Creates canonical name_email to identify gpg key +@@ -25,77 +24,17 @@ def create_gpg_email(username, projectname, domain): return "{}#{}@copr.{}".format(username, projectname, domain) - --def call_sign_bin(cmd, log): + def call_sign_bin(cmd, log): - """ - Call /bin/sign and return (rc, stdout, stderr). Re-try the call - automatically upon certain failures (if that makes sense). @@ -204,8 +111,10 @@ index e21653e78..95f674255 100644 - break - return handle.returncode, stdout, stderr - -- --def get_pubkey(username, projectname, log, sign_domain, outfile=None): ++ signer = new_signer() ++ return signer.call_sign_bin(cmd, log) + + def get_pubkey(username, projectname, log, sign_domain, outfile=None): - """ - Retrieves public key for user/project from signer host. - @@ -238,8 +147,10 @@ index e21653e78..95f674255 100644 - - return stdout - -- --def _sign_one(path, email, hashtype, log): ++ signer = new_signer() ++ return signer.get_pubkey(username, projectname, log, sign_domain, outfile) + + def _sign_one(path, email, hashtype, log): - cmd = [SIGN_BINARY, "-4", "-h", hashtype, "-u", email, "-r", path] - returncode, stdout, stderr = call_sign_bin(cmd, log) - if returncode != 0: @@ -249,67 +160,88 @@ index e21653e78..95f674255 100644 - cmd=cmd, stdout=stdout, stderr=stderr) - return stdout, stderr - -- ++ signer = new_signer() ++ return signer._sign_one(path, email, hashtype, log) + def gpg_hashtype_for_chroot(chroot, opts): """ - Given the chroot name (in "mock format", like "fedora-rawhide-x86_64") -@@ -136,133 +64,436 @@ def gpg_hashtype_for_chroot(chroot, opts): +@@ -135,134 +74,455 @@ def gpg_hashtype_for_chroot(chroot, opts): + # fallback to sha256 return "sha256" - --def sign_rpms_in_dir(username, projectname, path, chroot, opts, log): +- + def sign_rpms_in_dir(username, projectname, path, chroot, opts, log): - """ - Signs rpms using obs-signd. ++ signer = new_signer() ++ return signer.sign_rpms_in_dir(username, projectname, path, chroot, opts, log) + +- If some some pkgs failed to sign, entire build marked as failed, +- but we continue to try sign other pkgs. +- +- :param username: copr username +- :param projectname: copr projectname +- :param path: directory with rpms to be signed +- :param chroot: chroot name where we sign packages, affects the hash type +- :param Munch opts: backend config ++def create_user_keys(username, projectname, opts, try_indefinitely=False): ++ signer = new_signer() ++ return signer.create_user_keys(username, projectname, opts, try_indefinitely) + +- :type log: logging.Logger ++def _unsign_one(path): ++ signer = new_signer() ++ return signer._unsign_one(path) + +- :raises: :py:class:`backend.exceptions.CoprSignError` failed to sign at least one package +- """ ++def unsign_rpms_in_dir(path, opts, log): ++ signer = new_signer() ++ return signer.unsign_rpms_in_dir(path, opts, log) ++ ++ +# a sign interface +class Signer(object): + @classmethod + def get_pubkey(cls, username, projectname, log, sign_domain, outfile=None): + """get public key""" + raise NotImplementedError - -- If some some pkgs failed to sign, entire build marked as failed, -- but we continue to try sign other pkgs. ++ + @classmethod + def sign_rpms_in_dir(cls, username, projectname, path, chroot, opts, log): + """batch sign rpms""" + raise NotImplementedError - -- :param username: copr username -- :param projectname: copr projectname -- :param path: directory with rpms to be signed -- :param chroot: chroot name where we sign packages, affects the hash type -- :param Munch opts: backend config ++ + @classmethod + def create_user_keys(username, projectname, opts, try_indefinitely=False): + """create user key pair""" + raise NotImplementedError - -- :type log: logging.Logger ++ + @classmethod + def _sign_one(cls, path, email, hashtype, log): + """sign one rpm""" + raise NotImplementedError - -- :raises: :py:class:`backend.exceptions.CoprSignError` failed to sign at least one package -- """ ++ + @classmethod + def _unsign_one(cls, path): + # Requires rpm-sign package + cmd = ["/usr/bin/rpm", "--delsign", path] + handle = Popen(cmd, stdout=PIPE, stderr=PIPE, encoding="utf-8") + stdout, stderr = handle.communicate() -+ -+ if handle.returncode != 0: -+ err = CoprSignError( -+ msg="Failed to unsign {}".format(path), -+ return_code=handle.returncode, -+ cmd=cmd, stdout=stdout, stderr=stderr) - rpm_list = [ - os.path.join(path, filename) - for filename in os.listdir(path) - if filename.endswith(".rpm") - ] ++ if handle.returncode != 0: ++ err = CoprSignError( ++ msg="Failed to unsign {}".format(path), ++ return_code=handle.returncode, ++ cmd=cmd, stdout=stdout, stderr=stderr) + +- if not rpm_list: +- return + raise err + + return stdout, stderr @@ -364,19 +296,35 @@ index e21653e78..95f674255 100644 + if filename.endswith(".rpm") + ] -- if not rpm_list: -- return +- hashtype = gpg_hashtype_for_chroot(chroot, opts) + if not rpm_list: + return -- hashtype = gpg_hashtype_for_chroot(chroot, opts) -+ hashtype = gpg_hashtype_for_chroot(chroot, opts) - - try: - get_pubkey(username, projectname, log, opts.sign_domain) - except CoprSignNoKeyError: - create_user_keys(username, projectname, opts, try_indefinitely=True) -+ try: ++ hashtype = gpg_hashtype_for_chroot(chroot, opts) + +- errors = [] # tuples (rpm_filepath, exception) +- for rpm in rpm_list: + try: +- _sign_one(rpm, create_gpg_email(username, projectname, opts.sign_domain), +- hashtype, log) +- log.info("signed rpm: %s", rpm) +- +- except CoprSignError as e: +- log.exception("failed to sign rpm: %s", rpm) +- errors.append((rpm, e)) +- +- if errors: +- raise CoprSignError("Rpm sign failed, affected rpms: {}" +- .format([err[0] for err in errors])) +- +- +-def create_user_keys(username, projectname, opts, try_indefinitely=False): +- """ +- Generate a new key-pair at sign host + cls.get_pubkey(username, projectname, log, opts.sign_domain) + except CoprSignNoKeyError: + cls.create_user_keys(username, projectname, opts, try_indefinitely=True) @@ -427,8 +375,10 @@ index e21653e78..95f674255 100644 + raise CoprSignError("Rpm unsign failed, affected rpms: {}" + .format([err[0] for err in errors])) + -+def new_signer(opts): -+ if opts.sign_backend == "signatrust": ++@functools.lru_cache(maxsize=1) ++def new_signer(): ++ opts = get_backend_opts() ++ if hasattr(opts, "sign_backend") and opts.sign_backend == "signatrust": + Signatrust.signatrust_token = opts.signatrust_token + Signatrust.signatrust_host = opts.signatrust_host + return Signatrust @@ -466,14 +416,39 @@ index e21653e78..95f674255 100644 + return_code=returncode, + cmd=cmd, stdout=stdout, stderr=stderr) -- errors = [] # tuples (rpm_filepath, exception) -- for rpm in rpm_list: +- :param username: +- :param projectname: +- :param opts: backend config + if outfile: + with open(outfile, "w") as handle: + handle.write(stdout) -+ + +- :return: None +- """ +- data = { +- "name_real": "{}_{}".format(username, projectname), +- "name_email": create_gpg_email(username, projectname, opts.sign_domain) +- } +- +- log = get_redis_logger(opts, "sign", "actions") +- keygen_url = "http://{}/gen_key".format(opts.keygen_host) +- query = dict(url=keygen_url, data=data, method="post") +- try: +- request = SafeRequest(log=log, try_indefinitely=try_indefinitely) +- response = request.send(**query) +- except Exception as e: +- raise CoprKeygenRequestError( +- msg="Failed to create key-pair for user: {}," +- " project:{} with error: {}" +- .format(username, projectname, e), request=query) +- +- if response.status_code >= 400: +- raise CoprKeygenRequestError( +- msg="Failed to create key-pair for user: {}, project:{}, status_code: {}, response: {}" +- .format(username, projectname, response.status_code, response.text), +- request=query, response=response) + return stdout -+ + + @classmethod + def _sign_one(cls, path, email, hashtype, log): + cmd = [cls.sign_cmd, "-4", "-h", hashtype, "-u", email, "-r", path] @@ -574,18 +549,17 @@ index e21653e78..95f674255 100644 + + key_name = cls.get_key_name(username, projectname) + url = "{}/api/v1/keys/{}/public_key".format(cls.signatrust_host, key_name) - try: -- _sign_one(rpm, create_gpg_email(username, projectname, opts.sign_domain), -- hashtype, log) -- log.info("signed rpm: %s", rpm) ++ try: + r = requests.get(url, headers=headers) + except Exception as e: + raise CoprKeygenRequestError( + msg="Failed to get public_key", request="/api/v1/keys/{}/public_key".format(key_name), response=r) -- except CoprSignError as e: -- log.exception("failed to sign rpm: %s", rpm) -- errors.append((rpm, e)) +-def _unsign_one(path): +- # Requires rpm-sign package +- cmd = ["/usr/bin/rpm", "--delsign", path] +- handle = Popen(cmd, stdout=PIPE, stderr=PIPE, encoding="utf-8") +- stdout, stderr = handle.communicate() + if r.status_code == 404: + raise CoprSignNoKeyError( + "There are no gpg keys for user {} in keyring".format(username), @@ -624,9 +598,11 @@ index e21653e78..95f674255 100644 + return_code=returncode, + cmd=cmd, stdout=stdout, stderr=stderr) -- if errors: -- raise CoprSignError("Rpm sign failed, affected rpms: {}" -- .format([err[0] for err in errors])) +- if handle.returncode != 0: +- err = CoprSignError( +- msg="Failed to unsign {}".format(path), +- return_code=handle.returncode, +- cmd=cmd, stdout=stdout, stderr=stderr) + if stderr: + # signatrust client will print error message for one rpm per line + failed_list = re.findall(r"failed to sign file (.*.rpm) due to error", stderr) @@ -645,67 +621,20 @@ index e21653e78..95f674255 100644 + """ + return +- raise err + @classmethod + def _key_existed(cls, username, projectname, opts): + """ + check keyname existence --def create_user_keys(username, projectname, opts, try_indefinitely=False): -- """ -- Generate a new key-pair at sign host +- return stdout, stderr + HEAD /api/v1/keys/ + """ + if not cls.prefix: + cls.get_prefix() -- :param username: -- :param projectname: -- :param opts: backend config + key_name = cls.get_key_name(username, projectname, prefix=False) -- :return: None -- """ -- data = { -- "name_real": "{}_{}".format(username, projectname), -- "name_email": create_gpg_email(username, projectname, opts.sign_domain) -- } -- -- log = get_redis_logger(opts, "sign", "actions") -- keygen_url = "http://{}/gen_key".format(opts.keygen_host) -- query = dict(url=keygen_url, data=data, method="post") -- try: -- request = SafeRequest(log=log, try_indefinitely=try_indefinitely) -- response = request.send(**query) -- except Exception as e: -- raise CoprKeygenRequestError( -- msg="Failed to create key-pair for user: {}," -- " project:{} with error: {}" -- .format(username, projectname, e), request=query) -- -- if response.status_code >= 400: -- raise CoprKeygenRequestError( -- msg="Failed to create key-pair for user: {}, project:{}, status_code: {}, response: {}" -- .format(username, projectname, response.status_code, response.text), -- request=query, response=response) -- -- --def _unsign_one(path): -- # Requires rpm-sign package -- cmd = ["/usr/bin/rpm", "--delsign", path] -- handle = Popen(cmd, stdout=PIPE, stderr=PIPE, encoding="utf-8") -- stdout, stderr = handle.communicate() -- -- if handle.returncode != 0: -- err = CoprSignError( -- msg="Failed to unsign {}".format(path), -- return_code=handle.returncode, -- cmd=cmd, stdout=stdout, stderr=stderr) -- -- raise err -- -- return stdout, stderr -- -- -def unsign_rpms_in_dir(path, opts, log): - """ - :param path: directory with rpms to be signed @@ -800,238 +729,152 @@ index e21653e78..95f674255 100644 + if res.status_code >= 400: + raise CoprKeygenRequestError( + msg="Failed to create user payload: {}".format(data), request="/api/v1/keys/", response=res) -diff --git a/tests/daemons/test_log.py b/backend/tests/daemons/test_log.py -index 73b1a777a..c68b7d918 100644 ---- a/tests/daemons/test_log.py -+++ b/tests/daemons/test_log.py -@@ -45,7 +45,8 @@ class TestLog(object): - self.log_file = os.path.join(self.log_dir, "copr.log") - self.opts = Munch( - verbose=False, -- log_dir=self.log_dir -+ log_dir=self.log_dir, -+ sign_backend = "obs-signd" - ) - print("\n log dir: {}".format(self.log_dir)) - self.queue = MagicMock() -diff --git a/tests/daemons/unused_test_job_grab.py b/backend/tests/daemons/unused_test_job_grab.py -index be3e64c56..79f6472b7 100644 ---- a/tests/daemons/unused_test_job_grab.py -+++ b/tests/daemons/unused_test_job_grab.py -@@ -87,6 +87,7 @@ class TestJobGrab(object): - redis_host="127.0.0.1", - redis_port=6379, - redis_db=0, -+ sign_backend = "obs-signd" - ) - - self.queue = MagicMock() -diff --git a/tests/run/test_copr_prune_results.py b/backend/tests/run/test_copr_prune_results.py -index 6620f01b1..8c9ef2369 100644 ---- a/tests/run/test_copr_prune_results.py -+++ b/tests/run/test_copr_prune_results.py -@@ -59,7 +59,8 @@ class TestPruneResults(object): - self.opts = Munch( - prune_days=14, - frontend_base_url = '<frontend_url>', -- destdir=self.testresults_dir -+ destdir=self.testresults_dir, -+ sign_backend = "obs-signd" - ) - - def teardown_method(self, method): -diff --git a/tests/test_action.py b/backend/tests/test_action.py -index 7da3ab09c..4c935eb53 100644 ---- a/tests/test_action.py -+++ b/tests/test_action.py -@@ -57,6 +57,7 @@ class TestAction(object): - results_baseurl=RESULTS_ROOT_URL, - - do_sign=False, -+ sign_backend = "obs-signd", - - keygen_host="example.com" - ) -@@ -136,7 +137,7 @@ class TestAction(object): - @mock.patch("copr_backend.actions.os.makedirs") - @mock.patch("copr_backend.actions.copy_tree") - @mock.patch("copr_backend.actions.os.path.exists") -- @mock.patch("copr_backend.actions.unsign_rpms_in_dir") -+ @mock.patch("copr_backend.sign.ObsSign.unsign_rpms_in_dir") - @mock.patch("copr_backend.helpers.subprocess.Popen") - def test_action_handle_forks(self, mc_popen, mc_unsign_rpms_in_dir, - mc_exists, mc_copy_tree, _mc_os_makedirs, diff --git a/tests/test_background_worker_build.py b/backend/tests/test_background_worker_build.py -index 1dfe19563..258564067 100644 +index 1dfe19563..ba1e5aeab 100644 --- a/tests/test_background_worker_build.py +++ b/tests/test_background_worker_build.py -@@ -77,6 +77,7 @@ def _reset_build_worker(): - # Don't waste time with mocking. We don't want to log anywhere, and we want - # to let BuildBackgroundWorker adjust the handlers. - worker.log.handlers = [] -+ worker.opts.sign_backend = "obs-signd" - return worker - - def _fake_host(): -diff --git a/tests/test_frontend.py b/backend/tests/test_frontend.py -index eeb8dc8f4..06a6e605b 100644 ---- a/tests/test_frontend.py -+++ b/tests/test_frontend.py -@@ -48,6 +48,7 @@ class TestFrontendClient(object): - self.opts = Munch( - frontend_base_url="http://example.com/", - frontend_auth="12345678", -+ sign_backend = "obs-signd" - ) - self.fc = FrontendClient(self.opts) - -diff --git a/tests/test_helpers.py b/backend/tests/test_helpers.py -index 8da70269d..e23565054 100644 ---- a/tests/test_helpers.py -+++ b/tests/test_helpers.py -@@ -31,6 +31,7 @@ class TestHelpers(object): - self.opts = Munch( - redis_db=9, - redis_port=7777, -+ sign_backend = "obs-signd" - ) - - self.rc = get_redis_connection(self.opts) +@@ -88,6 +88,12 @@ def _fake_host(): + host.release = mock.MagicMock() + return host + ++@pytest.fixture(autouse=True) ++def get_opts(): ++ with pytest.MonkeyPatch.context() as mp: ++ mp.setattr("copr_backend.sign.get_backend_opts", lambda: None) ++ yield mp ++ + @pytest.fixture + def f_build_something(): + """ +@@ -324,8 +330,8 @@ def test_full_srpm_build(f_build_srpm): + "00855954/hello-2.8-1.src.rpm") + + +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") +-@mock.patch("copr_backend.sign._sign_one") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign._sign_one") + def test_build_and_sign(mc_sign_one, f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -351,7 +357,7 @@ def test_build_and_sign(mc_sign_one, f_build_rpm_sign_on, caplog): + _, level, _ = record + assert level <= logging.INFO + +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + @mock.patch("copr_backend.sign._sign_one") + @_patch_bwbuild_object("sign_rpms_in_dir") + def test_sign_built_packages_exception(mc_sign_rpms, mc_sign_one, +@@ -452,7 +458,7 @@ def test_invalid_job_info(f_build_rpm_case, caplog): + + @mock.patch("copr_backend.vm_alloc.time.sleep", mock.MagicMock()) + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_build_on_vm_allocation(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -513,7 +519,7 @@ class _CancelFunction(): + time.sleep(0.25) + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_build_on_tail_log_no_ssh(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -542,7 +548,7 @@ def test_cancel_build_on_tail_log_no_ssh(f_build_rpm_sign_on, caplog): + assert "canceled stdout" in log + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_before_vm(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -558,7 +564,7 @@ def test_cancel_before_vm(f_build_rpm_sign_on, caplog): + assert_logs_dont_exist(["Releasing VM back to pool"], caplog) + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_before_start(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -578,7 +584,7 @@ def test_cancel_before_start(f_build_rpm_sign_on, caplog): + ], caplog) + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_build_retry(f_build_rpm_sign_on): + config = f_build_rpm_sign_on + worker = config.bw +@@ -650,7 +656,7 @@ def test_fe_failed_start(f_build_rpm_sign_on, caplog): + assert worker.redis_get_worker_flag("status") == "done" + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_script_failure(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw +@@ -672,7 +678,7 @@ def test_cancel_script_failure(f_build_rpm_sign_on, caplog): + ], caplog) + + @_patch_bwbuild_object("CANCEL_CHECK_PERIOD", 0.5) +-@mock.patch("copr_backend.sign.SIGN_BINARY", "tests/fake-bin-sign") ++@mock.patch("copr_backend.sign.ObsSign.sign_cmd", "tests/fake-bin-sign") + def test_cancel_build_during_log_download(f_build_rpm_sign_on, caplog): + config = f_build_rpm_sign_on + worker = config.bw diff --git a/tests/test_sign.py b/backend/tests/test_sign.py -index bf2dd1b8c..ebb8f2be3 100644 +index bf2dd1b8c..13a7a2ebc 100644 --- a/tests/test_sign.py +++ b/tests/test_sign.py -@@ -10,10 +10,10 @@ import pytest - - from copr_backend.exceptions import CoprSignError, CoprSignNoKeyError, CoprKeygenRequestError +@@ -12,13 +12,16 @@ from copr_backend.exceptions import CoprSignError, CoprSignNoKeyError, CoprKeyge from copr_backend.sign import ( -- get_pubkey, _sign_one, sign_rpms_in_dir, create_user_keys, -+ new_signer, + get_pubkey, _sign_one, sign_rpms_in_dir, create_user_keys, gpg_hashtype_for_chroot, - call_sign_bin, ++ call_sign_bin ) -+from copr_backend.constants import DEF_SIGN_BACKEND ++from copr_backend import helpers STDOUT = "stdout" STDERR = "stderr" -@@ -33,6 +33,8 @@ class TestSign(object): - self.opts = Munch(keygen_host="example.com") - self.opts.gently_gpg_sha256 = False - self.opts.sign_domain = "fedorahosted.org" -+ self.opts.sign_backend = DEF_SIGN_BACKEND -+ self.signer = new_signer(self.opts) - - def teardown_method(self, method): - if self.tmp_dir_path: -@@ -60,7 +62,7 @@ class TestSign(object): - mc_handle.returncode = 0 - mc_popen.return_value = mc_handle - -- result = get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) -+ result = self.signer.get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) - assert result == STDOUT - assert mc_popen.call_args[0][0] == ['/bin/sign', '-u', self.usermail, '-p'] - -@@ -70,7 +72,7 @@ class TestSign(object): - mc_popen.side_effect = IOError(STDERR) - - with pytest.raises(CoprSignError): -- get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) -+ self.signer.get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) - - - @mock.patch("copr_backend.sign.time.sleep") -@@ -82,7 +84,7 @@ class TestSign(object): - mc_popen.return_value = mc_handle - - with pytest.raises(CoprSignNoKeyError) as err: -- get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) -+ self.signer.get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) - - assert "There are no gpg keys for user foo in keyring" in str(err) - -@@ -95,7 +97,7 @@ class TestSign(object): - mc_popen.return_value = mc_handle - - with pytest.raises(CoprSignError) as err: -- get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) -+ self.signer.get_pubkey(self.username, self.projectname, MagicMock(), self.opts.sign_domain) - - assert "Failed to get user pubkey" in str(err) - -@@ -108,7 +110,7 @@ class TestSign(object): - outfile_path = os.path.join(self.tmp_dir_path, "out.pub") - assert not os.path.exists(outfile_path) -- result = get_pubkey(self.username, self.projectname, MagicMock(), -+ result = self.signer.get_pubkey(self.username, self.projectname, MagicMock(), - self.opts.sign_domain, outfile_path) - assert result == STDOUT - assert os.path.exists(outfile_path) -@@ -124,7 +126,7 @@ class TestSign(object): - mc_popen.return_value = mc_handle - fake_path = "/tmp/pkg.rpm" -- result = _sign_one(fake_path, self.usermail, "sha1", MagicMock()) -+ result = self.signer._sign_one(fake_path, self.usermail, "sha1", MagicMock()) - assert STDOUT, STDERR == result - - expected_cmd = ['/bin/sign', "-4", "-h", "sha1", "-u", self.usermail, -@@ -137,7 +139,7 @@ class TestSign(object): - - fake_path = "/tmp/pkg.rpm" - with pytest.raises(CoprSignError): -- _sign_one(fake_path, self.usermail, "sha256", MagicMock()) -+ self.signer._sign_one(fake_path, self.usermail, "sha256", MagicMock()) ++ ++ + class TestSign(object): + # pylint: disable=too-many-public-methods - @mock.patch("copr_backend.sign.time.sleep") - @mock.patch("copr_backend.sign.Popen") -@@ -149,12 +151,11 @@ class TestSign(object): +@@ -38,6 +41,12 @@ class TestSign(object): + if self.tmp_dir_path: + shutil.rmtree(self.tmp_dir_path) - fake_path = "/tmp/pkg.rpm" - with pytest.raises(CoprSignError): -- _sign_one(fake_path, self.usermail, "sha256", MagicMock()) -+ self.signer._sign_one(fake_path, self.usermail, "sha256", MagicMock()) ++ @pytest.fixture(autouse=True) ++ def get_opts(self): ++ with pytest.MonkeyPatch.context() as mp: ++ mp.setattr("copr_backend.sign.get_backend_opts", lambda: None) ++ yield mp ++ + @pytest.fixture + def tmp_dir(self): + subdir = "test_createrepo_{}".format(time.time()) +@@ -54,7 +63,7 @@ class TestSign(object): + handle.write("1") -- @staticmethod - @mock.patch("copr_backend.sign.time.sleep") @mock.patch("copr_backend.sign.Popen") -- def test_call_sign_bin_repeatedly(mc_popen, _sleep): -+ def test_call_sign_bin_repeatedly(self, mc_popen, _sleep): - """ - Test that we attempt to run /bin/sign multiple times if it returns - non-zero exit status -@@ -163,13 +164,13 @@ class TestSign(object): +- def test_get_pubkey(self, mc_popen): ++ def test_get_pubkey(self, mc_popen, get_opts): + mc_handle = MagicMock() mc_handle.communicate.return_value = (STDOUT, STDERR) - mc_handle.returncode = 1 - mc_popen.return_value = mc_handle -- call_sign_bin(cmd=[], log=MagicMock()) -+ self.signer.call_sign_bin(cmd=[], log=MagicMock()) - assert mc_popen.call_count == 3 - - @mock.patch("copr_backend.sign.SafeRequest.send") - def test_create_user_keys(self, mc_request): - mc_request.return_value.status_code = 200 -- create_user_keys(self.username, self.projectname, self.opts) -+ self.signer.create_user_keys(self.username, self.projectname, self.opts) - - assert mc_request.called - expected_call = mock.call( -@@ -183,7 +184,7 @@ class TestSign(object): - def test_create_user_keys_error_1(self, mc_request): - mc_request.side_effect = IOError() - with pytest.raises(CoprKeygenRequestError) as err: -- create_user_keys(self.username, self.projectname, self.opts) -+ self.signer.create_user_keys(self.username, self.projectname, self.opts) - - assert "Failed to create key-pair" in str(err) - -@@ -195,16 +196,16 @@ class TestSign(object): - mc_request.return_value.content = "error: {}".format(code) - - with pytest.raises(CoprKeygenRequestError) as err: -- create_user_keys(self.username, self.projectname, self.opts) -+ self.signer.create_user_keys(self.username, self.projectname, self.opts) + mc_handle.returncode = 0 +@@ -198,9 +207,9 @@ class TestSign(object): + create_user_keys(self.username, self.projectname, self.opts) assert "Failed to create key-pair for user: foo, project:bar" in str(err) - @mock.patch("copr_backend.sign._sign_one") @@ -1043,12 +886,7 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_nothing(self, mc_gp, mc_cuk, mc_so, tmp_dir): # empty target dir doesn't produce error -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "epel-8-x86_64", self.opts, - log=MagicMock()) - -@@ -212,13 +213,13 @@ class TestSign(object): +@@ -212,9 +221,9 @@ class TestSign(object): assert not mc_cuk.called assert not mc_so.called @@ -1061,12 +899,7 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_ok(self, mc_gp, mc_cuk, mc_so, tmp_dir, tmp_files): -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "fedora-rawhide-x86_64", - self.opts, log=MagicMock()) - -@@ -234,15 +235,15 @@ class TestSign(object): +@@ -234,9 +243,9 @@ class TestSign(object): assert os.path.join(self.tmp_dir_path, name) in pathes assert len(pathes) == count @@ -1079,14 +912,7 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_error_on_pubkey( self, mc_gp, mc_cuk, mc_so, tmp_dir, tmp_files): - mc_gp.side_effect = CoprSignError("foobar") - with pytest.raises(CoprSignError): -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "epel-7-x86_64", self.opts, - log=MagicMock()) - -@@ -250,15 +251,15 @@ class TestSign(object): +@@ -250,9 +259,9 @@ class TestSign(object): assert not mc_cuk.called assert not mc_so.called @@ -1099,14 +925,7 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_no_pub_key( self, mc_gp, mc_cuk, mc_so, tmp_dir, tmp_files): - mc_gp.side_effect = CoprSignNoKeyError("foobar") - -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "rhel-7-x86_64", self.opts, - log=MagicMock()) - -@@ -266,9 +267,9 @@ class TestSign(object): +@@ -266,9 +275,9 @@ class TestSign(object): assert mc_cuk.called assert mc_so.called @@ -1119,16 +938,7 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_sign_error_one( self, mc_gp, mc_cuk, mc_so, tmp_dir, tmp_files): -@@ -276,7 +277,7 @@ class TestSign(object): - None, CoprSignError("foobar"), None - ] - with pytest.raises(CoprSignError): -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "fedora-36-x86_64", self.opts, - log=MagicMock()) - -@@ -285,15 +286,15 @@ class TestSign(object): +@@ -285,9 +294,9 @@ class TestSign(object): assert mc_so.called @@ -1141,10 +951,3 @@ index bf2dd1b8c..ebb8f2be3 100644 def test_sign_rpms_id_dir_sign_error_all( self, mc_gp, mc_cuk, mc_so, tmp_dir, tmp_files): - mc_so.side_effect = CoprSignError("foobar") - with pytest.raises(CoprSignError): -- sign_rpms_in_dir(self.username, self.projectname, -+ self.signer.sign_rpms_in_dir(self.username, self.projectname, - self.tmp_dir_path, "fedora-36-i386", self.opts, - log=MagicMock()) - |