diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman_pgp/config/__init__.py | 36 | ||||
| -rw-r--r-- | src/mailman_pgp/config/config.py | 66 | ||||
| -rw-r--r-- | src/mailman_pgp/config/converter.py | 71 | ||||
| -rw-r--r-- | src/mailman_pgp/config/tests/test_config.py | 34 | ||||
| -rw-r--r-- | src/mailman_pgp/config/tests/test_converter.py | 100 | ||||
| -rw-r--r-- | src/mailman_pgp/config/tests/test_validator.py | 86 | ||||
| -rw-r--r-- | src/mailman_pgp/config/validator.py | 51 | ||||
| -rw-r--r-- | src/mailman_pgp/model/list.py | 3 | ||||
| -rw-r--r-- | src/mailman_pgp/plugin.py | 1 | ||||
| -rw-r--r-- | src/mailman_pgp/runners/incoming.py | 2 | ||||
| -rw-r--r-- | src/mailman_pgp/styles/base.py | 3 | ||||
| -rw-r--r-- | src/mailman_pgp/workflows/key_change.py | 3 |
12 files changed, 314 insertions, 142 deletions
diff --git a/src/mailman_pgp/config/__init__.py b/src/mailman_pgp/config/__init__.py index 13b6eba..7e86f45 100644 --- a/src/mailman_pgp/config/__init__.py +++ b/src/mailman_pgp/config/__init__.py @@ -15,42 +15,10 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see <http://www.gnu.org/licenses/>. -"""Mailman PGP configuration module.""" - -from configparser import ConfigParser - from mailman.config import config as mailman_config -from mailman.utilities.modules import expand_path -from pkg_resources import resource_string -from public.public import public - -from mailman_pgp.config.validator import ConfigValidator - - -@public -class Config(ConfigParser): - """A ConfigParser with a name.""" - - def load(self, name): - """ - Load the plugin configuration, and set our name. - - :param name: The name to set/load configuration for. - :type name: str - """ - self.name = name - self.read(expand_path( - dict(mailman_config.plugin_configs)[self.name].configuration)) - - def validate(self): - """ - - """ - validator = ConfigValidator( - resource_string('mailman_pgp.config', - 'schema.cfg').decode('utf-8')) - validator.validate(self) +from public import public +from mailman_pgp.config.config import Config config = Config() public(config=config) diff --git a/src/mailman_pgp/config/config.py b/src/mailman_pgp/config/config.py new file mode 100644 index 0000000..0b5fe4f --- /dev/null +++ b/src/mailman_pgp/config/config.py @@ -0,0 +1,66 @@ +# Copyright (C) 2017 Jan Jancar +# +# This file is a part of the Mailman PGP plugin. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +"""Mailman PGP configuration module.""" +from configparser import ConfigParser + +from mailman.config import config as mailman_config +from mailman.utilities.modules import expand_path +from pkg_resources import resource_string +from public.public import public + +from mailman_pgp.config.converter import ConfigConverter +from mailman_pgp.config.validator import ConfigValidator + + +@public +class Config(ConfigParser): + """A ConfigParser with a name.""" + + def __init__(self): + super().__init__() + self.name = None + self.dict = None + schema = resource_string('mailman_pgp.config', + 'schema.cfg').decode('utf-8') + self.validator = ConfigValidator(schema) + self.converter = ConfigConverter(schema) + + def load(self, name): + """ + Load the plugin configuration, and set our name. + + :param name: The name to set/load configuration for. + :type name: str + """ + self.name = name + self.read(expand_path( + dict(mailman_config.plugin_configs)[self.name].configuration)) + + def validate(self): + self.validator.validate(self) + + def convert(self): + self.dict = self.converter.convert(self) + + def get_value(self, section, option): + return self.dict[section][option] + + def set(self, section, option, value=None): + self.dict[section][option] = self.converter.converter(section, option)( + value) + return super().set(section, option, value) diff --git a/src/mailman_pgp/config/converter.py b/src/mailman_pgp/config/converter.py new file mode 100644 index 0000000..e3cdb90 --- /dev/null +++ b/src/mailman_pgp/config/converter.py @@ -0,0 +1,71 @@ +# Copyright (C) 2017 Jan Jancar +# +# This file is a part of the Mailman PGP plugin. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +"""Config conversion.""" +import builtins +import re +from configparser import ConfigParser + +from mailman.utilities.modules import find_name + + +class ConfigConverter: + """Converts a ConfigParser object values according to a schema.""" + + def __init__(self, schema): + self.schema = ConfigParser() + self.schema.read_string(schema) + + def convert(self, cfg): + """ + + :param cfg: + :type cfg: ConfigParser + """ + out = dict() + for section in self.schema.sections(): + out[section] = dict() + for option in self.schema.options(section): + out[section][option] = self._transform_option(section, option, + cfg.get(section, + option)) + return out + + def converter(self, section, option): + schema = self.schema.get(section, option) + call = None + try: + call = getattr(builtins, schema) + except: + try: + call = find_name(schema) + except: + if len(schema) != 0: + def call(value): + match = re.search(schema, value) + if match is None: + raise ValueError + return match.group() + return call + + def _transform_option(self, section, option, value): + call = self.converter(section, option) + + if call is None: + raise ValueError + else: + return call(value) diff --git a/src/mailman_pgp/config/tests/test_config.py b/src/mailman_pgp/config/tests/test_config.py index 3ad4ca2..d3ef9ea 100644 --- a/src/mailman_pgp/config/tests/test_config.py +++ b/src/mailman_pgp/config/tests/test_config.py @@ -15,12 +15,15 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see <http://www.gnu.org/licenses/>. +"""""" from unittest import TestCase +from pkg_resources import resource_filename, resource_string + from mailman_pgp.config import config -from mailman_pgp.database import Database -from mailman_pgp.pgp import PGP -from mailman_pgp.testing.layers import PGPConfigLayer +from mailman_pgp.config.config import Config +from mailman_pgp.config.validator import ConfigValidator +from mailman_pgp.testing.layers import PGPConfigLayer, PGPLayer class TestConfig(TestCase): @@ -29,14 +32,21 @@ class TestConfig(TestCase): def test_name(self): self.assertEqual(config.name, 'pgp') - def test_sections(self): - sections = sorted(['db', 'keydirs', 'keypairs', 'queues', 'misc']) - self.assertListEqual(sorted(config.sections()), sections) - def test_db(self): - self.assertTrue(hasattr(config, 'db')) - self.assertIsInstance(config.db, Database) +class TestConfigs(TestCase): + layer = PGPLayer + + def setUp(self): + self.validator = ConfigValidator( + resource_string('mailman_pgp.config', + 'schema.cfg').decode('utf-8')) + + def test_default_config(self): + cfg = Config() + cfg.read(resource_filename('mailman_pgp.config', 'mailman_pgp.cfg')) + self.validator.validate(cfg) - def test_pgp(self): - self.assertTrue(hasattr(config, 'pgp')) - self.assertIsInstance(config.pgp, PGP) + def test_testing_config(self): + cfg = Config() + cfg.read(resource_filename('mailman_pgp.testing', 'mailman_pgp.cfg')) + self.validator.validate(cfg) diff --git a/src/mailman_pgp/config/tests/test_converter.py b/src/mailman_pgp/config/tests/test_converter.py new file mode 100644 index 0000000..842ccc4 --- /dev/null +++ b/src/mailman_pgp/config/tests/test_converter.py @@ -0,0 +1,100 @@ +# Copyright (C) 2017 Jan Jancar +# +# This file is a part of the Mailman PGP plugin. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +"""""" +from unittest import TestCase + +from mailman_pgp.config.config import Config +from mailman_pgp.config.converter import ConfigConverter +from mailman_pgp.testing.layers import PGPLayer + + +class TestConverter(TestCase): + layer = PGPLayer + + def test_builtins(self): + schema = """\ + [test] + test_option: int + """ + converter = ConfigConverter(schema) + valid = Config() + valid.read_string("""\ + [test] + test_option: 5 + """) + invalid = Config() + invalid.read_string("""\ + [test] + test_option: xyz + """) + out = converter.convert(valid) + self.assertEqual(out['test']['test_option'], 5) + self.assertRaises(ValueError, converter.convert, invalid) + + def test_callable(self): + schema = """\ + [test] + test_option: lazr.config.as_boolean + """ + converter = ConfigConverter(schema) + valid = Config() + valid.read_string("""\ + [test] + test_option: yes + """) + invalid = Config() + invalid.read_string("""\ + [test] + test_option: xyz + """) + out = converter.convert(valid) + self.assertEqual(out['test']['test_option'], True) + self.assertRaises(ValueError, converter.convert, invalid) + + def test_regex(self): + schema = """\ + [test] + test_option: 29*4 + """ + converter = ConfigConverter(schema) + valid = Config() + valid.read_string("""\ + [test] + test_option: 2999999994 + """) + invalid = Config() + invalid.read_string("""\ + [test] + test_option: xyz + """) + out = converter.convert(valid) + self.assertEqual(out['test']['test_option'], '2999999994') + self.assertRaises(ValueError, converter.convert, invalid) + + def test_none(self): + schema = """\ + [test] + test_option: + """ + converter = ConfigConverter(schema) + cfg = Config() + cfg.read_string("""\ + [test] + test_option: something + """) + self.assertRaises(ValueError, converter.convert, cfg) diff --git a/src/mailman_pgp/config/tests/test_validator.py b/src/mailman_pgp/config/tests/test_validator.py index d24dfc7..10beba6 100644 --- a/src/mailman_pgp/config/tests/test_validator.py +++ b/src/mailman_pgp/config/tests/test_validator.py @@ -18,100 +18,64 @@ """""" from unittest import TestCase -from pkg_resources import resource_filename, resource_string - -from mailman_pgp.config import Config, ConfigValidator +from mailman_pgp.config.config import Config +from mailman_pgp.config.validator import ConfigValidator from mailman_pgp.testing.layers import PGPLayer -class TestConfigs(TestCase): - layer = PGPLayer - - def setUp(self): - self.validator = ConfigValidator( - resource_string('mailman_pgp.config', - 'schema.cfg').decode('utf-8')) - - def test_default_config(self): - cfg = Config() - cfg.read(resource_filename('mailman_pgp.config', 'mailman_pgp.cfg')) - self.validator.validate(cfg) - - def test_testing_config(self): - cfg = Config() - cfg.read(resource_filename('mailman_pgp.testing', 'mailman_pgp.cfg')) - self.validator.validate(cfg) - - class TestValidator(TestCase): layer = PGPLayer - def test_builtins(self): + def test_missing_section(self): schema = """\ [test] - test_option: int + test_option: something """ validator = ConfigValidator(schema) - valid = Config() - valid.read_string("""\ - [test] - test_option: 5 - """) - invalid = Config() - invalid.read_string("""\ - [test] - test_option: xyz + cfg = Config() + cfg.read_string("""\ + [other_section] + some_option: something else """) - validator.validate(valid) - self.assertRaises(ValueError, validator.validate, invalid) + self.assertRaises(ValueError, validator.validate, cfg) - def test_callable(self): + def test_additional_section(self): schema = """\ [test] - test_option: lazr.config.as_boolean + test_option: something """ validator = ConfigValidator(schema) - valid = Config() - valid.read_string("""\ - [test] - test_option: yes - """) - invalid = Config() - invalid.read_string("""\ + cfg = Config() + cfg.read_string("""\ [test] - test_option: xyz + test_option: something + [other_section] + some_option: something else """) - validator.validate(valid) - self.assertRaises(ValueError, validator.validate, invalid) + self.assertRaises(ValueError, validator.validate, cfg) - def test_regex(self): + def test_missing_option(self): schema = """\ [test] - test_option: 29*4 + test_option: something """ validator = ConfigValidator(schema) - valid = Config() - valid.read_string("""\ - [test] - test_option: 2999999994 - """) - invalid = Config() - invalid.read_string("""\ + cfg = Config() + cfg.read_string("""\ [test] - test_option: xyz """) - validator.validate(valid) - self.assertRaises(ValueError, validator.validate, invalid) + self.assertRaises(ValueError, validator.validate, cfg) - def test_none(self): + def test_additional_option(self): schema = """\ [test] - test_option: + test_option: something """ validator = ConfigValidator(schema) cfg = Config() cfg.read_string("""\ [test] test_option: something + other_option: something else """) self.assertRaises(ValueError, validator.validate, cfg) diff --git a/src/mailman_pgp/config/validator.py b/src/mailman_pgp/config/validator.py index 1010663..51f57d7 100644 --- a/src/mailman_pgp/config/validator.py +++ b/src/mailman_pgp/config/validator.py @@ -15,13 +15,9 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see <http://www.gnu.org/licenses/>. -"""Config validation and transforms.""" -import builtins -import re +"""Config validation.""" from configparser import ConfigParser -from mailman.utilities.modules import find_name - class ConfigValidator: """Validates a ConfigParser object against a schema.""" @@ -36,29 +32,28 @@ class ConfigValidator: :param cfg: :type cfg: ConfigParser """ + errors = [] + additional_sections = set(cfg.sections()).difference( + self.schema.sections()) + + if len(additional_sections) > 0: + errors.append( + 'Additional sections: {}'.format(additional_sections)) + for section in self.schema.sections(): - assert cfg.has_section(section) + if not cfg.has_section(section): + errors.append('Missing config section: {}'.format(section)) + continue for option in self.schema.options(section): - assert cfg.has_option(section, option) - self._check_option(cfg.get(section, option), - self.schema.get(section, option)) - - def _check_option(self, value, schema): - call = None - try: - call = getattr(builtins, schema) - except: - try: - call = find_name(schema) - except: - if len(schema) != 0: - def call(value): - match = re.search(schema, value) - if match is None: - raise ValueError - return match + if not cfg.has_option(section, option): + errors.append( + 'Missing config option {} in {}'.format(option, + section)) + additional_options = set(cfg.options(section)).difference( + self.schema.options(section)) + if len(additional_options) > 0: + errors.append( + 'Additional options: {}'.format(additional_options)) - if call is None: - raise ValueError - else: - return call(value) + if len(errors) > 0: + raise ValueError(errors) diff --git a/src/mailman_pgp/model/list.py b/src/mailman_pgp/model/list.py index 946af34..d80f4a7 100644 --- a/src/mailman_pgp/model/list.py +++ b/src/mailman_pgp/model/list.py @@ -16,7 +16,6 @@ # this program. If not, see <http://www.gnu.org/licenses/>. """Model for PGP enabled mailing lists.""" -from lazr.config import as_boolean from mailman.database.types import Enum, SAUnicode from mailman.interfaces.action import Action from mailman.interfaces.listmanager import (IListManager, ListDeletingEvent) @@ -145,7 +144,7 @@ class PGPMailingList(Base): @classhandler.handler(ListDeletingEvent) def on_delete(event): - shred = as_boolean(config.get('keypairs', 'shred')) + shred = config.get_value('keypairs', 'shred') pgp_list = PGPMailingList.for_list(event.mailing_list) if pgp_list: with transaction() as session: diff --git a/src/mailman_pgp/plugin.py b/src/mailman_pgp/plugin.py index 9824716..7ee31e2 100644 --- a/src/mailman_pgp/plugin.py +++ b/src/mailman_pgp/plugin.py @@ -36,6 +36,7 @@ class PGPMailman: """See `IPlugin`.""" config.load(self.name) config.validate() + config.convert() config.db = Database() config.pgp = PGP() diff --git a/src/mailman_pgp/runners/incoming.py b/src/mailman_pgp/runners/incoming.py index acb079d..9931576 100644 --- a/src/mailman_pgp/runners/incoming.py +++ b/src/mailman_pgp/runners/incoming.py @@ -35,7 +35,7 @@ log = logging.getLogger('mailman.plugin.pgp') def _pass_default(msg, msgdata, listid): - inq = config.get('queues', 'in') + inq = config.get_value('queues', 'in') mailman_config.switchboards[inq].enqueue(msg, msgdata, listid=listid) diff --git a/src/mailman_pgp/styles/base.py b/src/mailman_pgp/styles/base.py index bad67ad..348cb04 100644 --- a/src/mailman_pgp/styles/base.py +++ b/src/mailman_pgp/styles/base.py @@ -16,7 +16,6 @@ # this program. If not, see <http://www.gnu.org/licenses/>. """""" -from lazr.config import as_boolean from public import public from mailman_pgp.config import config, mm_config @@ -42,7 +41,7 @@ class PGPStyle: if pgp_list: return - generate = as_boolean(config.get('keypairs', 'autogenerate')) + generate = config.get_value('keypairs', 'autogenerate') with transaction() as session: pgp_list = PGPMailingList(mailing_list) diff --git a/src/mailman_pgp/workflows/key_change.py b/src/mailman_pgp/workflows/key_change.py index 61acf95..290e504 100644 --- a/src/mailman_pgp/workflows/key_change.py +++ b/src/mailman_pgp/workflows/key_change.py @@ -16,7 +16,6 @@ # this program. If not, see <http://www.gnu.org/licenses/>. """""" -from lazr.config import as_timedelta from mailman.email.message import UserNotification from mailman.interfaces.pending import IPendable, IPendings from mailman.interfaces.subscriptions import TokenOwner @@ -95,7 +94,7 @@ class KeyChangeWorkflow(Workflow): pubkey=str(self.pubkey), fingerprint=self.pubkey.fingerprint ) - lifetime = as_timedelta(config.get('misc', 'change_request_lifetime')) + lifetime = config.get_value('misc', 'change_request_lifetime') self.token = pendings.add(pendable, lifetime=lifetime) self.token_owner = TokenOwner.subscriber |
