From 04c61c4505bbcc846031221530fa080ab711b94e Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Jun 01 2017 14:28:01 +0000 Subject: [PATCH 1/2] Errata class and builds_signed(...) method --- diff --git a/freshmaker/errata.py b/freshmaker/errata.py new file mode 100644 index 0000000..5c8df7f --- /dev/null +++ b/freshmaker/errata.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017 Red Hat, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Written by Jan Kaluza + +import requests +from requests_kerberos import HTTPKerberosAuth + +from freshmaker.events import BrewRPMSignEvent + + +class ErrataAdvisory(object): + """ + Represents Errata advisory. + """ + + def __init__(self, errata_id, name, state): + """ + Initializes the ErrataAdvisory instance. + """ + self.errata_id = errata_id + self.name = name + self.state = state + + +class Errata(object): + """ Interface to Errata. """ + + def __init__(self, server_url): + """ + Initializes the Errata instance. + + :param str server_url: Base URL of Errata server. + """ + self.server_url = server_url.rstrip('/') + + def _errata_get(self, endpoint): + r = requests.get("%s/%s" % (self.server_url, endpoint), + auth=HTTPKerberosAuth()) + r.raise_for_status() + return r.json() + + def advisories_from_event(self, event): + """ + Returns list of ErrataAdvisory instances associated with + the Freshmaker Event. + + :param BaseEvent event: Event from which the errata ID should be + returned. Following events are supported: + - BrewRPMSignEvent + :raises ValueError: if unsupported BaseEvent subclass is passed + :return: List of ErrataAdvisory instances + :rtype: list + """ + if isinstance(event, BrewRPMSignEvent): + build = self._errata_get("api/v1/build/%s" % str(event.nvr)) + if "all_errata" not in build: + return [] + return [ + ErrataAdvisory(errata["id"], errata["name"], errata["status"]) + for errata in build["all_errata"]] + else: + raise ValueError("Unsupported event type") + + def builds_signed(self, errata_id): + """ + Returns True if all builds in the advisory are signed. + :param str or int errata_id: Errata advisory ID to check. + :return: True if all builds in advisory are signed. + :rtype: bool + """ + builds_per_product = self._errata_get( + "advisory/%s/builds.json" % str(errata_id)) + + # Store NVRs of all builds in advisory to nvrs set. + nvrs = set() + for builds in builds_per_product.values(): + for build in builds: + nvrs.update(set(build.keys())) + + # For each NVR, check that all the rpms are signed. + for nvr in nvrs: + build = self._errata_get("api/v1/build/%s" % str(nvr)) + if "rpms_signed" not in build or not build["rpms_signed"]: + return False + + return True diff --git a/freshmaker/events.py b/freshmaker/events.py index 7fd9a48..39ee370 100644 --- a/freshmaker/events.py +++ b/freshmaker/events.py @@ -219,3 +219,12 @@ class KojiTaskStateChangeEvent(BaseEvent): super(KojiTaskStateChangeEvent, self).__init__(msg_id) self.task_id = task_id self.task_state = task_state + + +class BrewRPMSignEvent(BaseEvent): + """ + Represents the message sent by Brew when RPM is signed. + """ + def __init__(self, msg_id, nvr): + super(BrewRPMSignEvent, self).__init__(msg_id) + self.nvr = nvr diff --git a/tests/test_errata.py b/tests/test_errata.py new file mode 100644 index 0000000..0f7aeaf --- /dev/null +++ b/tests/test_errata.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017 Red Hat, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import unittest + +from mock import patch + +from freshmaker.errata import Errata +from freshmaker.events import BrewRPMSignEvent, GitRPMSpecChangeEvent + + +class MockedErrataAPI(object): + """ + Class mocking methods accessing Errata API in Errata class. + """ + def __init__(self, errata_get): + errata_get.side_effect = (self.errata_get) + + self.builds_json = { + "PRODUCT1": [ + { + "libntirpc-1.4.3-4.el6rhs": + { + "PRODUCT1-3.2-NFS": + {"x86_64": ["libntirpc-devel-1.4.3-4.el6rhs.x86_64.rpm"], + "SRPMS": ["libntirpc-1.4.3-4.el6rhs.src.rpm"]} + } + } + ], + "PRODUCT2": [ + { + "libntirpc-1.4.3-4.el7rhgs": + { + "PRODUCT2-3.2-NFS": + {"x86_64": ["libntirpc-devel-1.4.3-4.el7rhgs.x86_64.rpm"], + "SRPMS": ["libntirpc-1.4.3-4.el7rhgs.src.rpm"]} + } + } + ] + } + + self.builds = {} + self.builds["libntirpc-1.4.3-4.el6rhs"] = { + "all_errata": [{"id": 28484, "name": "RHSA-2017:28484", "status": "QE"}], + "rpms_signed": True} + self.builds["libntirpc-1.4.3-4.el7rhgs"] = { + "all_errata": [{"id": 28484, "name": "RHSA-2017:28484", "status": "QE"}], + "rpms_signed": True} + + def errata_get(self, endpoint): + if endpoint.endswith("builds.json"): + return self.builds_json + elif endpoint.find("api/v1/build/") != -1: + nvr = endpoint.split("/")[-1] + return self.builds[nvr] + + +class TestErrata(unittest.TestCase): + def setUp(self): + self.errata = Errata("https://localhost/") + + @patch.object(Errata, "_errata_get") + def test_advisories_from_event(self, errata_get): + MockedErrataAPI(errata_get) + event = BrewRPMSignEvent("msgid", "libntirpc-1.4.3-4.el7rhgs") + advisories = self.errata.advisories_from_event(event) + self.assertEqual(len(advisories), 1) + self.assertEqual(advisories[0].errata_id, 28484) + + @patch.object(Errata, "_errata_get") + def test_advisories_from_event_missing_all_errata(self, errata_get): + mocked_errata = MockedErrataAPI(errata_get) + del mocked_errata.builds["libntirpc-1.4.3-4.el7rhgs"]["all_errata"] + + event = BrewRPMSignEvent("msgid", "libntirpc-1.4.3-4.el7rhgs") + advisories = self.errata.advisories_from_event(event) + self.assertEqual(len(advisories), 0) + + def test_advisories_from_event_unsupported_event(self): + event = GitRPMSpecChangeEvent("msgid", "libntirpc", "master", "foo") + with self.assertRaises(ValueError): + self.errata.advisories_from_event(event) + + @patch.object(Errata, "_errata_get") + def test_builds_signed_all_signed(self, errata_get): + MockedErrataAPI(errata_get) + self.assertTrue(self.errata.builds_signed(28484)) + + @patch.object(Errata, "_errata_get") + def test_builds_signed_some_unsigned(self, errata_get): + mocked_errata = MockedErrataAPI(errata_get) + mocked_errata.builds["libntirpc-1.4.3-4.el7rhgs"]["rpms_signed"] = False + self.assertFalse(self.errata.builds_signed(28484)) + + @patch.object(Errata, "_errata_get") + def test_builds_signed_missing_data(self, errata_get): + mocked_errata = MockedErrataAPI(errata_get) + mocked_errata.builds["libntirpc-1.4.3-4.el7rhgs"] = {} + self.assertFalse(self.errata.builds_signed(28484)) diff --git a/tox.ini b/tox.ini index 0868b04..689286d 100644 --- a/tox.ini +++ b/tox.ini @@ -27,7 +27,7 @@ commands = basepython = python3 skip_install = true deps = flake8 -commands = flake8 --ignore E501,E731 --exclude freshmaker/migrations/*,.tox/* +commands = flake8 --ignore E501,E731 --exclude freshmaker/migrations/*,.tox/*,build/* [testenv:bandit] basepython = python3 From aa731dd257018ced3b4bacdce020f1c2d4425318 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Jun 01 2017 14:32:57 +0000 Subject: [PATCH 2/2] Fix flake8 tests for lightblue classes --- diff --git a/freshmaker/lightblue.py b/freshmaker/lightblue.py index c2c4731..764cb45 100644 --- a/freshmaker/lightblue.py +++ b/freshmaker/lightblue.py @@ -258,7 +258,6 @@ class LightBlue(object): } return self.find_container_repositories(repo_request) - def find_images_with_included_srpm(self, repositories, srpm_name, published=True): @@ -313,12 +312,9 @@ class LightBlue(object): } return self.find_container_images(image_request) - - def find_images_with_package_from_content_set(self, srpm_name, - content_sets, - published=True, - deprecated=False, - release_category="Generally Available"): + def find_images_with_package_from_content_set( + self, srpm_name, content_sets, published=True, deprecated=False, + release_category="Generally Available"): """Query lightblue and find containers which contain given package from one of content sets @@ -357,7 +353,7 @@ class LightBlue(object): dockerfile, _, commit = dockerfile_url.partition("?id=") _, _, reponame = dockerfile.partition("/cgit/") - reponame = reponame.replace("/plain/Dockerfile","") + reponame = reponame.replace("/plain/Dockerfile", "") commits.append({"repository": reponame, "commit": commit, "srpm_nevra": srpm_nevra}) diff --git a/tests/test_lightblue.py b/tests/test_lightblue.py index 70c44cd..11dce78 100644 --- a/tests/test_lightblue.py +++ b/tests/test_lightblue.py @@ -23,7 +23,7 @@ import json import unittest -from mock import call, patch, Mock +from mock import call, patch from six.moves import http_client from freshmaker.lightblue import ContainerImage @@ -450,7 +450,6 @@ class TestQueryEntityFromLightBlue(unittest.TestCase): cont_images.assert_called_with(expected_image_request) self.assertEqual(ret, cont_images.return_value) - @patch('freshmaker.lightblue.LightBlue.find_container_repositories') @patch('freshmaker.lightblue.LightBlue.find_container_images') @patch('os.path.exists') @@ -468,7 +467,7 @@ class TestQueryEntityFromLightBlue(unittest.TestCase): ret = lb.find_images_with_package_from_content_set("openssl", ["dummy-content-set-1"]) - self.assertEqual(2,len(ret)) + self.assertEqual(2, len(ret)) self.assertEqual(ret, [ { @@ -513,7 +512,6 @@ class TestQueryEntityFromLightBlue(unittest.TestCase): ["dummy-content-set-1"]) - class TestEntityVersion(unittest.TestCase): """Test case for ensuring correct entity version in request"""