diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index ee0c3a374..b2f1743a3 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -32,11 +32,13 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * `--dns-google-credentials` now supports additional types of file-based credential, such as [External Account Credentials](https://google.aip.dev/auth/4117) created by Workload Identity Federation. All file-based credentials implemented by the Google Auth library are supported. -* ### Fixed * `certbot-dns-google` no longer requires deprecated `oauth2client` library. +* Certbot will no longer try to invoke plugins which do not subclass from the proper + `certbot.interfaces.{Installer,Authenticator}` interface (e.g. `certbot -i standalone` + will now be ignored). See [GH-9664](https://github.com/certbot/certbot/issues/9664). More details about these changes can be found on our GitHub repo. diff --git a/certbot/certbot/_internal/plugins/selection.py b/certbot/certbot/_internal/plugins/selection.py index 708877d3e..4e1bdf7ea 100644 --- a/certbot/certbot/_internal/plugins/selection.py +++ b/certbot/certbot/_internal/plugins/selection.py @@ -112,8 +112,9 @@ def pick_plugin(config: configuration.NamespaceConfig, default: Optional[str], "https://eff.org/letsencrypt-plugins for more detail on what " "the plugins do and how to use them.") - filtered = plugins.visible().ifaces(ifaces) + filtered = plugins.visible() + filtered = filtered.ifaces(ifaces) filtered.init(config) filtered.prepare() prepared = filtered.available() diff --git a/certbot/certbot/_internal/tests/main_test.py b/certbot/certbot/_internal/tests/main_test.py index 8dd4deba1..7f90ee25c 100644 --- a/certbot/certbot/_internal/tests/main_test.py +++ b/certbot/certbot/_internal/tests/main_test.py @@ -356,6 +356,17 @@ class CertonlyTest(unittest.TestCase): self._call('certonly --nginx -d example.com --dry-run'.split()) mock_installer.restart.assert_not_called() + @mock.patch('certbot._internal.main._report_next_steps') + @mock.patch('certbot._internal.main._report_new_cert') + @mock.patch('certbot._internal.main._find_cert') + @mock.patch('certbot._internal.main._get_and_save_cert') + def test_invalid_installer(self, mock_get_cert, mock_find_cert, + unused_report_new, unused_report_next): + mock_get_cert.return_value = mock.MagicMock() + mock_find_cert.return_value = (True, None) + self._call((f'certonly --webroot -w {tempfile.gettempdir()} ' + + '-i standalone -d example.com').split()) + class FindDomainsOrCertnameTest(unittest.TestCase): """Tests for certbot._internal.main._find_domains_or_certname.""" diff --git a/certbot/certbot/_internal/tests/plugins/selection_test.py b/certbot/certbot/_internal/tests/plugins/selection_test.py index 290965544..ee776d1e8 100644 --- a/certbot/certbot/_internal/tests/plugins/selection_test.py +++ b/certbot/certbot/_internal/tests/plugins/selection_test.py @@ -110,6 +110,14 @@ class PickPluginTest(unittest.TestCase): mock_choose.return_value = None assert self._call() is None + def test_default_must_be_filtered(self): + # https://github.com/certbot/certbot/issues/9664 + self.default = "foo" + filtered = mock.MagicMock() + self.reg.filter.return_value = filtered + self._call() + assert filtered.ifaces.call_count == 1 + class ChoosePluginTest(unittest.TestCase): """Tests for certbot._internal.plugins.selection.choose_plugin."""