From e6c48fb00b96c525616d0942e44a6acfc8521acd Mon Sep 17 00:00:00 2001 From: Lubomir Gallovic Date: Tue, 19 Sep 2023 15:19:20 +0200 Subject: [PATCH 1/2] Allow Errata HTTP client to work without Kerberos credentials If credentials are not specified, the HTTP method returns None without querying the endpoint. This change was made because the Errata Kerberos credentials are not yet prepared and the gathered information is not yet necessary. This unusual feature should be removed in the future. --- .../backend/errata_source/errata_http_client.py | 10 ++++++++++ .../_impl/backend/errata_source/errata_source.py | 9 ++++++--- tests/baseline/test_baseline.py | 12 ++++++++++++ tests/errata/test_errata_http_client.py | 11 +++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/pushsource/_impl/backend/errata_source/errata_http_client.py b/src/pushsource/_impl/backend/errata_source/errata_http_client.py index d7db4718..a4c2badd 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_http_client.py +++ b/src/pushsource/_impl/backend/errata_source/errata_http_client.py @@ -5,6 +5,7 @@ import logging import tempfile from urllib.parse import urljoin +from functools import wraps import requests import gssapi @@ -12,6 +13,14 @@ LOG = logging.getLogger("pushsource.errata_http_client") +def return_none_if_unauthenticated(func): + @wraps(func) + def wrapper_return_none_if_unauthenticated(self, *args, **kwargs): + if not self.keytab_path or not self.principal: + return None + return func(self, *args, **kwargs) + + return wrapper_return_none_if_unauthenticated class ErrataHTTPClient: """Class for performing HTTP API queries with Errata.""" @@ -123,6 +132,7 @@ def session(self) -> requests.Session: return self._thread_local.session + @return_none_if_unauthenticated def get_advisory_data(self, advisory: str) -> dict: """ Get advisory data. diff --git a/src/pushsource/_impl/backend/errata_source/errata_source.py b/src/pushsource/_impl/backend/errata_source/errata_source.py index ab282762..2797549c 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_source.py +++ b/src/pushsource/_impl/backend/errata_source/errata_source.py @@ -239,9 +239,12 @@ def _push_items_from_container_manifests(self, erratum, docker_file_list): # Get product name from Errata. Enrich Container push items with this info advisory_data = self._http_client.get_advisory_data(erratum.name) - # This dictionary key is different based on erratum type - erratum_type = list(advisory_data["errata"].keys())[0] - product_name = advisory_data["errata"][erratum_type]["product"]["name"] + if advisory_data: + # This dictionary key is different based on erratum type + erratum_type = list(advisory_data["errata"].keys())[0] + product_name = advisory_data["errata"][erratum_type]["product"]["name"] + else: + product_name = None # We'll be getting container metadata from these builds. with self._koji_source( diff --git a/tests/baseline/test_baseline.py b/tests/baseline/test_baseline.py index 846755be..d165d1ea 100644 --- a/tests/baseline/test_baseline.py +++ b/tests/baseline/test_baseline.py @@ -86,9 +86,21 @@ def koji_test_backend(fake_koji, koji_dir): @pytest.fixture(autouse=True) def fake_kerberos_auth(mocker): + mocker.patch( + "pushsource._impl.backend.errata_source." + "errata_http_client.ErrataHTTPClient.create_kerberos_ticket" + ) mocker.patch("gssapi.Name") mocker.patch("gssapi.Credentials.acquire") mocker.patch("requests_gssapi.HTTPSPNEGOAuth", return_value=None) + with patch.dict( + "os.environ", + { + "PUSHSOURCE_ERRATA_KEYTAB_PATH": "/path/to/keytab", + "PUSHSOURCE_ERRATA_PRINCIPAL": "pub-errata@IPA.REDHAT.COM", + }, + ): + yield @pytest.fixture(autouse=True) diff --git a/tests/errata/test_errata_http_client.py b/tests/errata/test_errata_http_client.py index b2dab997..1aa0708e 100644 --- a/tests/errata/test_errata_http_client.py +++ b/tests/errata/test_errata_http_client.py @@ -243,3 +243,14 @@ def test_get_advisory_data(caplog): "Queried Errata HTTP API for RHSA-123456789", "GET https://errata.example.com/api/v1/erratum/RHSA-123456789 200", ] + + +def test_get_advisory_data_no_credentials(caplog): + caplog.set_level(logging.DEBUG) + + client = ErrataHTTPClient("https://errata.example.com/") + + data = client.get_advisory_data("RHSA-123456789") + + assert data == None + assert caplog.messages == [] From 83a36adc9b8591c21ba48f671ed323bb626e90a5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 13:54:53 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../_impl/backend/errata_source/errata_http_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pushsource/_impl/backend/errata_source/errata_http_client.py b/src/pushsource/_impl/backend/errata_source/errata_http_client.py index a4c2badd..3e2d6976 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_http_client.py +++ b/src/pushsource/_impl/backend/errata_source/errata_http_client.py @@ -13,6 +13,7 @@ LOG = logging.getLogger("pushsource.errata_http_client") + def return_none_if_unauthenticated(func): @wraps(func) def wrapper_return_none_if_unauthenticated(self, *args, **kwargs): @@ -22,6 +23,7 @@ def wrapper_return_none_if_unauthenticated(self, *args, **kwargs): return wrapper_return_none_if_unauthenticated + class ErrataHTTPClient: """Class for performing HTTP API queries with Errata."""