diff --git a/SOURCES/leapp-repository-0.23.0-elevate.patch b/SOURCES/leapp-repository-0.23.0-elevate.patch index 4e84a80..00c0b47 100644 --- a/SOURCES/leapp-repository-0.23.0-elevate.patch +++ b/SOURCES/leapp-repository-0.23.0-elevate.patch @@ -8871,6 +8871,107 @@ index c076fe6b..2455a2f6 100644 UPGRADE_BLS_DIR = '/boot/upgrade-loader' CONTAINER_DOWNLOAD_DIR = '/tmp_pkg_download_dir' +diff --git a/repos/system_upgrade/el8toel9/actors/checkkernelrt/actor.py b/repos/system_upgrade/el8toel9/actors/checkkernelrt/actor.py +new file mode 100644 +index 00000000..073d7599 +--- /dev/null ++++ b/repos/system_upgrade/el8toel9/actors/checkkernelrt/actor.py +@@ -0,0 +1,21 @@ ++from leapp.actors import Actor ++from leapp.libraries.actor import checkkernelrt ++from leapp.models import DistributionSignedRPM, RpmTransactionTasks ++from leapp.tags import ChecksPhaseTag, IPUWorkflowTag ++ ++ ++class CheckKernelRT(Actor): ++ """ ++ Workaround kernel-rt upgrade candidate issue during RHEL 8 to RHEL 9 upgrade. ++ ++ Removes the kernel-rt metapackage to avoid RPM transaction failures and ensures ++ kernel-rt-core is explicitly upgraded so real-time kernels continue to work. ++ """ ++ ++ name = 'check_kernel_rt' ++ consumes = (DistributionSignedRPM,) ++ produces = (RpmTransactionTasks,) ++ tags = (IPUWorkflowTag, ChecksPhaseTag) ++ ++ def process(self): ++ checkkernelrt.process() +diff --git a/repos/system_upgrade/el8toel9/actors/checkkernelrt/libraries/checkkernelrt.py b/repos/system_upgrade/el8toel9/actors/checkkernelrt/libraries/checkkernelrt.py +new file mode 100644 +index 00000000..654bc77c +--- /dev/null ++++ b/repos/system_upgrade/el8toel9/actors/checkkernelrt/libraries/checkkernelrt.py +@@ -0,0 +1,20 @@ ++from leapp.exceptions import StopActorExecutionError ++from leapp.libraries.stdlib import api ++from leapp.models import DistributionSignedRPM, RpmTransactionTasks ++ ++KERNEL_RT_PKG = 'kernel-rt' ++KERNEL_RT_CORE_PKG = 'kernel-rt-core' ++ ++ ++def process(): ++ pkgs = next(api.consume(DistributionSignedRPM), None) ++ if not pkgs: ++ raise StopActorExecutionError("Did not receive DistributionSignedRPM message.") ++ ++ has_kernel_rt = any(pkg.name == KERNEL_RT_PKG for pkg in pkgs.items) ++ if has_kernel_rt: ++ api.current_logger().debug( ++ 'Removing {} package as a workaround for problems with ' ++ 'finding its best upgrade candidate.'.format(KERNEL_RT_PKG) ++ ) ++ api.produce(RpmTransactionTasks(to_remove=[KERNEL_RT_PKG], to_upgrade=[KERNEL_RT_CORE_PKG])) +diff --git a/repos/system_upgrade/el8toel9/actors/checkkernelrt/tests/unit_test_checkkernelrt.py b/repos/system_upgrade/el8toel9/actors/checkkernelrt/tests/unit_test_checkkernelrt.py +new file mode 100644 +index 00000000..599cfc56 +--- /dev/null ++++ b/repos/system_upgrade/el8toel9/actors/checkkernelrt/tests/unit_test_checkkernelrt.py +@@ -0,0 +1,42 @@ ++import pytest ++ ++from leapp.libraries.actor import checkkernelrt ++from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked ++from leapp.libraries.stdlib import api ++from leapp.models import DistributionSignedRPM, RPM ++ ++ ++def _rpm(name): ++ return RPM( ++ name=name, ++ arch='x86_64', ++ version='1', ++ release='1', ++ epoch='0', ++ packager='Red Hat', ++ pgpsig='SOME_SIG' ++ ) ++ ++ ++@pytest.mark.parametrize( ++ ('pkgs', 'expect_produce'), ++ [ ++ ([], False), ++ ([_rpm('kernel')], False), ++ ([_rpm('kernel-rt'), _rpm('kernel-rt-core'), _rpm('kernel-rt-modules'), _rpm('kernel')], True), ++ ] ++) ++def test_kernel_rt_workaround(monkeypatch, pkgs, expect_produce): ++ current_actor_mocked = CurrentActorMocked(msgs=[DistributionSignedRPM(items=pkgs)]) ++ monkeypatch.setattr(api, "current_actor", current_actor_mocked) ++ monkeypatch.setattr(api, 'produce', produce_mocked()) ++ ++ checkkernelrt.process() ++ ++ if expect_produce: ++ assert api.produce.called == 1 ++ rpm_tasks = api.produce.model_instances[0] ++ assert rpm_tasks.to_remove == ['kernel-rt'] ++ assert rpm_tasks.to_upgrade == ['kernel-rt-core'] ++ else: ++ assert not api.produce.called diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py index daa7b2ca..dd604d8b 100644 --- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py @@ -8902,6 +9003,322 @@ index daa7b2ca..dd604d8b 100644 def get_workaround_efi_info(): +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/actor.py b/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/actor.py +new file mode 100644 +index 00000000..eee195cf +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/actor.py +@@ -0,0 +1,18 @@ ++from leapp.actors import Actor ++from leapp.libraries.actor import checkkrb5conf ++from leapp.models import OutdatedKrb5conf, Report ++from leapp.tags import ChecksPhaseTag, IPUWorkflowTag ++ ++ ++class CheckKrb5conf(Actor): ++ """ ++ Create report with the location of oudated krb5 configuration files ++ """ ++ ++ name = 'check_krb5_conf' ++ consumes = (OutdatedKrb5conf,) ++ produces = (Report,) ++ tags = (ChecksPhaseTag, IPUWorkflowTag) ++ ++ def process(self): ++ checkkrb5conf.process() +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/libraries/checkkrb5conf.py b/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/libraries/checkkrb5conf.py +new file mode 100644 +index 00000000..9feeb74e +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/checkkrb5conf/libraries/checkkrb5conf.py +@@ -0,0 +1,55 @@ ++from leapp import reporting ++from leapp.exceptions import StopActorExecutionError ++from leapp.libraries.stdlib import api ++from leapp.models import OutdatedKrb5conf ++ ++FMT_LIST_SEPARATOR = "\n - " ++ ++ ++def __human_readable_list(unmanaged_files): ++ if unmanaged_files: ++ return FMT_LIST_SEPARATOR + FMT_LIST_SEPARATOR.join(unmanaged_files) ++ return '' ++ ++ ++def process(): ++ msg = next(api.consume(OutdatedKrb5conf), None) ++ if not msg: ++ raise StopActorExecutionError('Expected OutdatedKrb5conf, but got None') ++ ++ if msg.unmanaged_files: ++ reporting.create_report([ ++ reporting.Title('Unmanaged MIT krb5 configuration file(s) will be ' ++ 'updated to point to the new X.509 CA bundle file'), ++ reporting.Summary( ++ 'On RHEL 10, the location of the reference X.509 CA bundle ' ++ 'file was modified. The following unmanaged MIT krb5 ' ++ 'configuration files have to be updated to point to the new ' ++ 'bundle file:' + __human_readable_list(msg.unmanaged_files)), ++ reporting.Severity(reporting.Severity.INFO), ++ reporting.Groups([reporting.Groups.SECURITY, reporting.Groups.AUTHENTICATION]) ++ ]) ++ ++ if msg.rpm_provided_files: ++ file_paths_from_rpm = [f'{r.path} (provided by {r.rpm})'for r in msg.rpm_provided_files] ++ reporting.create_report([ ++ reporting.Title('RPM-provided MIT krb5 configuration file(s) are ' ++ 'pointing to outdated X.509 CA bundle file'), ++ reporting.Summary( ++ 'On RHEL 10, the location of the reference X.509 CA bundle ' ++ 'file was modified. Some MIT krb5 configuration files on this ' ++ 'system are pointing to the old bundle file, but are provided ' ++ 'by third-party RPMs. You must make sure these third-party ' ++ 'RPMs were updated to reflect this change, or you may be ' ++ 'unable to complete Kerberos PKINIT pre-authentication (e.g. ' ++ 'using user certificates, or smartcards). The following files ' ++ 'are affected:' + __human_readable_list(file_paths_from_rpm)), ++ reporting.Severity(reporting.Severity.MEDIUM), ++ reporting.Groups([reporting.Groups.SECURITY, reporting.Groups.AUTHENTICATION]) ++ ]) ++ ++ if not msg.unmanaged_files and not msg.rpm_provided_files: ++ api.current_logger().debug( ++ 'No outdated X.509 CA bundle references were found in MIT krb5 ' ++ 'configuration files, thus these files will remain unchanged.' ++ ) +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/actor.py b/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/actor.py +new file mode 100644 +index 00000000..962978ab +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/actor.py +@@ -0,0 +1,20 @@ ++from leapp.actors import Actor ++from leapp.libraries.actor import convertkrb5conf ++from leapp.models import OutdatedKrb5conf ++from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag ++ ++ ++class ConvertKrb5conf(Actor): ++ """ ++ Replace outdated references to the /etc/ssl/certs/ca-certificates.crt CA ++ bundle by the new /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem one in ++ krb5 configuration files. ++ """ ++ ++ name = 'convert_krb5_conf' ++ consumes = (OutdatedKrb5conf,) ++ produces = () ++ tags = (ApplicationsPhaseTag, IPUWorkflowTag) ++ ++ def process(self): ++ convertkrb5conf.process() +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/libraries/convertkrb5conf.py b/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/libraries/convertkrb5conf.py +new file mode 100644 +index 00000000..5078b5bf +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/convertkrb5conf/libraries/convertkrb5conf.py +@@ -0,0 +1,37 @@ ++from leapp.libraries.stdlib import api, CalledProcessError, run ++from leapp.models import OutdatedKrb5conf ++ ++ ++def _backup_krb5conf(conf_file): ++ try: ++ run(['/usr/bin/cp', conf_file, conf_file + '.leappsave']) ++ except CalledProcessError: ++ return False ++ return True ++ ++ ++def _convert_krb5conf(conf_file): ++ with open(conf_file) as f: ++ text = f.read().replace('/etc/ssl/certs/ca-certificates.crt', ++ '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem') ++ with open(conf_file, 'w') as f: ++ f.write(text) ++ ++ ++def process(): ++ msg = next(api.consume(OutdatedKrb5conf), None) ++ if not msg: ++ api.current_logger().error( ++ 'Expected OutdatedKrb5conf, but got None. ' ++ 'Cannot apply possibly needed changes in kerberos configuration files.' ++ ) ++ return ++ ++ if msg.unmanaged_files: ++ for file_path in msg.unmanaged_files: ++ if not _backup_krb5conf(file_path): ++ api.current_logger().error( ++ 'Could not back up the {} file. Skipping other actions.'.format(file_path) ++ ) ++ return ++ _convert_krb5conf(file_path) +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/actor.py b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/actor.py +new file mode 100644 +index 00000000..5283345d +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/actor.py +@@ -0,0 +1,19 @@ ++from leapp.actors import Actor ++from leapp.libraries.actor.scankrb5conf import fetch_outdated_krb5_conf_files ++from leapp.models import OutdatedKrb5conf ++from leapp.tags import FactsPhaseTag, IPUWorkflowTag ++ ++ ++class ScanKrb5conf(Actor): ++ """ ++ Scan the krb5 modular configuration folder for additional conf files ++ """ ++ ++ name = 'scan_krb5_conf' ++ consumes = () ++ produces = (OutdatedKrb5conf,) ++ tags = (FactsPhaseTag, IPUWorkflowTag) ++ ++ def process(self): ++ self.produce(fetch_outdated_krb5_conf_files(['/etc/krb5.conf', ++ '/etc/krb5.conf.d'])) +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/libraries/scankrb5conf.py b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/libraries/scankrb5conf.py +new file mode 100644 +index 00000000..64b7743a +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/libraries/scankrb5conf.py +@@ -0,0 +1,40 @@ ++import os ++ ++from leapp.libraries.common.rpms import has_package ++from leapp.libraries.stdlib import CalledProcessError, run ++from leapp.models import DistributionSignedRPM, OutdatedKrb5conf, RpmKrb5conf ++ ++ ++def fetch_outdated_krb5_conf_files(conf_paths, ca_bundle_path='/etc/ssl/certs/ca-certificates.crt'): ++ krb5_conf_files = set() ++ outdated_rpm_conf = [] ++ outdated_conf = set() ++ ++ for conf_path in conf_paths: ++ if os.path.isdir(conf_path): ++ for conf_file in os.listdir(conf_path): ++ krb5_conf_files.add(os.path.join(conf_path, conf_file)) ++ else: ++ krb5_conf_files.add(conf_path) ++ ++ for file_path in krb5_conf_files: ++ with open(file_path) as f: ++ if -1 != f.read().find(ca_bundle_path): ++ if file_path == '/etc/krb5.conf': ++ # The main krb5 config file is a special case. It is not ++ # modified by RPM updates, thus we have to use Leapp to do ++ # so. ++ outdated_conf.add(file_path) ++ else: ++ try: ++ rpm_nvr = run(['/usr/bin/rpm', '-qf', file_path], split=True)['stdout'][0] ++ # We only want to handle files signed by the distribution, because we have no guarantees ++ # about third party packages (we assume updated versions are already available). ++ if not has_package(DistributionSignedRPM, rpm_nvr): ++ outdated_rpm_conf.append(RpmKrb5conf(path=file_path, rpm=rpm_nvr)) ++ except CalledProcessError: ++ # Files not associated with any RPM are considered unmanaged. ++ outdated_conf.add(file_path) ++ ++ return OutdatedKrb5conf(unmanaged_files=list(outdated_conf), ++ rpm_provided_files=list(outdated_rpm_conf)) +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_affected b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_affected +new file mode 100644 +index 00000000..862c87c4 +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_affected +@@ -0,0 +1,2 @@ ++[libdefaults] ++pkinit_anchors = FILE:/not/affected/ca-bundle.pem +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_configured b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_configured +new file mode 100644 +index 00000000..d5726c25 +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_not_configured +@@ -0,0 +1,2 @@ ++[libdefaults] ++ca_bundle_not_configured = true +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_outdated b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_outdated +new file mode 100644 +index 00000000..44743726 +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_outdated +@@ -0,0 +1,2 @@ ++[libdefaults] ++pkinit_anchors = FILE:/etc/ssl/certs/ca-certificates.crt +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_uptodate b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_uptodate +new file mode 100644 +index 00000000..54a1869b +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/files/krb5conf_uptodate +@@ -0,0 +1,2 @@ ++[libdefaults] ++pkinit_anchors = FILE:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem +diff --git a/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/test_scankrb5conf.py b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/test_scankrb5conf.py +new file mode 100644 +index 00000000..2be949cb +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/actors/krb5conf/scankrb5conf/tests/test_scankrb5conf.py +@@ -0,0 +1,53 @@ ++import os ++ ++import pytest ++ ++from leapp.libraries.actor import scankrb5conf ++from leapp.libraries.actor.scankrb5conf import fetch_outdated_krb5_conf_files ++from leapp.libraries.common.testutils import CurrentActorMocked ++from leapp.libraries.stdlib import api ++from leapp.models import DistributionSignedRPM, RPM ++ ++CUR_DIR = os.path.dirname(os.path.abspath(__file__)) ++ ++ ++@pytest.mark.parametrize( ++ 'inp,exp_out', ++ [ ++ (['files/krb5conf_outdated'], ['files/krb5conf_outdated']), ++ (['files/krb5conf_not_affected'], []), ++ (['files/krb5conf_not_configured'], []), ++ (['files/krb5conf_uptodate'], []), ++ (['files'], ['files/krb5conf_outdated']), ++ ], ++) ++def test_fetch_outdated_krb5_conf_files_with_files(inp, exp_out): ++ msg = fetch_outdated_krb5_conf_files([os.path.join(CUR_DIR, i) for i in inp]) ++ assert len(msg.unmanaged_files) == len(exp_out) ++ assert set(msg.unmanaged_files) == set(os.path.join(CUR_DIR, o) for o in exp_out) ++ ++ ++def test_fetch_outdated_krb5_conf_files_rpm_provided(monkeypatch): ++ """Test that rpm_provided_files is populated when file belongs to an RPM not in DistributionSignedRPM.""" ++ test_rpm_name = 'krb5-libs' ++ test_file_path = os.path.join(CUR_DIR, 'files/krb5conf_outdated') ++ ++ def mock_run(cmd, split=False): ++ assert cmd == ['/usr/bin/rpm', '-qf', test_file_path] ++ return {'stdout': [test_rpm_name]} ++ ++ monkeypatch.setattr(scankrb5conf, 'run', mock_run) ++ ++ other_rpm = RPM(name='other-package', epoch='0', version='1.0', release='1.el9', ++ arch='x86_64', packager='Red Hat', pgpsig='RSA/SHA256') ++ dist_signed_rpms = DistributionSignedRPM(items=[other_rpm]) ++ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[dist_signed_rpms])) ++ ++ msg = fetch_outdated_krb5_conf_files([test_file_path]) ++ ++ # File should be in rpm_provided_files since the owning RPM is not in DistributionSignedRPM ++ assert len(msg.rpm_provided_files) == 1 ++ assert msg.rpm_provided_files[0].path == test_file_path ++ assert msg.rpm_provided_files[0].rpm == test_rpm_name ++ # Should not be in unmanaged_files ++ assert len(msg.unmanaged_files) == 0 diff --git a/repos/system_upgrade/el9toel10/actors/motifcheck/actor.py b/repos/system_upgrade/el9toel10/actors/motifcheck/actor.py new file mode 100644 index 00000000..4014e7f7 @@ -9055,3 +9472,31 @@ index 00000000..f7f641b3 + else: + # Assert for no motif packages installed + assert not reporting.create_report.called +diff --git a/repos/system_upgrade/el9toel10/models/OutdateKrb5conf.py b/repos/system_upgrade/el9toel10/models/OutdateKrb5conf.py +new file mode 100644 +index 00000000..e07c98f2 +--- /dev/null ++++ b/repos/system_upgrade/el9toel10/models/OutdateKrb5conf.py +@@ -0,0 +1,22 @@ ++from leapp.models import fields, Model ++from leapp.topics import SystemInfoTopic ++ ++ ++class RpmKrb5conf(Model): ++ topic = SystemInfoTopic ++ ++ path = fields.String() ++ rpm = fields.String() ++ ++ ++class OutdatedKrb5conf(Model): ++ """ ++ Provides a list of outdated krb5 conf files. ++ """ ++ topic = SystemInfoTopic ++ ++ unmanaged_files = fields.List(fields.String(), default=[]) ++ rpm_provided_files = fields.List(fields.Model(RpmKrb5conf), default=[]) ++ """ ++ The list with the full path to the krb5 conf files. ++ """ diff --git a/SPECS/leapp-repository.spec b/SPECS/leapp-repository.spec index 31f0015..b303039 100644 --- a/SPECS/leapp-repository.spec +++ b/SPECS/leapp-repository.spec @@ -53,7 +53,7 @@ py2_byte_compile "%1" "%2"} Epoch: 1 Name: leapp-repository Version: 0.23.0 -Release: 3%{?dist}.elevate.1 +Release: 3%{?dist}.elevate.2 Summary: Repositories for leapp License: ASL 2.0 @@ -572,6 +572,9 @@ fi %changelog +* Fri Jan 23 2026 Yuriy Kohut - 0.23.0-3.elevate.2 +- ELevate vendors support for upstream 0.23.0-3 version (8ad95cd1cb2a8cd38f92ae0c5f898892f5611a71) + * Tue Jan 20 2026 Yuriy Kohut - 0.23.0-3.elevate.1 - ELevate vendors support for upstream 0.23.0-3 version (c8e7af181a22e6282caed2d83d70265b6f1c73ce)