247 lines
11 KiB
Diff
247 lines
11 KiB
Diff
|
From 4968bec73947fb83aeb2d89fe7e919fba2ca2776 Mon Sep 17 00:00:00 2001
|
||
|
From: Petr Stodulka <pstodulk@redhat.com>
|
||
|
Date: Mon, 11 Dec 2023 18:00:40 +0100
|
||
|
Subject: [PATCH 50/60] distributionsignedrpmscanner: refactoring + gpg-pubkey
|
||
|
fix
|
||
|
|
||
|
We have decided to refactor the code in the actor (coming history
|
||
|
time ago) to make it more readable.
|
||
|
|
||
|
Also it's fixing an old issue with gpg-pubkey detection as unsigned
|
||
|
rpm. gpg-pubkey is not a real package and it's just an entry in RPM DB
|
||
|
about the imported RPM GPG keys. Originally it has been checked whether
|
||
|
the packager is vendor/authority of the installed distribution and if
|
||
|
not, such a package (key) has been mared as unsigned.
|
||
|
|
||
|
This led to false positive reports, that we do not know what will
|
||
|
happen with gpg-pubkey packages (reported even multiple times..)
|
||
|
and that they might be removed or do another problems with the upgrade
|
||
|
transaction - which has not been true.
|
||
|
|
||
|
So I dropped the check for the packager and mark gpg-pubkey always
|
||
|
as signed. It's a question whether we should not ignore this package
|
||
|
always and do not put it to any signed/unsigned list. Handling it
|
||
|
in this way for now.
|
||
|
---
|
||
|
.../distributionsignedrpmscanner/actor.py | 94 ++++---------------
|
||
|
.../libraries/distributionsignedrpmscanner.py | 72 ++++++++++++++
|
||
|
.../test_distributionsignedrpmscanner.py | 6 +-
|
||
|
3 files changed, 92 insertions(+), 80 deletions(-)
|
||
|
create mode 100644 repos/system_upgrade/common/actors/distributionsignedrpmscanner/libraries/distributionsignedrpmscanner.py
|
||
|
|
||
|
diff --git a/repos/system_upgrade/common/actors/distributionsignedrpmscanner/actor.py b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/actor.py
|
||
|
index 5772cb25..56016513 100644
|
||
|
--- a/repos/system_upgrade/common/actors/distributionsignedrpmscanner/actor.py
|
||
|
+++ b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/actor.py
|
||
|
@@ -1,11 +1,5 @@
|
||
|
-import json
|
||
|
-import os
|
||
|
-
|
||
|
from leapp.actors import Actor
|
||
|
-from leapp.exceptions import StopActorExecutionError
|
||
|
-from leapp.libraries.common import rhui
|
||
|
-from leapp.libraries.common.config import get_env
|
||
|
-from leapp.libraries.stdlib import api
|
||
|
+from leapp.libraries.actor import distributionsignedrpmscanner
|
||
|
from leapp.models import DistributionSignedRPM, InstalledRedHatSignedRPM, InstalledRPM, InstalledUnsignedRPM
|
||
|
from leapp.tags import FactsPhaseTag, IPUWorkflowTag
|
||
|
from leapp.utils.deprecation import suppress_deprecation
|
||
|
@@ -13,10 +7,22 @@ from leapp.utils.deprecation import suppress_deprecation
|
||
|
|
||
|
@suppress_deprecation(InstalledRedHatSignedRPM)
|
||
|
class DistributionSignedRpmScanner(Actor):
|
||
|
- """Provide data about installed RPM Packages signed by the distribution.
|
||
|
+ """
|
||
|
+ Provide data about distribution signed & unsigned RPM packages.
|
||
|
+
|
||
|
+ For various checks and actions done during the upgrade it's important to
|
||
|
+ know what packages are signed by GPG keys of the installed linux system
|
||
|
+ distribution. RPMs that are not provided in the distribution could have
|
||
|
+ different versions, different behaviour, and also it could be completely
|
||
|
+ different application just with the same RPM name.
|
||
|
+
|
||
|
+ For that reasons, various actors rely on the DistributionSignedRPM message
|
||
|
+ to check whether particular package is installed, to be sure it provides
|
||
|
+ valid data. Fingerprints of distribution GPG keys are stored under
|
||
|
+ common/files/distro/<distro>/gpg_signatures.json
|
||
|
+ where <distro> is distribution ID of the installed system (e.g. centos, rhel).
|
||
|
|
||
|
- After filtering the list of installed RPM packages by signature, a message
|
||
|
- with relevant data will be produced.
|
||
|
+ If the file for the installed distribution is not find, end with error.
|
||
|
"""
|
||
|
|
||
|
name = 'distribution_signed_rpm_scanner'
|
||
|
@@ -25,70 +31,4 @@ class DistributionSignedRpmScanner(Actor):
|
||
|
tags = (IPUWorkflowTag, FactsPhaseTag)
|
||
|
|
||
|
def process(self):
|
||
|
- # TODO(pstodulk): refactor this function
|
||
|
- # - move it to the private library
|
||
|
- # - split it into several functions (so the main function stays small)
|
||
|
- # FIXME(pstodulk): gpg-pubkey is handled wrong; it's not a real package
|
||
|
- # and create FP report about unsigned RPMs. Keeping the fix for later.
|
||
|
- distribution = self.configuration.os_release.release_id
|
||
|
- distributions_path = api.get_common_folder_path('distro')
|
||
|
-
|
||
|
- distribution_config = os.path.join(distributions_path, distribution, 'gpg-signatures.json')
|
||
|
- if os.path.exists(distribution_config):
|
||
|
- with open(distribution_config) as distro_config_file:
|
||
|
- distro_config_json = json.load(distro_config_file)
|
||
|
- distribution_keys = distro_config_json.get('keys', [])
|
||
|
- distribution_packager = distro_config_json.get('packager', 'not-available')
|
||
|
- else:
|
||
|
- raise StopActorExecutionError(
|
||
|
- 'Cannot find distribution signature configuration.',
|
||
|
- details={'Problem': 'Distribution {} was not found in {}.'.format(distribution, distributions_path)})
|
||
|
-
|
||
|
- signed_pkgs = DistributionSignedRPM()
|
||
|
- rh_signed_pkgs = InstalledRedHatSignedRPM()
|
||
|
- unsigned_pkgs = InstalledUnsignedRPM()
|
||
|
-
|
||
|
- all_signed = get_env('LEAPP_DEVEL_RPMS_ALL_SIGNED', '0') == '1'
|
||
|
-
|
||
|
- def has_distributionsig(pkg):
|
||
|
- return any(key in pkg.pgpsig for key in distribution_keys)
|
||
|
-
|
||
|
- def is_gpg_pubkey(pkg):
|
||
|
- """
|
||
|
- Check if gpg-pubkey pkg exists or LEAPP_DEVEL_RPMS_ALL_SIGNED=1
|
||
|
-
|
||
|
- gpg-pubkey is not signed as it would require another package
|
||
|
- to verify its signature
|
||
|
- """
|
||
|
- return ( # pylint: disable-msg=consider-using-ternary
|
||
|
- pkg.name == 'gpg-pubkey'
|
||
|
- and pkg.packager.startswith(distribution_packager)
|
||
|
- or all_signed
|
||
|
- )
|
||
|
-
|
||
|
- def has_katello_prefix(pkg):
|
||
|
- """Whitelist the katello package."""
|
||
|
- return pkg.name.startswith('katello-ca-consumer')
|
||
|
-
|
||
|
- whitelisted_cloud_pkgs = rhui.get_all_known_rhui_pkgs_for_current_upg()
|
||
|
-
|
||
|
- for rpm_pkgs in self.consume(InstalledRPM):
|
||
|
- for pkg in rpm_pkgs.items:
|
||
|
- if any(
|
||
|
- [
|
||
|
- has_distributionsig(pkg),
|
||
|
- is_gpg_pubkey(pkg),
|
||
|
- has_katello_prefix(pkg),
|
||
|
- pkg.name in whitelisted_cloud_pkgs,
|
||
|
- ]
|
||
|
- ):
|
||
|
- signed_pkgs.items.append(pkg)
|
||
|
- if distribution == 'rhel':
|
||
|
- rh_signed_pkgs.items.append(pkg)
|
||
|
- continue
|
||
|
-
|
||
|
- unsigned_pkgs.items.append(pkg)
|
||
|
-
|
||
|
- self.produce(signed_pkgs)
|
||
|
- self.produce(rh_signed_pkgs)
|
||
|
- self.produce(unsigned_pkgs)
|
||
|
+ distributionsignedrpmscanner.process()
|
||
|
diff --git a/repos/system_upgrade/common/actors/distributionsignedrpmscanner/libraries/distributionsignedrpmscanner.py b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/libraries/distributionsignedrpmscanner.py
|
||
|
new file mode 100644
|
||
|
index 00000000..0bc71bfa
|
||
|
--- /dev/null
|
||
|
+++ b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/libraries/distributionsignedrpmscanner.py
|
||
|
@@ -0,0 +1,72 @@
|
||
|
+import json
|
||
|
+import os
|
||
|
+
|
||
|
+from leapp.exceptions import StopActorExecutionError
|
||
|
+from leapp.libraries.common import rhui
|
||
|
+from leapp.libraries.common.config import get_env
|
||
|
+from leapp.libraries.stdlib import api
|
||
|
+from leapp.models import DistributionSignedRPM, InstalledRedHatSignedRPM, InstalledRPM, InstalledUnsignedRPM
|
||
|
+
|
||
|
+
|
||
|
+def get_distribution_data(distribution):
|
||
|
+ distributions_path = api.get_common_folder_path('distro')
|
||
|
+
|
||
|
+ distribution_config = os.path.join(distributions_path, distribution, 'gpg-signatures.json')
|
||
|
+ if os.path.exists(distribution_config):
|
||
|
+ with open(distribution_config) as distro_config_file:
|
||
|
+ distro_config_json = json.load(distro_config_file)
|
||
|
+ distro_keys = distro_config_json.get('keys', [])
|
||
|
+ # distro_packager = distro_config_json.get('packager', 'not-available')
|
||
|
+ else:
|
||
|
+ raise StopActorExecutionError(
|
||
|
+ 'Cannot find distribution signature configuration.',
|
||
|
+ details={'Problem': 'Distribution {} was not found in {}.'.format(distribution, distributions_path)})
|
||
|
+ return distro_keys
|
||
|
+
|
||
|
+
|
||
|
+def is_distro_signed(pkg, distro_keys):
|
||
|
+ return any(key in pkg.pgpsig for key in distro_keys)
|
||
|
+
|
||
|
+
|
||
|
+def is_exceptional(pkg, allowlist):
|
||
|
+ """
|
||
|
+ Some packages should be marked always as signed
|
||
|
+
|
||
|
+ tl;dr; gpg-pubkey, katello packages, and rhui packages
|
||
|
+
|
||
|
+ gpg-pubkey is not real RPM. It's just an entry representing
|
||
|
+ gpg key imported inside the RPM DB. For that same reason, it cannot be
|
||
|
+ signed. Note that it cannot affect the upgrade transaction, so ignore
|
||
|
+ who vendored the key. Total majority of all machines have imported third
|
||
|
+ party gpg keys.
|
||
|
+
|
||
|
+ Katello packages have various names and are created on a Satellite server.
|
||
|
+
|
||
|
+ The allowlist is now used for any other package names that should be marked
|
||
|
+ always as signed for the particular upgrade.
|
||
|
+ """
|
||
|
+ return pkg.name == 'gpg-pubkey' or pkg.name.startswith('katello-ca-consumer') or pkg.name in allowlist
|
||
|
+
|
||
|
+
|
||
|
+def process():
|
||
|
+ distribution = api.current_actor().configuration.os_release.release_id
|
||
|
+ distro_keys = get_distribution_data(distribution)
|
||
|
+ all_signed = get_env('LEAPP_DEVEL_RPMS_ALL_SIGNED', '0') == '1'
|
||
|
+ rhui_pkgs = rhui.get_all_known_rhui_pkgs_for_current_upg()
|
||
|
+
|
||
|
+ signed_pkgs = DistributionSignedRPM()
|
||
|
+ rh_signed_pkgs = InstalledRedHatSignedRPM()
|
||
|
+ unsigned_pkgs = InstalledUnsignedRPM()
|
||
|
+
|
||
|
+ for rpm_pkgs in api.consume(InstalledRPM):
|
||
|
+ for pkg in rpm_pkgs.items:
|
||
|
+ if all_signed or is_distro_signed(pkg, distro_keys) or is_exceptional(pkg, rhui_pkgs):
|
||
|
+ signed_pkgs.items.append(pkg)
|
||
|
+ if distribution == 'rhel':
|
||
|
+ rh_signed_pkgs.items.append(pkg)
|
||
|
+ continue
|
||
|
+ unsigned_pkgs.items.append(pkg)
|
||
|
+
|
||
|
+ api.produce(signed_pkgs)
|
||
|
+ api.produce(rh_signed_pkgs)
|
||
|
+ api.produce(unsigned_pkgs)
|
||
|
diff --git a/repos/system_upgrade/common/actors/distributionsignedrpmscanner/tests/test_distributionsignedrpmscanner.py b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/tests/test_distributionsignedrpmscanner.py
|
||
|
index a15ae173..f138bcb2 100644
|
||
|
--- a/repos/system_upgrade/common/actors/distributionsignedrpmscanner/tests/test_distributionsignedrpmscanner.py
|
||
|
+++ b/repos/system_upgrade/common/actors/distributionsignedrpmscanner/tests/test_distributionsignedrpmscanner.py
|
||
|
@@ -180,11 +180,11 @@ def test_gpg_pubkey_pkg(current_actor_context):
|
||
|
current_actor_context.feed(InstalledRPM(items=installed_rpm))
|
||
|
current_actor_context.run(config_model=mock_configs.CONFIG)
|
||
|
assert current_actor_context.consume(DistributionSignedRPM)
|
||
|
- assert len(current_actor_context.consume(DistributionSignedRPM)[0].items) == 1
|
||
|
+ assert len(current_actor_context.consume(DistributionSignedRPM)[0].items) == 2
|
||
|
assert current_actor_context.consume(InstalledRedHatSignedRPM)
|
||
|
- assert len(current_actor_context.consume(InstalledRedHatSignedRPM)[0].items) == 1
|
||
|
+ assert len(current_actor_context.consume(InstalledRedHatSignedRPM)[0].items) == 2
|
||
|
assert current_actor_context.consume(InstalledUnsignedRPM)
|
||
|
- assert len(current_actor_context.consume(InstalledUnsignedRPM)[0].items) == 1
|
||
|
+ assert not current_actor_context.consume(InstalledUnsignedRPM)[0].items
|
||
|
|
||
|
|
||
|
def test_create_lookup():
|
||
|
--
|
||
|
2.43.0
|
||
|
|