aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-08-01 01:00:34 +0200
committerJ08nY2017-08-01 01:00:34 +0200
commit8d4fdb5017bdeee344d9908ddc98b51ae3b7c79b (patch)
treea5d61f909810688d32fda0ba10ce422eccbb5be5
parent8c3ac4d693cfa6138a02bf2d58b98ff62fe4f234 (diff)
parent89e7005f70a7feda03f15cbe39bf866a6f5bd059 (diff)
downloadmailman-pgp-8d4fdb5017bdeee344d9908ddc98b51ae3b7c79b.tar.gz
mailman-pgp-8d4fdb5017bdeee344d9908ddc98b51ae3b7c79b.tar.zst
mailman-pgp-8d4fdb5017bdeee344d9908ddc98b51ae3b7c79b.zip
-rw-r--r--src/mailman_pgp/config/__init__.py36
-rw-r--r--src/mailman_pgp/config/config.py66
-rw-r--r--src/mailman_pgp/config/converter.py71
-rw-r--r--src/mailman_pgp/config/tests/test_config.py34
-rw-r--r--src/mailman_pgp/config/tests/test_converter.py100
-rw-r--r--src/mailman_pgp/config/tests/test_validator.py86
-rw-r--r--src/mailman_pgp/config/validator.py51
-rw-r--r--src/mailman_pgp/model/list.py3
-rw-r--r--src/mailman_pgp/plugin.py1
-rw-r--r--src/mailman_pgp/runners/incoming.py2
-rw-r--r--src/mailman_pgp/styles/base.py3
-rw-r--r--src/mailman_pgp/workflows/key_change.py3
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