test: import-shadow validation covers Import nodes; plain 'import pytest' allowed, aliased spoofs rejected
This commit is contained in:
+31
-16
@@ -666,28 +666,26 @@ def test_dao_matrix_test_file_raw_probes_are_only_constraint_probes() -> None:
|
|||||||
NotIntegrityError and fake.IntegrityError fail).
|
NotIntegrityError and fake.IntegrityError fail).
|
||||||
"""
|
"""
|
||||||
# Names bound to pytest's raises: parse the FILE's actual
|
# Names bound to pytest's raises: parse the FILE's actual
|
||||||
# ImportFrom nodes. A bare Name('raises') is trusted only
|
# Import nodes. A bare Name('raises') is trusted only when
|
||||||
# when an alias binds it from the pytest module (with or
|
# an alias binds it from the pytest module; ANY other import
|
||||||
# without an asname), and only when no other import or
|
# (Import or ImportFrom) binding 'raises', 'pytest', or any
|
||||||
# assignment shadows it anywhere in this file.
|
# raises alias from a non-pytest module fails closed, so a
|
||||||
|
# spoofed module or shadowed alias cannot defeat the check.
|
||||||
raises_bindings: set[str] = set()
|
raises_bindings: set[str] = set()
|
||||||
for file_node in ast.walk(tree):
|
for file_node in ast.walk(tree):
|
||||||
if (
|
|
||||||
isinstance(file_node, ast.ImportFrom)
|
|
||||||
and file_node.module == "pytest"
|
|
||||||
):
|
|
||||||
for alias in file_node.names:
|
|
||||||
if alias.name == "raises":
|
|
||||||
raises_bindings.add(
|
|
||||||
alias.asname or alias.name
|
|
||||||
)
|
|
||||||
for file_node in ast.walk(tree):
|
|
||||||
# Any competing binding of the same names fails closed.
|
|
||||||
if isinstance(file_node, ast.ImportFrom):
|
if isinstance(file_node, ast.ImportFrom):
|
||||||
|
if file_node.module == "pytest":
|
||||||
|
for alias in file_node.names:
|
||||||
|
if alias.name == "raises":
|
||||||
|
raises_bindings.add(
|
||||||
|
alias.asname or alias.name
|
||||||
|
)
|
||||||
|
# Any ImportFrom binding the guarded names from a
|
||||||
|
# non-pytest module fails closed.
|
||||||
for alias in file_node.names:
|
for alias in file_node.names:
|
||||||
bound = alias.asname or alias.name
|
bound = alias.asname or alias.name
|
||||||
if (
|
if (
|
||||||
bound in {"raises", "pytest"}
|
bound in raises_bindings | {"pytest"}
|
||||||
and file_node.module != "pytest"
|
and file_node.module != "pytest"
|
||||||
):
|
):
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
@@ -695,6 +693,23 @@ def test_dao_matrix_test_file_raw_probes_are_only_constraint_probes() -> None:
|
|||||||
f"{file_node.module!r} defeats the "
|
f"{file_node.module!r} defeats the "
|
||||||
"pytest.raises probe validation"
|
"pytest.raises probe validation"
|
||||||
)
|
)
|
||||||
|
elif isinstance(file_node, ast.Import):
|
||||||
|
# import fake_module as pytest (or as anything the
|
||||||
|
# raises machinery trusts) fails closed. A plain
|
||||||
|
# `import pytest` (alias.name == 'pytest', no asname)
|
||||||
|
# is the genuine module binding and is allowed.
|
||||||
|
for alias in file_node.names:
|
||||||
|
bound = alias.asname or alias.name
|
||||||
|
genuine_pytest = (
|
||||||
|
alias.name == "pytest" and alias.asname is None
|
||||||
|
)
|
||||||
|
if bound in raises_bindings | {"pytest"} and (
|
||||||
|
not genuine_pytest
|
||||||
|
):
|
||||||
|
raise AssertionError(
|
||||||
|
f"import shadowing {bound!r} defeats the "
|
||||||
|
"pytest.raises probe validation"
|
||||||
|
)
|
||||||
for sub in ast.walk(node):
|
for sub in ast.walk(node):
|
||||||
if not (
|
if not (
|
||||||
isinstance(sub, ast.With)
|
isinstance(sub, ast.With)
|
||||||
|
|||||||
Reference in New Issue
Block a user