Skip to content

Commit f3443f4

Browse files
committed
forbid invalid plugin prefixes in plugin loading
1 parent 3ce7615 commit f3443f4

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/flake8/plugins/finder.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Functions related to finding and loading plugins."""
22
import configparser
33
import inspect
4+
import itertools
45
import logging
6+
import re
57
import sys
68
from typing import Any
79
from typing import Dict
@@ -20,6 +22,8 @@
2022

2123
LOG = logging.getLogger(__name__)
2224

25+
VALID_CODE = re.compile("^[A-Z]{1,3}[0-9]{0,3}$", re.ASCII)
26+
2327
FLAKE8_GROUPS = frozenset(("flake8.extension", "flake8.report"))
2428

2529
BANNED_PLUGINS = {
@@ -328,6 +332,13 @@ def _classify_plugins(
328332
else:
329333
raise NotImplementedError(f"what plugin type? {loaded}")
330334

335+
for loaded in itertools.chain(tree, logical_line, physical_line):
336+
if not VALID_CODE.match(loaded.entry_name):
337+
raise ExecutionError(
338+
f"plugin code for `{loaded.display_name}` does not match "
339+
f"{VALID_CODE.pattern}"
340+
)
341+
331342
return Plugins(
332343
checkers=Checkers(
333344
tree=tree,

tests/unit/plugins/finder_test.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,37 @@ def _loaded(plugin=None, obj=None, parameters=None):
2929
return finder.LoadedPlugin(plugin, obj, parameters)
3030

3131

32+
@pytest.mark.parametrize(
33+
"s",
34+
(
35+
"E",
36+
"E1",
37+
"E123",
38+
"ABC",
39+
"ABC1",
40+
"ABC123",
41+
),
42+
)
43+
def test_valid_plugin_prefixes(s):
44+
assert finder.VALID_CODE.match(s)
45+
46+
47+
@pytest.mark.parametrize(
48+
"s",
49+
(
50+
"",
51+
"A1234",
52+
"ABCD",
53+
"abc",
54+
"a-b",
55+
"☃",
56+
"A𝟗",
57+
),
58+
)
59+
def test_invalid_plugin_prefixes(s):
60+
assert finder.VALID_CODE.match(s) is None
61+
62+
3263
def test_loaded_plugin_entry_name_vs_display_name():
3364
loaded = _loaded(_plugin(package="package-name", ep=_ep(name="Q")))
3465
assert loaded.entry_name == "Q"
@@ -761,6 +792,35 @@ def test_classify_plugins_enable_a_disabled_plugin():
761792
)
762793

763794

795+
def test_classify_plugins_does_not_error_on_reporter_prefix():
796+
# these are ok, don't check their name
797+
plugin = _plugin(ep=_ep(name="report-er", group="flake8.report"))
798+
loaded = _loaded(plugin=plugin)
799+
800+
opts = finder.PluginOptions.blank()
801+
classified = finder._classify_plugins([loaded], opts)
802+
803+
assert classified == finder.Plugins(
804+
checkers=finder.Checkers([], [], []),
805+
reporters={"report-er": loaded},
806+
disabled=[],
807+
)
808+
809+
810+
def test_classify_plugins_errors_on_incorrect_checker_name():
811+
plugin = _plugin(ep=_ep(name="INVALID", group="flake8.extension"))
812+
loaded = _loaded(plugin=plugin, parameters={"tree": True})
813+
814+
with pytest.raises(ExecutionError) as excinfo:
815+
finder._classify_plugins([loaded], finder.PluginOptions.blank())
816+
817+
(msg,) = excinfo.value.args
818+
assert msg == (
819+
"plugin code for `local[INVALID]` "
820+
"does not match ^[A-Z]{1,3}[0-9]{0,3}$"
821+
)
822+
823+
764824
@pytest.mark.usefixtures("reset_sys")
765825
def test_load_plugins():
766826
plugin = _plugin(ep=_ep(value="aplugin:ExtensionTestPlugin2"))

0 commit comments

Comments
 (0)