diff --git a/certbot/main.py b/certbot/main.py index d1ed6fe2b..9d33d6059 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -743,8 +743,14 @@ def main(cli_args=sys.argv[1:]): config = configuration.NamespaceConfig(args) zope.component.provideUtility(config) - log.post_arg_parse_setup(config) - make_or_verify_needed_dirs(config) + try: + log.post_arg_parse_setup(config) + make_or_verify_needed_dirs(config) + except errors.Error: + # Let plugins_cmd be run as un-privileged user. + if config.func != plugins_cmd: + raise + set_displayer(config) # Reporter diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index f0b055d4c..4b9e4cf67 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -545,6 +545,26 @@ class MainTest(test_util.ConfigTestCase): # pylint: disable=too-many-public-met filtered = plugins.visible().ifaces() self.assertEqual(stdout.getvalue().strip(), str(filtered)) + @mock.patch('certbot.main.plugins_disco') + @mock.patch('certbot.main.cli.HelpfulArgumentParser.determine_help_topics') + def test_plugins_no_args_unprivileged(self, _det, mock_disco): + ifaces = [] + plugins = mock_disco.PluginsRegistry.find_all() + + def throw_error(directory, mode, uid, strict): + """Raises error.Error.""" + _, _, _, _ = directory, mode, uid, strict + raise errors.Error() + + with mock.patch('certbot.util.set_up_core_dir') as mock_set_up_core_dir: + mock_set_up_core_dir.side_effect = throw_error + + _, stdout, _, _ = self._call(['plugins']) + plugins.visible.assert_called_once_with() + plugins.visible().ifaces.assert_called_once_with(ifaces) + filtered = plugins.visible().ifaces() + self.assertEqual(stdout.getvalue().strip(), str(filtered)) + @mock.patch('certbot.main.plugins_disco') @mock.patch('certbot.main.cli.HelpfulArgumentParser.determine_help_topics') def test_plugins_init(self, _det, mock_disco):