diff --git a/.gitignore b/.gitignore index 6029501..4f175a5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ /0.9.tar.gz /0.12.tar.gz /0.16.tar.gz +/0.19.tar.gz diff --git a/0001-Remove-ipaclustercheck.patch b/0001-Remove-ipaclustercheck.patch index 2118a27..00319fe 100644 --- a/0001-Remove-ipaclustercheck.patch +++ b/0001-Remove-ipaclustercheck.patch @@ -1,6 +1,6 @@ -From 378e0a353e670a6b498d454558a9139a859890d4 Mon Sep 17 00:00:00 2001 +From dee0c0842f92b9fb7caf64eb498c4c27d1aa5326 Mon Sep 17 00:00:00 2001 From: Rob Crittenden -Date: Thu, 9 Nov 2023 10:49:05 -0500 +Date: Mon, 22 Sep 2025 16:33:24 -0400 Subject: [PATCH] Remove ipaclustercheck --- @@ -26,13 +26,13 @@ Subject: [PATCH] Remove ipaclustercheck delete mode 100644 tests/test_cluster_ruv.py diff --git a/setup.py b/setup.py -index d926302..cb6265a 100644 +index 578fc52..6f47cda 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import find_packages, setup setup( name='ipahealthcheck', - version='0.16', + version='0.19', - namespace_packages=['ipahealthcheck', 'ipaclustercheck'], + namespace_packages=['ipahealthcheck'], package_dir={'': 'src'}, @@ -53,7 +53,7 @@ index d926302..cb6265a 100644 ], # subsystem registries 'ipahealthcheck.registry': [ -@@ -72,13 +69,6 @@ setup( +@@ -73,13 +70,6 @@ setup( 'ipahealthcheck.system': [ 'filesystemspace = ipahealthcheck.system.filesystemspace', ], @@ -635,5 +635,5 @@ index 7583c84..0000000 - assert result.kw.get('name') == 'dangling_csruv' - assert result.kw.get('value') == '9' -- -2.38.1 +2.49.0 diff --git a/0002-Don-t-fail-if-a-service-name-cannot-be-looked-up-in-.patch b/0002-Don-t-fail-if-a-service-name-cannot-be-looked-up-in-.patch deleted file mode 100644 index 5233083..0000000 --- a/0002-Don-t-fail-if-a-service-name-cannot-be-looked-up-in-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 35ff77300758c12110132d6d638802d5b223bd6d Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 13 Nov 2023 14:09:16 -0500 -Subject: [PATCH] Don't fail if a service name cannot be looked up in LDAP - -A new method was introduced to handle more IPA services. This -requires looking some of them up in LDAP. dirsrv not running -was not being caught so raised an error instead. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/312 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/meta/services.py | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/src/ipahealthcheck/meta/services.py b/src/ipahealthcheck/meta/services.py -index 10fa83f..9838128 100644 ---- a/src/ipahealthcheck/meta/services.py -+++ b/src/ipahealthcheck/meta/services.py -@@ -25,10 +25,18 @@ class IPAServiceCheck(ServiceCheck): - def get_service_name(self, role): - """Roles define broad services. Translate a role name into - an individual service name. -+ -+ Returns a string on success, None if the service is not -+ configured or cannot be determined. - """ - conn = api.Backend.ldap2 -- if not api.Backend.ldap2.isconnected(): -- api.Backend.ldap2.connect() -+ try: -+ if not api.Backend.ldap2.isconnected(): -+ api.Backend.ldap2.connect() -+ except errors.NetworkError: -+ logger.debug("Service '%s' is not running", self.service_name) -+ return None -+ - dn = DN( - ("cn", role), ("cn", api.env.host), - ("cn", "masters"), ("cn", "ipa"), ("cn", "etc"), --- -2.41.0 - diff --git a/0003-Temporarily-disable-the-ipa-ods-exporter-service-sta.patch b/0003-Temporarily-disable-the-ipa-ods-exporter-service-sta.patch deleted file mode 100644 index 2795766..0000000 --- a/0003-Temporarily-disable-the-ipa-ods-exporter-service-sta.patch +++ /dev/null @@ -1,44 +0,0 @@ -From d1cb1997737c938bbc61d547aae277e308e78fce Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Tue, 14 Nov 2023 20:32:54 -0500 -Subject: [PATCH] Temporarily disable the ipa-ods-exporter service status check - -There is a bug in this service such that it will almost always -report as down. Rather than spamming users with this error give -time for it to be fixed in IPA upstream. - -See https://pagure.io/freeipa/issue/9463 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/meta/services.py | 14 -------------- - 1 file changed, 14 deletions(-) - -diff --git a/src/ipahealthcheck/meta/services.py b/src/ipahealthcheck/meta/services.py -index 9838128..b8973cb 100644 ---- a/src/ipahealthcheck/meta/services.py -+++ b/src/ipahealthcheck/meta/services.py -@@ -202,20 +202,6 @@ class ods_enforcerd(IPAServiceCheck): - return super().check() - - --@registry --class ipa_ods_exporter(IPAServiceCheck): -- requires = ('dirsrv',) -- -- def check(self, instance=''): -- self.service_name = self.get_service_name('DNSKeyExporter') -- -- if self.service_name is None: -- # No service name means it is not configured -- return () -- -- return super().check() -- -- - @registry - class ipa_dnskeysyncd(IPAServiceCheck): - requires = ('dirsrv',) --- -2.40.1 - diff --git a/0004-Skip-DogtagCertsConfigCheck-for-PKI-versions-11.5.0.patch b/0004-Skip-DogtagCertsConfigCheck-for-PKI-versions-11.5.0.patch deleted file mode 100644 index a31c062..0000000 --- a/0004-Skip-DogtagCertsConfigCheck-for-PKI-versions-11.5.0.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e556edc0b1cb607caa50f760d5059877f35fbcdc Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 11 Jan 2024 14:40:02 -0500 -Subject: [PATCH] Skip DogtagCertsConfigCheck for PKI versions >= 11.5.0 - -In 11.5.0 the PKI project stopped storing the certificate -blobs in CS.cfg. If we continue to check it we will report a -false positive so skip it in that case. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/317 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/dogtag/ca.py | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/ipahealthcheck/dogtag/ca.py b/src/ipahealthcheck/dogtag/ca.py -index 4afa5d7..ddf5ece 100644 ---- a/src/ipahealthcheck/dogtag/ca.py -+++ b/src/ipahealthcheck/dogtag/ca.py -@@ -16,6 +16,8 @@ from ipaserver.install import krainstance - from ipapython.directivesetter import get_directive - from cryptography.hazmat.primitives.serialization import Encoding - -+import pki.util -+ - logger = logging.getLogger() - - -@@ -30,6 +32,13 @@ class DogtagCertsConfigCheck(DogtagPlugin): - logger.debug("No CA configured, skipping dogtag config check") - return - -+ pki_version = pki.util.Version(pki.specification_version()) -+ if pki_version >= pki.util.Version("11.5.0"): -+ logger.debug( -+ "PKI 11.5.0 no longer stores certificats in CS.cfg" -+ ) -+ return -+ - kra = krainstance.KRAInstance(api.env.realm) - - blobs = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', --- -2.42.0 - diff --git a/0005-test-Handle-PKI-11.5.0-not-storing-certs-in-CS.cfg.patch b/0005-test-Handle-PKI-11.5.0-not-storing-certs-in-CS.cfg.patch deleted file mode 100644 index 3c62ac0..0000000 --- a/0005-test-Handle-PKI-11.5.0-not-storing-certs-in-CS.cfg.patch +++ /dev/null @@ -1,59 +0,0 @@ -From cafe01a23a36c408c8c60357ad2651688dc63599 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Fri, 12 Jan 2024 10:17:18 -0500 -Subject: [PATCH] test: Handle PKI >= 11.5.0 not storing certs in CS.cfg - -Update the test to expect 0 results if the PKI version is ->= 11.5.0. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/317 - -Signed-off-by: Rob Crittenden ---- - tests/test_dogtag_ca.py | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/tests/test_dogtag_ca.py b/tests/test_dogtag_ca.py -index 0820aba..1f61dea 100644 ---- a/tests/test_dogtag_ca.py -+++ b/tests/test_dogtag_ca.py -@@ -2,12 +2,16 @@ - # Copyright (C) 2019 FreeIPA Contributors see COPYING for license - # - -+import pki.util - from util import capture_results, CAInstance, KRAInstance - from base import BaseTest - from ipahealthcheck.core import config, constants - from ipahealthcheck.dogtag.plugin import registry - from ipahealthcheck.dogtag.ca import DogtagCertsConfigCheck - from unittest.mock import Mock, patch -+import pytest -+ -+pki_version = pki.util.Version(pki.specification_version()) - - - class mock_Cert: -@@ -43,6 +47,9 @@ class TestCACerts(BaseTest): - Mock(return_value=KRAInstance()), - } - -+ @pytest.mark.skipif( -+ pki_version >= pki.util.Version("11.5.0"), -+ reason='Does not apply to PKI 11.5.0+') - @patch('ipahealthcheck.dogtag.ca.get_directive') - @patch('ipaserver.install.certs.CertDB') - def test_ca_certs_ok(self, mock_certdb, mock_directive): -@@ -71,6 +78,9 @@ class TestCACerts(BaseTest): - assert result.source == 'ipahealthcheck.dogtag.ca' - assert result.check == 'DogtagCertsConfigCheck' - -+ @pytest.mark.skipif( -+ pki_version >= pki.util.Version("11.5.0"), -+ reason='Does not apply to PKI 11.5.0+') - @patch('ipahealthcheck.dogtag.ca.get_directive') - @patch('ipaserver.install.certs.CertDB') - def test_cert_missing_from_file(self, mock_certdb, mock_directive): --- -2.42.0 - diff --git a/0006-Fixes-log-file-permissions-as-per-CIS-benchmark.patch b/0006-Fixes-log-file-permissions-as-per-CIS-benchmark.patch deleted file mode 100644 index a2de107..0000000 --- a/0006-Fixes-log-file-permissions-as-per-CIS-benchmark.patch +++ /dev/null @@ -1,47 +0,0 @@ -From e0c09f9f1388bbce43775f40a39266e692e231da Mon Sep 17 00:00:00 2001 -From: Thorsten Scherf -Date: Wed, 13 Mar 2024 12:57:34 +0100 -Subject: [PATCH 1/4] Fixes log file permissions as per CIS benchmark - -As per CIS benchmark the log file permissions should be 640 for some log -files but if we change /var/log/ipa-custodia.audit.log permissions to -640 then "ipa-healthcheck" reports a permission issue. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/325 -Signed-off-by: Thorsten Scherf ---- - src/ipahealthcheck/ipa/files.py | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/ipahealthcheck/ipa/files.py b/src/ipahealthcheck/ipa/files.py -index b7ca116..d914014 100644 ---- a/src/ipahealthcheck/ipa/files.py -+++ b/src/ipahealthcheck/ipa/files.py -@@ -121,7 +121,7 @@ class IPAFileCheck(IPAPlugin, FileCheck): - self.files.append((filename, 'root', 'root', '0600')) - - self.files.append((paths.IPA_CUSTODIA_AUDIT_LOG, -- 'root', 'root', '0644')) -+ 'root', 'root', '0644', '0640')) - - self.files.append((paths.KADMIND_LOG, 'root', 'root', - ('0600', '0640'))) -@@ -133,11 +133,13 @@ class IPAFileCheck(IPAPlugin, FileCheck): - self.files.append((paths.SLAPD_INSTANCE_ERROR_LOG_TEMPLATE % inst, - constants.DS_USER, constants.DS_GROUP, '0600')) - -- self.files.append((paths.VAR_LOG_HTTPD_ERROR, 'root', 'root', '0644')) -+ self.files.append((paths.VAR_LOG_HTTPD_ERROR, 'root', 'root', -+ '0644', '0640')) - - for globpath in glob.glob("%s/debug*.log" % paths.TOMCAT_CA_DIR): - self.files.append( -- (globpath, constants.PKI_USER, constants.PKI_GROUP, "0644") -+ (globpath, constants.PKI_USER, constants.PKI_GROUP, -+ "0644", "0640") - ) - - for globpath in glob.glob( --- -2.45.0 - diff --git a/0007-Fix-some-file-mode-format-issues.patch b/0007-Fix-some-file-mode-format-issues.patch deleted file mode 100644 index d49c0cd..0000000 --- a/0007-Fix-some-file-mode-format-issues.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 2206b9915606c555163dec775a99a355dc02bee0 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Tue, 28 May 2024 11:15:48 -0400 -Subject: [PATCH 3/4] Fix some file mode format issues - -When specifying multiple possible modes for a file the values must -be a tuple. There were two occurances where they were listed -separately. - -Add in a pre-check on the formatting to raise an error for badly -formatted files. This may be annoying for users if one sneaks in -again but the CI should catch it. - -Related: https://github.com/freeipa/freeipa-healthcheck/issues/325 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/core/files.py | 12 +++++- - src/ipahealthcheck/ipa/files.py | 6 +-- - tests/test_core_files.py | 72 +++++++++++++++++++++++++++++++- - tests/util.py | 1 + - 4 files changed, 85 insertions(+), 6 deletions(-) - -diff --git a/src/ipahealthcheck/core/files.py b/src/ipahealthcheck/core/files.py -index 85d42bc..32bc5b2 100644 ---- a/src/ipahealthcheck/core/files.py -+++ b/src/ipahealthcheck/core/files.py -@@ -31,7 +31,17 @@ class FileCheck: - - @duration - def check(self): -- for (path, owner, group, mode) in self.files: -+ # first validate that the list of files to check is in the correct -+ # format -+ process_files = [] -+ for file in self.files: -+ if len(file) == 4: -+ process_files.append(file) -+ else: -+ yield Result(self, constants.ERROR, key=file, -+ msg='Code format is incorrect for file') -+ -+ for (path, owner, group, mode) in process_files: - if not isinstance(owner, tuple): - owner = tuple((owner,)) - if not isinstance(group, tuple): -diff --git a/src/ipahealthcheck/ipa/files.py b/src/ipahealthcheck/ipa/files.py -index d914014..c80fd5b 100644 ---- a/src/ipahealthcheck/ipa/files.py -+++ b/src/ipahealthcheck/ipa/files.py -@@ -121,7 +121,7 @@ class IPAFileCheck(IPAPlugin, FileCheck): - self.files.append((filename, 'root', 'root', '0600')) - - self.files.append((paths.IPA_CUSTODIA_AUDIT_LOG, -- 'root', 'root', '0644', '0640')) -+ 'root', 'root', ('0644', '0640'))) - - self.files.append((paths.KADMIND_LOG, 'root', 'root', - ('0600', '0640'))) -@@ -134,12 +134,12 @@ class IPAFileCheck(IPAPlugin, FileCheck): - constants.DS_USER, constants.DS_GROUP, '0600')) - - self.files.append((paths.VAR_LOG_HTTPD_ERROR, 'root', 'root', -- '0644', '0640')) -+ ('0644', '0640'))) - - for globpath in glob.glob("%s/debug*.log" % paths.TOMCAT_CA_DIR): - self.files.append( - (globpath, constants.PKI_USER, constants.PKI_GROUP, -- "0644", "0640") -+ ("0644", "0640")) - ) - - for globpath in glob.glob( -diff --git a/tests/test_core_files.py b/tests/test_core_files.py -index 924d7fa..e7010a9 100644 ---- a/tests/test_core_files.py -+++ b/tests/test_core_files.py -@@ -2,14 +2,22 @@ - # Copyright (C) 2019 FreeIPA Contributors see COPYING for license - # - -+from ldap import OPT_X_SASL_SSF_MIN - import pwd - import posix -+from util import m_api -+from util import capture_results -+ -+from ipahealthcheck.core import config - from ipahealthcheck.core.files import FileCheck - from ipahealthcheck.core import constants - from ipahealthcheck.core.plugin import Results -+from ipahealthcheck.ipa.files import IPAFileCheck -+from ipahealthcheck.system.plugin import registry - from unittest.mock import patch -+from ipapython.dn import DN -+from ipapython.ipaldap import LDAPClient, LDAPEntry - --from util import capture_results - - nobody = pwd.getpwnam('nobody') - -@@ -20,6 +28,37 @@ files = (('foo', 'root', 'root', '0660'), - ('fiz', ('root', 'bin'), ('root', 'bin'), '0664'), - ('zap', ('root', 'bin'), ('root', 'bin'), ('0664', '0640'),)) - -+bad_modes = (('biz', ('root', 'bin'), ('root', 'bin'), '0664', '0640'),) -+ -+ -+class mock_ldap: -+ SCOPE_BASE = 1 -+ SCOPE_ONELEVEL = 2 -+ SCOPE_SUBTREE = 4 -+ -+ def __init__(self, ldapentry): -+ """Initialize the results that we will return from get_entries""" -+ self.results = ldapentry -+ -+ def get_entry(self, dn, attrs_list=None, time_limit=None, -+ size_limit=None, get_effective_rights=False): -+ return [] # the call doesn't check the value -+ -+ -+class mock_ldap_conn: -+ def set_option(self, option, invalue): -+ pass -+ -+ def get_option(self, option): -+ if option == OPT_X_SASL_SSF_MIN: -+ return 256 -+ -+ return None -+ -+ def search_s(self, base, scope, filterstr=None, -+ attrlist=None, attrsonly=0): -+ return tuple() -+ - - def make_stat(mode=33200, uid=0, gid=0): - """Return a mocked-up stat. -@@ -234,4 +273,33 @@ def test_files_group_not_found(mock_grgid, mock_grnam, mock_stat): - my_results = get_results(results, 'group') - for result in my_results.results: - assert result.result == constants.WARNING -- assert result.kw.get('got') == 'Unknown gid 0' -+ -+ -+def test_bad_modes(): -+ f = FileCheck() -+ f.files = bad_modes -+ -+ results = capture_results(f) -+ -+ for result in results.results: -+ assert result.result == constants.ERROR -+ assert result.kw.get('msg') == 'Code format is incorrect for file' -+ -+ -+@patch('ipaserver.install.krbinstance.is_pkinit_enabled') -+def test_ipa_files_format(mock_pkinit): -+ mock_pkinit.return_value = True -+ -+ fake_conn = LDAPClient('ldap://localhost', no_schema=True) -+ ldapentry = LDAPEntry(fake_conn, DN(m_api.env.container_dns, -+ m_api.env.basedn)) -+ framework = object() -+ registry.initialize(framework, config.Config) -+ f = IPAFileCheck(registry) -+ -+ f.conn = mock_ldap(ldapentry) -+ -+ results = capture_results(f) -+ -+ for result in results.results: -+ assert result.result == constants.SUCCESS -diff --git a/tests/util.py b/tests/util.py -index 12c1688..fb8750a 100644 ---- a/tests/util.py -+++ b/tests/util.py -@@ -141,6 +141,7 @@ m_api.env.container_host = DN(('cn', 'computers'), ('cn', 'accounts')) - m_api.env.container_sysaccounts = DN(('cn', 'sysaccounts'), ('cn', 'etc')) - m_api.env.container_service = DN(('cn', 'services'), ('cn', 'accounts')) - m_api.env.container_masters = DN(('cn', 'masters')) -+m_api.env.container_dns = DN(('cn', 'dns')) - m_api.Backend = Mock() - m_api.Command = Mock() - m_api.Command.ping.return_value = { --- -2.45.0 - diff --git a/0008-Allow-WARNING-in-the-files-test.patch b/0008-Allow-WARNING-in-the-files-test.patch deleted file mode 100644 index b14d141..0000000 --- a/0008-Allow-WARNING-in-the-files-test.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 79cca342b3c440a045cadbff871ff977e35222c6 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 20 Jun 2024 14:27:16 -0400 -Subject: [PATCH] Allow WARNING in the files test - -We are only validating the format and don't need to actually -enforce the results in CI. The validation raises ERROR. - -Related: https://github.com/freeipa/freeipa-healthcheck/issues/325 - -Signed-off-by: Rob Crittenden ---- - tests/test_core_files.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/test_core_files.py b/tests/test_core_files.py -index e7010a9..d308410 100644 ---- a/tests/test_core_files.py -+++ b/tests/test_core_files.py -@@ -302,4 +302,4 @@ def test_ipa_files_format(mock_pkinit): - results = capture_results(f) - - for result in results.results: -- assert result.result == constants.SUCCESS -+ assert result.result in (constants.SUCCESS, constants.WARNING) --- -2.45.0 - diff --git a/0009-Check-user-provided-certificates-for-expiration.patch b/0009-Check-user-provided-certificates-for-expiration.patch deleted file mode 100644 index de7c4ba..0000000 --- a/0009-Check-user-provided-certificates-for-expiration.patch +++ /dev/null @@ -1,345 +0,0 @@ -From 7480a65f13cd17cc57a82f36ddb4fe3fbc7fdf64 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 10 Feb 2025 13:08:50 -0500 -Subject: [PATCH] Check user-provided certificates for expiration - -Validate the Apache, DS and PKINIT certificates and -warn if they are going to expire soon. This should help -users avoid expired certificates they provide themselves. - -These were originally logged and skipped. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/347 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/ipa/certs.py | 81 ++++++++++++++++ - tests/common.py | 71 ++++++++++++++ - tests/test_ipa_nssdb.py | 23 +---- - tests/test_ipa_userprovided_expiration.py | 110 ++++++++++++++++++++++ - 4 files changed, 263 insertions(+), 22 deletions(-) - create mode 100644 tests/common.py - create mode 100644 tests/test_ipa_userprovided_expiration.py - -diff --git a/src/ipahealthcheck/ipa/certs.py b/src/ipahealthcheck/ipa/certs.py -index b8332e0..fc626a6 100644 ---- a/src/ipahealthcheck/ipa/certs.py -+++ b/src/ipahealthcheck/ipa/certs.py -@@ -453,6 +453,87 @@ class IPACertfileExpirationCheck(IPAPlugin): - yield Result(self, constants.SUCCESS, key=id) - - -+@registry -+class IPAUserProvidedExpirationCheck(IPAPlugin): -+ """ -+ If we detect user-provided certificates then check to see if -+ they are expiring soon. -+ -+ This only applies to the HTTP, DS and KRB certificates. -+ """ -+ def validate_cert(self, id, cert, certfile=None, nssdb=None, -+ nickname=None): -+ now = datetime.now(tz=timezone.utc) -+ notafter = cert.not_valid_after_utc -+ -+ if certfile: -+ location = certfile -+ if nssdb: -+ location = "{}:{}".format(nssdb, nickname) -+ -+ if now > notafter: -+ logger.debug("expired") -+ yield Result(self, constants.ERROR, -+ key=id, -+ location=location, -+ expiration_date=generalized_time(notafter), -+ msg='Request id {key} expired on ' -+ '{expiration_date}') -+ return -+ -+ delta = notafter - now -+ diff = int(delta.total_seconds() / DAY) -+ if diff < int(self.config.cert_expiration_days): -+ logger.debug("expiring soon") -+ yield Result(self, constants.WARNING, -+ key=id, -+ location=location, -+ expiration_date=generalized_time(notafter), -+ days=diff, -+ msg='Request id {key} expires in {days} ' -+ 'days. You need to manually renew this ' -+ 'certificate.') -+ return -+ -+ yield Result(self, constants.SUCCESS, location=location, key=id) -+ -+ @duration -+ def check(self): -+ for id, certfile in ( -+ ("HTTP", paths.HTTPD_CERT_FILE), -+ ("KDC", paths.KDC_CERT) -+ ): -+ try: -+ cert = x509.load_certificate_from_file(certfile) -+ except Exception as e: -+ yield Result(self, constants.ERROR, -+ key=id, -+ certfile=certfile, -+ error=str(e), -+ msg='Request id {key}: Unable to open cert ' -+ 'file \'{certfile}\': {error}') -+ continue -+ issued = is_ipa_issued_cert(api, cert) -+ if issued is None: -+ logger.debug('Unable to determine if \'%s\' was issued by IPA ' -+ 'because no LDAP connection, assuming yes.') -+ continue -+ elif issued is True: -+ logging.debug("Issued by IPA, skipping") -+ continue -+ yield from self.validate_cert(id, cert, certfile=certfile) -+ -+ ds_db_dirname = dsinstance.config_dirname(self.serverid) -+ ds_db = certs.CertDB(api.env.realm, nssdir=ds_db_dirname) -+ nickname = self.ds.get_server_cert_nickname(self.serverid) -+ cert = ds_db.get_cert_from_db(nickname) -+ if is_ipa_issued_cert(api, cert): -+ logging.debug("Issued by IPA, skipping") -+ return -+ yield from self.validate_cert("LDAP", cert, nssdb=ds_db_dirname, -+ nickname=nickname) -+ -+ - @registry - class IPACertTracking(IPAPlugin): - """Compare the certificates tracked by certmonger to those that -diff --git a/tests/common.py b/tests/common.py -new file mode 100644 -index 0000000..91799cc ---- /dev/null -+++ b/tests/common.py -@@ -0,0 +1,71 @@ -+# -+# Copyright (C) 2025 FreeIPA Contributors see COPYING for license -+# -+from datetime import datetime, timedelta, timezone -+ -+ -+class mock_Cert: -+ """Fake up a certificate. -+ -+ The contents are the NSS nickname of the certificate. -+ """ -+ -+ def __init__( -+ self, -+ text, -+ issuer="CN=Someone", -+ not_after=datetime.now(tz=timezone.utc), -+ ): -+ self.text = text -+ self._issuer = issuer -+ self._not_valid_after_utc = not_after -+ -+ def public_bytes(self, encoding): -+ return self.text.encode("utf-8") -+ -+ @property -+ def issuer(self): -+ return self._issuer -+ -+ @property -+ def not_valid_after_utc(self): -+ return self._not_valid_after_utc -+ -+ -+class mock_CertDB: -+ def __init__(self, trust, expiration_days=0): -+ """A dict of nickname + NSSdb trust flags""" -+ self.trust = trust -+ self._expiration_days = expiration_days -+ -+ def list_certs(self): -+ return [ -+ (nickname, self.trust[nickname]) for nickname in self.trust -+ ] -+ -+ def get_cert_from_db(self, nickname): -+ """Return the nickname. This will match the value of get_directive""" -+ notafter = datetime.now(tz=timezone.utc) + timedelta( -+ days=self._expiration_days -+ ) -+ return mock_Cert(nickname, not_after=notafter) -+ -+ -+class mock_NSSDatabase: -+ def __init__(self, nssdir, token=None, pwd_file=None, trust=None): -+ self.trust = trust -+ self.token = token -+ -+ def list_certs(self): -+ return [ -+ (nickname, self.trust[nickname]) for nickname in self.trust -+ ] -+ -+ -+def my_unparse_trust_flags(trust_flags): -+ return trust_flags -+ -+ -+class DsInstance: -+ def get_server_cert_nickname(self, serverid): -+ return "Server-Cert" -diff --git a/tests/test_ipa_nssdb.py b/tests/test_ipa_nssdb.py -index cbf7277..8694f82 100644 ---- a/tests/test_ipa_nssdb.py -+++ b/tests/test_ipa_nssdb.py -@@ -9,28 +9,7 @@ from ipahealthcheck.ipa.plugin import registry - from ipahealthcheck.ipa.certs import IPACertNSSTrust - from ipaplatform.paths import paths - from unittest.mock import Mock, patch -- -- --class mock_CertDB: -- def __init__(self, trust): -- """A dict of nickname + NSSdb trust flags""" -- self.trust = trust -- -- def list_certs(self): -- return [(nickname, self.trust[nickname]) for nickname in self.trust] -- -- --class mock_NSSDatabase: -- def __init__(self, nssdir, token=None, pwd_file=None, trust=None): -- self.trust = trust -- self.token = token -- -- def list_certs(self): -- return [(nickname, self.trust[nickname]) for nickname in self.trust] -- -- --def my_unparse_trust_flags(trust_flags): -- return trust_flags -+from common import mock_NSSDatabase, my_unparse_trust_flags - - - # These tests make some assumptions about the order in which the -diff --git a/tests/test_ipa_userprovided_expiration.py b/tests/test_ipa_userprovided_expiration.py -new file mode 100644 -index 0000000..71ceb6c ---- /dev/null -+++ b/tests/test_ipa_userprovided_expiration.py -@@ -0,0 +1,110 @@ -+# -+# Copyright (C) 2025 FreeIPA Contributors see COPYING for license -+# -+ -+from util import capture_results -+from base import BaseTest -+from common import DsInstance -+from ipahealthcheck.core import config, constants -+from ipahealthcheck.ipa.plugin import registry -+from ipahealthcheck.ipa.certs import IPAUserProvidedExpirationCheck -+from unittest.mock import Mock, patch -+from ipapython.dn import DN -+from common import mock_CertDB -+ -+from datetime import datetime, timedelta, timezone -+ -+CERT_EXPIRATION_DAYS = 30 -+ -+ -+class IPACertificate: -+ def __init__(self, not_valid_after, serial_number=1): -+ self.subject = 'CN=RA AGENT' -+ self.issuer = 'CN=ISSUER' -+ self.serial_number = serial_number -+ self.not_valid_after_utc = not_valid_after -+ -+ -+class TestIPACertificateFile(BaseTest): -+ patches = { -+ 'ipaserver.install.dsinstance.DsInstance': -+ Mock(return_value=DsInstance()), -+ 'ipalib.install.certstore.get_ca_subject': -+ Mock(return_value=DN("CN=EXTERNAL")), -+ 'ipaserver.install.certs.is_ipa_issued_cert': -+ Mock(return_value=False), -+ } -+ -+ @patch('ipalib.x509.load_certificate_from_file') -+ @patch('ipaserver.install.certs.CertDB') -+ def test_certfile_expiration(self, mock_certdb, mock_load_cert): -+ cert = IPACertificate(not_valid_after=datetime.now(tz=timezone.utc) + -+ timedelta(days=CERT_EXPIRATION_DAYS)) -+ mock_load_cert.return_value = cert -+ mock_certdb.return_value = mock_CertDB({ -+ 'Server-Cert cert-pki-ca': 'u,u,u', -+ }, expiration_days=CERT_EXPIRATION_DAYS) -+ -+ framework = object() -+ registry.initialize(framework, config.Config) -+ f = IPAUserProvidedExpirationCheck(registry) -+ -+ f.config.cert_expiration_days = '28' -+ self.results = capture_results(f) -+ -+ assert len(self.results) == 3 -+ -+ for result in self.results.results: -+ assert result.result == constants.SUCCESS -+ assert result.source == 'ipahealthcheck.ipa.certs' -+ assert result.check == 'IPAUserProvidedExpirationCheck' -+ -+ @patch('ipalib.x509.load_certificate_from_file') -+ @patch('ipaserver.install.certs.CertDB') -+ def test_certfile_expiration_warning(self, mock_certdb, mock_load_cert): -+ cert = IPACertificate(not_valid_after=datetime.now(tz=timezone.utc) + -+ timedelta(days=7)) -+ mock_load_cert.return_value = cert -+ mock_certdb.return_value = mock_CertDB({ -+ 'Server-Cert cert-pki-ca': 'u,u,u', -+ }, expiration_days=7) -+ -+ framework = object() -+ registry.initialize(framework, config.Config) -+ f = IPAUserProvidedExpirationCheck(registry) -+ -+ f.config.cert_expiration_days = str(CERT_EXPIRATION_DAYS) -+ self.results = capture_results(f) -+ -+ assert len(self.results) == 3 -+ -+ for result in self.results.results: -+ assert result.result == constants.WARNING -+ assert result.source == 'ipahealthcheck.ipa.certs' -+ assert result.check == 'IPAUserProvidedExpirationCheck' -+ assert result.kw.get('days') == 6 -+ -+ @patch('ipalib.x509.load_certificate_from_file') -+ @patch('ipaserver.install.certs.CertDB') -+ def test_certfile_expiration_expired(self, mock_certdb, mock_load_cert): -+ cert = IPACertificate(not_valid_after=datetime.now(tz=timezone.utc) + -+ timedelta(days=-100)) -+ mock_load_cert.return_value = cert -+ mock_certdb.return_value = mock_CertDB({ -+ 'Server-Cert cert-pki-ca': 'u,u,u', -+ }, expiration_days=-100) -+ -+ framework = object() -+ registry.initialize(framework, config.Config) -+ f = IPAUserProvidedExpirationCheck(registry) -+ -+ f.config.cert_expiration_days = str(CERT_EXPIRATION_DAYS) -+ self.results = capture_results(f) -+ -+ assert len(self.results) == 3 -+ -+ for result in self.results.results: -+ assert result.result == constants.ERROR -+ assert result.source == 'ipahealthcheck.ipa.certs' -+ assert result.check == 'IPAUserProvidedExpirationCheck' -+ assert 'expiration_date' in result.kw --- -2.48.1 - diff --git a/0010-Warn-if-krbLastSuccessfulAuth-replication-is-enabled.patch b/0010-Warn-if-krbLastSuccessfulAuth-replication-is-enabled.patch deleted file mode 100644 index 31ab3b2..0000000 --- a/0010-Warn-if-krbLastSuccessfulAuth-replication-is-enabled.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 4127298975d4625006a8cb5183583df34c67107d Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 27 Feb 2025 12:17:41 -0500 -Subject: [PATCH] Warn if krbLastSuccessfulAuth replication is enabled - -This is controlled in IPA via the ipaconfigstring value including -KDC:Disable Last Success. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/315 - -Signed-off-by: Rob Crittenden ---- - setup.py | 1 + - src/ipahealthcheck/ipa/config.py | 46 +++++++++++++++++++++++++++ - tests/test_ipa_config.py | 54 ++++++++++++++++++++++++++++++++ - 3 files changed, 101 insertions(+) - create mode 100644 src/ipahealthcheck/ipa/config.py - create mode 100644 tests/test_ipa_config.py - -diff --git a/setup.py b/setup.py -index fe47b55..7126082 100644 ---- a/setup.py -+++ b/setup.py -@@ -39,6 +39,7 @@ setup( - # plugin modules for ipahealthcheck.ipa registry - 'ipahealthcheck.ipa': [ - 'ipacerts = ipahealthcheck.ipa.certs', -+ 'ipaconfig = ipahealthcheck.ipa.config', - 'ipadna = ipahealthcheck.ipa.dna', - 'ipadns = ipahealthcheck.ipa.idns', - 'ipafiles = ipahealthcheck.ipa.files', -diff --git a/src/ipahealthcheck/ipa/config.py b/src/ipahealthcheck/ipa/config.py -new file mode 100644 -index 0000000..c14ee8f ---- /dev/null -+++ b/src/ipahealthcheck/ipa/config.py -@@ -0,0 +1,46 @@ -+ -+# Copyright (C) 2025 FreeIPA Contributors see COPYING for license -+# -+ -+from ipahealthcheck.ipa.plugin import IPAPlugin, registry -+from ipahealthcheck.core.plugin import Result, duration -+from ipahealthcheck.core import constants -+ -+from ipalib import api -+ -+ -+@registry -+class IPAkrbLastSuccessfulAuth(IPAPlugin): -+ """Warn if krbLastSuccessfulAuth is enabled. It can cause -+ performance issues. -+ """ -+ requires = ('dirsrv',) -+ -+ @duration -+ def check(self): -+ try: -+ result = api.Command.config_show() -+ except Exception as e: -+ yield Result(self, constants.ERROR, -+ key='krbLastSuccessfulAuth', -+ msg='Request for configuration failed, %s' % e) -+ return -+ -+ configstring = result["result"].get( -+ "ipaconfigstring", [] -+ ) -+ -+ if 'KDC:Disable Last Success' not in configstring: -+ yield Result( -+ self, -+ constants.WARNING, -+ key='krbLastSuccessfulAuth', -+ configstring=configstring, -+ msg="Last Successful Auth is enabled. It may cause " -+ "performance problems.") -+ else: -+ yield Result( -+ self, -+ constants.SUCCESS, -+ key='krbLastSuccessfulAuth' -+ ) -diff --git a/tests/test_ipa_config.py b/tests/test_ipa_config.py -new file mode 100644 -index 0000000..5cc0c1e ---- /dev/null -+++ b/tests/test_ipa_config.py -@@ -0,0 +1,54 @@ -+# -+# Copyright (C) 2025 FreeIPA Contributors see COPYING for license -+# -+ -+from util import capture_results, m_api -+from base import BaseTest -+from ipahealthcheck.core import config, constants -+from ipahealthcheck.ipa.plugin import registry -+from ipahealthcheck.ipa.config import IPAkrbLastSuccessfulAuth -+ -+ -+class TestkrbLastSuccessfulAuth(BaseTest): -+ -+ def test_last_success_disabled(self): -+ """Test that no warning is issued in the default config""" -+ -+ m_api.Command.config_show.side_effect = [{ -+ 'result': { -+ 'ipaconfigstring': ['KDC:Disable Last Success',] -+ } -+ }] -+ -+ framework = object() -+ registry.initialize(framework, config.Config()) -+ f = IPAkrbLastSuccessfulAuth(registry) -+ self.results = capture_results(f) -+ -+ assert len(self.results) == 1 -+ result = self.results.results[0] -+ assert result.result == constants.SUCCESS -+ assert result.source == 'ipahealthcheck.ipa.config' -+ assert result.check == 'IPAkrbLastSuccessfulAuth' -+ -+ def test_last_success_enabled(self): -+ """Test that a warning is issued when krbLastSuccessfulAuth is -+ replicated. -+ """ -+ -+ m_api.Command.config_show.side_effect = [{ -+ 'result': { -+ 'ipaconfigstring': ['',] -+ } -+ }] -+ -+ framework = object() -+ registry.initialize(framework, config.Config()) -+ f = IPAkrbLastSuccessfulAuth(registry) -+ self.results = capture_results(f) -+ -+ assert len(self.results) == 1 -+ result = self.results.results[0] -+ assert result.result == constants.WARNING -+ assert result.source == 'ipahealthcheck.ipa.config' -+ assert result.check == 'IPAkrbLastSuccessfulAuth' --- -2.48.1 - diff --git a/0011-Warn-about-unexpected-umask.patch b/0011-Warn-about-unexpected-umask.patch deleted file mode 100644 index 055ca2b..0000000 --- a/0011-Warn-about-unexpected-umask.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 1607150d30a6f7da4dc4661b4e946d037da513e3 Mon Sep 17 00:00:00 2001 -From: David Hanina -Date: Wed, 26 Mar 2025 09:26:39 +0100 -Subject: [PATCH] Warn about unexpected umask - -We should let users know, that their umask set wrong to -an unsupported value, it does not make much sense to check file -permissions when wrong umask is set. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/353 -Signed-off-by: David Hanina ---- - src/ipahealthcheck/core/files.py | 25 ++++++++++++++++++++++++- - tests/test_core_files.py | 19 ++++++++++++++++++- - 2 files changed, 42 insertions(+), 2 deletions(-) - -diff --git a/src/ipahealthcheck/core/files.py b/src/ipahealthcheck/core/files.py -index 32bc5b2..6749d26 100644 ---- a/src/ipahealthcheck/core/files.py -+++ b/src/ipahealthcheck/core/files.py -@@ -12,6 +12,19 @@ from ipahealthcheck.core.plugin import Result, duration - - logger = logging.getLogger() - -+EXPECTED_UMASK = 0o022 -+ -+ -+def current_umask(): -+ """ -+ Retrieves current umask by setting it temporarily -+ -+ :returns: int umask -+ """ -+ umask = os.umask(EXPECTED_UMASK) -+ os.umask(umask) -+ return umask -+ - - class FileCheck: - """Generic check to validate permission and ownership of files -@@ -41,6 +54,16 @@ class FileCheck: - yield Result(self, constants.ERROR, key=file, - msg='Code format is incorrect for file') - -+ umask = current_umask() -+ correct_umask = umask == EXPECTED_UMASK -+ if not correct_umask: -+ yield Result(self, constants.WARNING, type='umask', -+ expected=oct(EXPECTED_UMASK), got=oct(umask), -+ msg='Unexpected umask %s expected %s, ' -+ 'skipping file permissions.' % -+ ('0o' + format(umask, 'o').zfill(3), -+ '0o' + format(EXPECTED_UMASK, 'o').zfill(3))) -+ - for (path, owner, group, mode) in process_files: - if not isinstance(owner, tuple): - owner = tuple((owner,)) -@@ -58,7 +81,7 @@ class FileCheck: - stat = os.stat(path) - fmode = str(oct(stat.st_mode)[-4:]) - key = '%s_mode' % path.replace('/', '_') -- if fmode not in mode: -+ if correct_umask and fmode not in mode: - if len(mode) == 1: - modes = mode[0] - else: -diff --git a/tests/test_core_files.py b/tests/test_core_files.py -index d308410..094305a 100644 ---- a/tests/test_core_files.py -+++ b/tests/test_core_files.py -@@ -9,7 +9,7 @@ from util import m_api - from util import capture_results - - from ipahealthcheck.core import config --from ipahealthcheck.core.files import FileCheck -+from ipahealthcheck.core.files import EXPECTED_UMASK, FileCheck - from ipahealthcheck.core import constants - from ipahealthcheck.core.plugin import Results - from ipahealthcheck.ipa.files import IPAFileCheck -@@ -303,3 +303,20 @@ def test_ipa_files_format(mock_pkinit): - - for result in results.results: - assert result.result in (constants.SUCCESS, constants.WARNING) -+ -+ -+@patch('os.umask') -+def test_bad_umask(mock_umask): -+ mock_umask.return_value = 0o027 -+ -+ f = FileCheck() -+ f.files = files -+ -+ results = capture_results(f) -+ my_results = get_results(results, 'umask') -+ assert my_results.results[0].result == constants.WARNING -+ assert my_results.results[0].kw.get('got') == oct(0o027) -+ assert my_results.results[0].kw.get('expected') == oct(EXPECTED_UMASK) -+ assert my_results.results[0].kw.get('type') == 'umask' -+ assert my_results.results[0].kw.get('msg') == \ -+ 'Unexpected umask 0o027 expected 0o022, skipping file permissions.' --- -2.49.0 - diff --git a/0012-Don-t-rely-on-order-in-trust-agent-controller-role-c.patch b/0012-Don-t-rely-on-order-in-trust-agent-controller-role-c.patch deleted file mode 100644 index 8c4b7c9..0000000 --- a/0012-Don-t-rely-on-order-in-trust-agent-controller-role-c.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 57cda16e67c5b5b5972452b8623534b0a567a264 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 23 Jun 2025 16:07:34 -0400 -Subject: [PATCH] Don't rely on order in trust agent/controller role check - -The code expected that the local server would always be the -first one returned. Instead loop through the returned list -to find the current server and set the state based on that. - -Fixes: https://github.com/freeipa/freeipa-healthcheck/issues/356 - -Signed-off-by: Rob Crittenden ---- - src/ipahealthcheck/ipa/plugin.py | 15 ++++--- - tests/test_ipa_trust.py | 71 +++++++++++++++++++++++++++++++- - 2 files changed, 79 insertions(+), 7 deletions(-) - -diff --git a/src/ipahealthcheck/ipa/plugin.py b/src/ipahealthcheck/ipa/plugin.py -index f1a325c..efaa947 100644 ---- a/src/ipahealthcheck/ipa/plugin.py -+++ b/src/ipahealthcheck/ipa/plugin.py -@@ -35,6 +35,13 @@ class IPARegistry(Registry): - self.trust_controller = False - self.ca_configured = False - -+ def has_role(self, roles): -+ for role in roles: -+ if role.get('server_server') == api.env.host: -+ if role.get('status') == 'enabled': -+ return True -+ return False -+ - def initialize(self, framework, config, options=None): - super().initialize(framework, config) - # deferred import for mock -@@ -81,12 +88,8 @@ class IPARegistry(Registry): - component_services=['ADTRUST'] - ), - ) -- role = roles[0].status(api)[0] -- if role.get('status') == 'enabled': -- self.trust_agent = True -- role = roles[1].status(api)[0] -- if role.get('status') == 'enabled': -- self.trust_controller = True -+ self.trust_agent = self.has_role(roles[0].status(api)) -+ self.trust_controller = self.has_role(roles[1].status(api)) - - - registry = IPARegistry() -diff --git a/tests/test_ipa_trust.py b/tests/test_ipa_trust.py -index 6c4754a..0faa702 100644 ---- a/tests/test_ipa_trust.py -+++ b/tests/test_ipa_trust.py -@@ -11,7 +11,8 @@ from util import capture_results - from util import m_api - - from ipahealthcheck.core import config, constants --from ipahealthcheck.ipa.plugin import registry -+from ipahealthcheck.core.plugin import Results -+from ipahealthcheck.ipa.plugin import registry, IPARegistry - from ipahealthcheck.ipa.trust import (IPATrustAgentCheck, - IPATrustDomainsCheck, - IPADomainCheck, -@@ -1287,3 +1288,71 @@ class TestPackageCheck(BaseTest): - assert result.source == 'ipahealthcheck.ipa.trust' - assert result.check == 'IPATrustPackageCheck' - sys.modules['ipaserver.install'] = save -+ -+ -+class TestHasRole(BaseTest): -+ """Verify that the output of server-role-find which is used to -+ determine whether a host is a trust agent or controller -+ (or neither) isn't dependent upon the order the hosts are -+ returned. -+ -+ Only trust agent is tested here but there is no difference -+ between an agent and a trust in the way they are stored in -+ a server role. -+ """ -+ def test_role_last(self): -+ self.results = Results() -+ reg = IPARegistry() -+ -+ roles = [ -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "replica.ipa.example", -+ "status": "absent", -+ }, -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "server.ipa.example", -+ "status": "enabled", -+ }, -+ ] -+ -+ assert reg.has_role(roles) is True -+ -+ def test_role_first(self): -+ self.results = Results() -+ reg = IPARegistry() -+ -+ roles = [ -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "server.ipa.example", -+ "status": "enabled", -+ }, -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "replica.ipa.example", -+ "status": "absent", -+ }, -+ ] -+ -+ assert reg.has_role(roles) is True -+ -+ def test_no_role(self): -+ self.results = Results() -+ reg = IPARegistry() -+ -+ roles = [ -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "server.ipa.example", -+ "status": "absent", -+ }, -+ { -+ "role_servrole": "AD trust agent", -+ "server_server": "replica.ipa.example", -+ "status": "enabled", -+ }, -+ ] -+ -+ assert reg.has_role(roles) is False --- -2.49.0 - diff --git a/freeipa-healthcheck.spec b/freeipa-healthcheck.spec index 29a2ddb..5895d3d 100644 --- a/freeipa-healthcheck.spec +++ b/freeipa-healthcheck.spec @@ -16,8 +16,8 @@ %bcond_without tests Name: %{prefix}-healthcheck -Version: 0.16 -Release: 9%{?dist} +Version: 0.19 +Release: 1%{?dist} Summary: Health check tool for %{productname} BuildArch: noarch License: GPLv3 @@ -26,17 +26,6 @@ Source0: https://github.com/freeipa/freeipa-healthcheck/archive/%{version Source1: ipahealthcheck.conf Patch0001: 0001-Remove-ipaclustercheck.patch -Patch0002: 0002-Don-t-fail-if-a-service-name-cannot-be-looked-up-in-.patch -Patch0003: 0003-Temporarily-disable-the-ipa-ods-exporter-service-sta.patch -Patch0004: 0004-Skip-DogtagCertsConfigCheck-for-PKI-versions-11.5.0.patch -Patch0005: 0005-test-Handle-PKI-11.5.0-not-storing-certs-in-CS.cfg.patch -Patch0006: 0006-Fixes-log-file-permissions-as-per-CIS-benchmark.patch -Patch0007: 0007-Fix-some-file-mode-format-issues.patch -Patch0008: 0008-Allow-WARNING-in-the-files-test.patch -Patch0009: 0009-Check-user-provided-certificates-for-expiration.patch -Patch0010: 0010-Warn-if-krbLastSuccessfulAuth-replication-is-enabled.patch -Patch0011: 0011-Warn-about-unexpected-umask.patch -Patch0012: 0012-Don-t-rely-on-order-in-trust-agent-controller-role-c.patch Requires: %{name}-core = %{version}-%{release} Requires: %{prefix}-server @@ -166,6 +155,13 @@ PYTHONPATH=src PATH=$PATH:$RPM_BUILD_ROOT/usr/bin pytest-3 tests/test_* %changelog +* Tue Sep 23 2025 Rob Crittenden - 0.19-1 +- Update to 0.19 release + - Add a message if not a trust agent/controller (RHEL-116896) + - Check that expected NSS token matches the current FIPS state (RHEL-116897) + - Add /etc/pki/tls/certs/ directory to file checker (RHEL-116898) + - Check that allowed_uids in the SSSD config is valid (RHEL-79092) + * Mon Jun 30 2025 Rob Crittenden - 0.16-9 - Don't rely on order in trust roles (RHEL-99531) diff --git a/sources b/sources index fe926f0..a7cf3f7 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (0.16.tar.gz) = d1be0159773e0dd663a9c6dfea586fdba01a88ac1ab0e6a13459fc563b4ef814ac3c2597ad7a0bd1ef2132eb54fe9020f46726465d7cfaf3c5a124894296f2eb +SHA512 (0.19.tar.gz) = 7f40e9451c4207f4bbb02644ba8abd14eed3b818227f6ad5c5957487a4a401f294f2f8d57a663f06d84b6926864baec0494d88ae02542aa15eef08ff001da734