mirror of
https://github.com/certbot/certbot.git
synced 2026-06-05 06:42:10 -04:00
This PR is the second part of #6497 to ease the integration, following the new plan propose by @bmw here: #6497 (comment) This PR creates the module certbot.compat.os, that delegates everything to os, and that will be the safeguard against problematic methods of the standard module. On top of that, a quality check wrapper is called in the lint tox environment. This wrapper calls pylint and ensures that standard os module is no used directly in the certbot codebase. Finally local oldest requirements are updated to ensure that tests will take the new logic when running. * Add executable permissions * Add the delegate certbot.compat.os module, add check coding style to enforce usage of certbot.compat.os instead of standard os * Load certbot.compat.os instead of os * Move existing compat test * Update local oldest requirements * Import sys * Update account_test.py * Update os.py * Update os.py * Update local oldest requirements * Implement the new linter_plugin * Fix local oldest for nginx * Remove check coding style * Update linter_plugin.py * Add several comments * Update the setup.py * Add documentation * Update acme dependencies * Update certbot/compat/os.py * Update docs/contributing.rst * Update linter_plugin.py * Handle os.path. Simplify checker. * Add a comment to a reference implementation * Update changelog * Fix module registering * Update docs/contributing.rst * Update config and changelog
316 lines
14 KiB
Python
316 lines
14 KiB
Python
"""Tests for certbot_postfix.installer."""
|
|
import copy
|
|
import functools
|
|
import unittest
|
|
from contextlib import contextmanager
|
|
|
|
import mock
|
|
import pkg_resources
|
|
import six
|
|
from acme.magic_typing import Dict, Tuple # pylint: disable=unused-import,no-name-in-module
|
|
|
|
from certbot import errors
|
|
from certbot.compat import os
|
|
from certbot.tests import util as certbot_test_util
|
|
|
|
|
|
DEFAULT_MAIN_CF = {
|
|
"smtpd_tls_cert_file": "",
|
|
"smtpd_tls_key_file": "",
|
|
"smtpd_tls_dh1024_param_file": "",
|
|
"smtpd_tls_security_level": "none",
|
|
"smtpd_tls_auth_only": "",
|
|
"smtpd_tls_mandatory_protocols": "",
|
|
"smtpd_tls_protocols": "",
|
|
"smtpd_tls_ciphers": "",
|
|
"smtpd_tls_exclude_ciphers": "",
|
|
"smtpd_tls_mandatory_ciphers": "",
|
|
"smtpd_tls_eecdh_grade": "medium",
|
|
"smtp_tls_security_level": "",
|
|
"smtp_tls_ciphers": "",
|
|
"smtp_tls_exclude_ciphers": "",
|
|
"smtp_tls_mandatory_ciphers": "",
|
|
"mail_version": "3.2.3"
|
|
}
|
|
|
|
def _main_cf_with(obj):
|
|
main_cf = copy.copy(DEFAULT_MAIN_CF)
|
|
main_cf.update(obj)
|
|
return main_cf
|
|
|
|
class InstallerTest(certbot_test_util.ConfigTestCase):
|
|
# pylint: disable=too-many-public-methods
|
|
|
|
def setUp(self):
|
|
super(InstallerTest, self).setUp()
|
|
_config_file = pkg_resources.resource_filename("certbot_postfix.tests",
|
|
os.path.join("testdata", "config.json"))
|
|
self.config.postfix_ctl = "postfix"
|
|
self.config.postfix_config_dir = self.tempdir
|
|
self.config.postfix_config_utility = "postconf"
|
|
self.config.postfix_tls_only = False
|
|
self.config.postfix_server_only = False
|
|
self.config.config_dir = self.tempdir
|
|
|
|
@mock.patch("certbot_postfix.installer.util.is_acceptable_value")
|
|
def test_set_vars(self, mock_is_acceptable_value):
|
|
mock_is_acceptable_value.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
mock_is_acceptable_value.return_value = False
|
|
|
|
@mock.patch("certbot_postfix.installer.util.is_acceptable_value")
|
|
def test_acceptable_value(self, mock_is_acceptable_value):
|
|
mock_is_acceptable_value.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
mock_is_acceptable_value.return_value = False
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_confirm_changes_no_raises_error(self, mock_util):
|
|
mock_util().yesno.return_value = False
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertRaises(errors.PluginError, installer.deploy_cert,
|
|
"example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_save(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.postconf.flush = mock.Mock()
|
|
installer.reverter = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.save()
|
|
self.assertEqual(installer.save_notes, [])
|
|
self.assertEqual(installer.postconf.flush.call_count, 1)
|
|
self.assertEqual(installer.reverter.add_to_checkpoint.call_count, 1)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_save_with_title(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.postconf.flush = mock.Mock()
|
|
installer.reverter = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.save(title="new_file!")
|
|
self.assertEqual(installer.reverter.finalize_checkpoint.call_count, 1)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_rollback_checkpoints_resets_postconf(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.rollback_checkpoints()
|
|
self.assertEqual(installer.postconf.get_changes(), {})
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_recovery_routine_resets_postconf(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.recovery_routine()
|
|
self.assertEqual(installer.postconf.get_changes(), {})
|
|
|
|
def test_restart(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.restart()
|
|
self.assertEqual(installer.postfix.restart.call_count, 1) # pylint: disable=no-member
|
|
|
|
def test_add_parser_arguments(self):
|
|
options = set(("ctl", "config-dir", "config-utility",
|
|
"tls-only", "server-only", "ignore-master-overrides"))
|
|
mock_add = mock.MagicMock()
|
|
|
|
from certbot_postfix import installer
|
|
installer.Installer.add_parser_arguments(mock_add)
|
|
|
|
for call in mock_add.call_args_list:
|
|
self.assertTrue(call[0][0] in options)
|
|
|
|
def test_no_postconf_prepare(self):
|
|
with create_installer(self.config) as installer:
|
|
installer_path = "certbot_postfix.installer"
|
|
exe_exists_path = installer_path + ".certbot_util.exe_exists"
|
|
path_surgery_path = "certbot_postfix.util.plugins_util.path_surgery"
|
|
with mock.patch(path_surgery_path, return_value=False):
|
|
with mock.patch(exe_exists_path, return_value=False):
|
|
self.assertRaises(errors.NoInstallationError,
|
|
installer.prepare)
|
|
|
|
def test_old_version(self):
|
|
with create_installer(self.config, main_cf=_main_cf_with({"mail_version": "0.0.1"}))\
|
|
as installer:
|
|
self.assertRaises(errors.NotSupportedError, installer.prepare)
|
|
|
|
def test_lock_error(self):
|
|
with create_installer(self.config) as installer:
|
|
assert_raises = functools.partial(self.assertRaises,
|
|
errors.PluginError,
|
|
installer.prepare)
|
|
certbot_test_util.lock_and_call(assert_raises, self.tempdir)
|
|
|
|
|
|
@mock.patch('certbot.util.lock_dir_until_exit')
|
|
def test_dir_locked(self, lock_dir):
|
|
with create_installer(self.config) as installer:
|
|
lock_dir.side_effect = errors.LockError
|
|
self.assertRaises(errors.PluginError, installer.prepare)
|
|
|
|
def test_more_info(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
output = installer.more_info()
|
|
self.assertTrue("Postfix" in output)
|
|
self.assertTrue(self.tempdir in output)
|
|
self.assertTrue(DEFAULT_MAIN_CF["mail_version"] in output)
|
|
|
|
def test_get_all_names(self):
|
|
config = {"mydomain": "example.org",
|
|
"myhostname": "mail.example.org",
|
|
"myorigin": "example.org"}
|
|
with create_installer(self.config, main_cf=_main_cf_with(config)) as installer:
|
|
installer.prepare()
|
|
result = installer.get_all_names()
|
|
self.assertEqual(result, set(config.values()))
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
from certbot_postfix import constants
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
|
|
# pylint: disable=protected-access
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
changes = installer.postconf.get_changes()
|
|
expected = {} # type: Dict[str, Tuple[str, ...]]
|
|
expected.update(constants.TLS_SERVER_VARS)
|
|
expected.update(constants.DEFAULT_SERVER_VARS)
|
|
expected.update(constants.DEFAULT_CLIENT_VARS)
|
|
self.assertEqual(changes["smtpd_tls_key_file"], "key_path")
|
|
self.assertEqual(changes["smtpd_tls_cert_file"], "cert_path")
|
|
for name, value in six.iteritems(expected):
|
|
self.assertEqual(changes[name], value[0])
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_tls_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: x == "tls_only"
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 4)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_server_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: x == "server_only"
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 11)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_tls_and_server_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: True
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 3)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy_twice(self, mock_util):
|
|
# Deploying twice on the same installer shouldn't do anything!
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
from certbot_postfix.postconf import ConfigMain
|
|
with mock.patch.object(ConfigMain, "set", wraps=installer.postconf.set) as fake_set:
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(fake_set.call_count, 15)
|
|
fake_set.reset_mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertFalse(fake_set.called)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy_already_secure(self, mock_util):
|
|
# Should not overwrite "more-secure" parameters
|
|
mock_util().yesno.return_value = True
|
|
more_secure = {
|
|
"smtpd_tls_security_level": "encrypt",
|
|
"smtpd_tls_protocols": "!SSLv3, !SSLv2, !TLSv1",
|
|
"smtpd_tls_eecdh_grade": "strong"
|
|
}
|
|
with create_installer(self.config,\
|
|
main_cf=_main_cf_with(more_secure)) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
for param in more_secure:
|
|
self.assertFalse(param in installer.postconf.get_changes())
|
|
|
|
def test_enhance(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertRaises(errors.PluginError,
|
|
installer.enhance,
|
|
"example.org", "redirect")
|
|
|
|
def test_supported_enhancements(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertEqual(installer.supported_enhancements(), [])
|
|
|
|
|
|
@contextmanager
|
|
def create_installer(config, main_cf=None):
|
|
"""Creates a Postfix installer with calls to `postconf` and `postfix` mocked out.
|
|
|
|
In particular, creates a ConfigMain object that does regular things, but seeds it
|
|
with values from `main_cf` and `master_cf` dicts.
|
|
"""
|
|
if main_cf is None:
|
|
main_cf = DEFAULT_MAIN_CF
|
|
|
|
from certbot_postfix.postconf import ConfigMain
|
|
from certbot_postfix import installer
|
|
|
|
def _mock_init_postconf(postconf, executable, ignore_master_overrides=False, config_dir=None):
|
|
# pylint: disable=protected-access,unused-argument
|
|
postconf._ignore_master_overrides = ignore_master_overrides
|
|
postconf._db = main_cf
|
|
postconf._master_db = {}
|
|
postconf._updated = {}
|
|
# override get_default to get from main
|
|
postconf.get_default = lambda name: main_cf[name]
|
|
with mock.patch.object(ConfigMain, "__init__", _mock_init_postconf):
|
|
exe_exists_path = "certbot_postfix.installer.certbot_util.exe_exists"
|
|
with mock.patch(exe_exists_path, return_value=True):
|
|
with mock.patch("certbot_postfix.installer.util.PostfixUtil",
|
|
return_value=mock.Mock()):
|
|
yield installer.Installer(config, "postfix")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main() # pragma: no cover
|