From 17c9a8faf83534fda64d1c77d93ced00d0d1a838 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Fri, 9 Oct 2026 14:26:19 -0700 Subject: [PATCH] test(ssl): certbot re-issue test skips on ANY certbot import/init failure The skip guard caught only ImportError; a half-installed or version-skewed certbot can fail on import with other exceptions (verified with a stub that raises RuntimeError: previously an ERROR, now a skip). new_lineage() itself stays outside the guard - it is the assertion. Co-Authored-By: Claude Opus 5.5 --- scripts/test-cert-write-safety.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/scripts/test-cert-write-safety.py b/scripts/test-cert-write-safety.py index d58c3eb..c89e742 100755 --- a/scripts/test-cert-write-safety.py +++ b/scripts/test-cert-write-safety.py @@ -957,24 +957,31 @@ class TestRetiredLineageCanBeReissued(CertPublishTestCase): def test_certbot_can_issue_the_name_again_after_retirement(self): """Against certbot's own storage code (skipped where certbot is not importable, e.g. the image's app python).""" + # Import AND initialisation are both guarded: a half-installed or + # version-skewed certbot can fail with far more than ImportError (a + # missing transitive dependency, a pkg_resources/entry-point error, a + # moved internal). Any of those means "cannot run this check here", + # not "retirement is broken". new_lineage() itself is NOT inside the + # guard - that is the assertion. try: + import types from certbot._internal import storage - except ImportError: - self.skipTest('certbot not importable from this python') - import types - cfg = types.SimpleNamespace( - config_dir=self.le, renewal_configs_dir=os.path.join(self.le, 'renewal'), - default_archive_dir=os.path.join(self.le, 'archive'), - live_dir=os.path.join(self.le, 'live')) - real_rv = storage.relevant_values + real_rv = storage.relevant_values + new_lineage = storage.RenewableCert.new_lineage + cfg = types.SimpleNamespace( + config_dir=self.le, renewal_configs_dir=os.path.join(self.le, 'renewal'), + default_archive_dir=os.path.join(self.le, 'archive'), + live_dir=os.path.join(self.le, 'live')) + except Exception as e: # noqa: BLE001 - deliberately broad, see above + self.skipTest(f'certbot unusable from this python ({type(e).__name__}: {e})') storage.relevant_values = lambda c: {'server': 'https://acme.invalid/directory'} self.addCleanup(setattr, storage, 'relevant_values', real_rv) cert, key = san('new_bundle.crt').encode(), san('new_bundle.key').encode() - first = storage.RenewableCert.new_lineage('brain-jar.com', cert, key, cert, cfg) + first = new_lineage('brain-jar.com', cert, key, cert, cfg) self.assertEqual('brain-jar.com', first.lineagename) hm.retire_lineage_tree('brain-jar.com') - again = storage.RenewableCert.new_lineage('brain-jar.com', cert, key, cert, cfg) + again = new_lineage('brain-jar.com', cert, key, cert, cfg) self.assertEqual('brain-jar.com', again.lineagename, 'certbot could not re-create the lineage under the same name') self.assertTrue(os.path.getsize(os.path.join(self.le, 'renewal', 'brain-jar.com.conf')) > 0)