From 65bb5fb01e34aec8c5611005abdd9d0fabd3e9f0 Mon Sep 17 00:00:00 2001 From: vovanbravin Date: Thu, 16 Apr 2026 18:36:28 +0300 Subject: [PATCH 1/2] feat: add new checks in validate_config --- admin/admin.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/admin/admin.py b/admin/admin.py index 584ef7c..e028053 100644 --- a/admin/admin.py +++ b/admin/admin.py @@ -23,12 +23,65 @@ def validate_config(content: bytes) -> list[str]: errors.append("Config file is empty") return errors + if 'global' not in config: + errors.append("Missing required section: 'global'") + else: + if 'rules' not in config['global']: + errors.append("Missing 'global.rules' section") + else: + rules = config['global']['rules'] + + if 'block_categories' in rules and not isinstance(rules['block_categories'], list): + errors.append("global.rules.block_categories must be a list") + + if 'block_domains' in rules and not isinstance(rules['block_domains'], list): + errors.append("global.rules.block_domains must be a list") + + if 'allow_domains' in rules and not isinstance(rules['allow_domains'], list): + errors.append("global.rules.allow_domains must be a list") + + if 'min_trust_level' in rules: + if not isinstance(rules['min_trust_level'], int): + errors.append("global.rules.min_trust_level must be an integer") + elif rules['min_trust_level'] < 0: + errors.append("global.rules.min_trust_level must be >= 0") + + if 'block_by_trust' in rules and not isinstance(rules['block_by_trust'], dict): + errors.append("global.rules.block_by_trust must be a table") + if 'filters' in config: - filter_names = set() - for filter_name in config['filters'].keys(): - if filter_name in filter_names: - errors.append(f"Duplicate filter name: '{filter_name}'") - filter_names.add(filter_name) + if not isinstance(config['filters'], dict): + errors.append("'filters' must be a table") + else: + filter_names = set() + for filter_name in config['filters'].keys(): + if filter_name in filter_names: + errors.append(f"Duplicate filter name: '{filter_name}'") + filter_names.add(filter_name) + + filter_config = config['filters'][filter_name] + if not isinstance(filter_config, dict): + errors.append(f"Filter '{filter_name}' must be a table") + continue + + if 'block_categories' in filter_config and not isinstance(filter_config['block_categories'], list): + errors.append(f"Filter '{filter_name}'.block_categories must be a list") + + if 'block_domains' in filter_config and not isinstance(filter_config['block_domains'], list): + errors.append(f"Filter '{filter_name}'.block_domains must be a list") + + if 'allow_domains' in filter_config and not isinstance(filter_config['allow_domains'], list): + errors.append(f"Filter '{filter_name}'.allow_domains must be a list") + + if 'min_trust_level' in filter_config: + if not isinstance(filter_config['min_trust_level'], int): + errors.append(f"Filter '{filter_name}'.min_trust_level must be an integer") + elif filter_config['min_trust_level'] < 0: + errors.append(f"Filter '{filter_name}'.min_trust_level must be >= 0") + + if 'block_by_trust' in filter_config and not isinstance(filter_config['block_by_trust'], dict): + errors.append(f"Filter '{filter_name}'.block_by_trust must be a table") + return errors class AdminClient: From e01ca1ff08740e4e335c7a207574009143aeeafd Mon Sep 17 00:00:00 2001 From: vovanbravin Date: Fri, 24 Apr 2026 16:33:37 +0300 Subject: [PATCH 2/2] test: add unit test validate_config --- admin/test_validate.py | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 admin/test_validate.py diff --git a/admin/test_validate.py b/admin/test_validate.py new file mode 100644 index 0000000..4201990 --- /dev/null +++ b/admin/test_validate.py @@ -0,0 +1,64 @@ +import unittest +import toml +from admin import validate_config + + +class TestValidateConfig(unittest.TestCase): + + def test_valid_config(self): + config = { + "global": { + "rules": { + "block_categories": ["MALWARE"], + "block_domains": ["youtube.com"], + "allow_domains": ["github.com"], + "min_trust_level": 5, + "block_by_trust": {"SOCIAL": 6} + } + } + } + content = toml.dumps(config).encode('utf-8') + errors = validate_config(content) + self.assertEqual(errors, []) + + def test_empty_config(self): + errors = validate_config(b"") + self.assertIn("Config file is empty", errors) + + def test_invalid_toml(self): + errors = validate_config(b"not valid toml {") + self.assertTrue(any("Invalid TOML" in e for e in errors)) + + def test_missing_global(self): + config = {"filters": {}} + content = toml.dumps(config).encode('utf-8') + errors = validate_config(content) + self.assertIn("Missing required section: 'global'", errors) + + def test_block_categories_not_list(self): + config = { + "global": { + "rules": { + "block_categories": "not a list" + } + } + } + content = toml.dumps(config).encode('utf-8') + errors = validate_config(content) + self.assertIn("global.rules.block_categories must be a list", errors) + + def test_min_trust_level_negative(self): + config = { + "global": { + "rules": { + "min_trust_level": -5 + } + } + } + content = toml.dumps(config).encode('utf-8') + errors = validate_config(content) + self.assertIn("global.rules.min_trust_level must be >= 0", errors) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file