@@ -83,10 +83,10 @@ def test_wildcard_summary_and_analysis_share_module_parse(
8383 parse_calls = 0
8484 real_parse = call_graph .ast .parse
8585
86- def tracking_parse (source : str , filename : str = "<unknown>" ) -> ast .Module :
86+ def tracking_parse (source_code : str , filename : str = "<unknown>" ) -> ast .Module :
8787 nonlocal parse_calls
8888 parse_calls += 1
89- return real_parse (source , filename = filename )
89+ return real_parse (source_code , filename = filename )
9090
9191 monkeypatch .setattr (
9292 call_graph , "_resolve_module_source" , lambda module_name : module_path if module_name == "module" else None
@@ -124,6 +124,21 @@ def _env_without_pythonpath() -> dict[str, str]:
124124 return {key : value for key , value in os .environ .items () if key != "PYTHONPATH" }
125125
126126
127+ def _pickle_exec_child_code (body : str ) -> str :
128+ return f"""
129+ import pickle
130+ import sys
131+ from pathlib import Path
132+
133+ module_dir = Path(sys.argv[1])
134+ marker = Path(sys.argv[2])
135+ payload = bytes.fromhex(sys.argv[3])
136+
137+ sys.path.insert(0, str(module_dir))
138+ { body }
139+ """
140+
141+
127142def test_iter_call_nodes_reuses_cached_walk (monkeypatch : pytest .MonkeyPatch ) -> None :
128143 module = ast .parse (
129144 """
@@ -224,9 +239,12 @@ def counting_initial_parameter_controlled_names(
224239def test_split_function_name_reuses_cached_resolution (monkeypatch : pytest .MonkeyPatch ) -> None :
225240 analyze_calls : list [str ] = []
226241
227- def fake_analyze_module (module_name : str ) -> object | None :
242+ class _AnalyzedModule :
243+ pass
244+
245+ def fake_analyze_module (module_name : str ) -> _AnalyzedModule | None :
228246 analyze_calls .append (module_name )
229- return object () if module_name == "pkg.mod" else None
247+ return _AnalyzedModule () if module_name == "pkg.mod" else None
230248
231249 monkeypatch .setattr (call_graph , "_analyze_module" , fake_analyze_module )
232250 call_graph ._split_function_name .cache_clear ()
@@ -1479,20 +1497,13 @@ def test_scan_bytes_ignores_uninvoked_nested_function_body_calls(
14791497
14801498 assert report .verdict == SafetyVerdict .CLEAN
14811499 assert not _has_critical_call_graph_finding (report , module_name , function_name , "subprocess.run" )
1482- child_code = """
1483- import pickle
1484- import sys
1485- from pathlib import Path
1486-
1487- module_dir = Path(sys.argv[1])
1488- marker = Path(sys.argv[2])
1489- payload = bytes.fromhex(sys.argv[3])
1490-
1491- sys.path.insert(0, str(module_dir))
1500+ child_code = _pickle_exec_child_code (
1501+ """
14921502pickle.loads(payload)
14931503if marker.exists():
14941504 raise SystemExit("nested body unexpectedly executed")
14951505"""
1506+ )
14961507 result = _run_python_subprocess (
14971508 [sys .executable , "-c" , child_code , str (module_dir ), str (marker ), payload .hex ()],
14981509 cwd = tmp_path .parent ,
@@ -1529,22 +1540,15 @@ def test_scan_bytes_does_not_treat_newobj_as_init_invocation(
15291540
15301541 assert report .verdict == SafetyVerdict .CLEAN
15311542 assert not _has_critical_call_graph_finding (report , module_name , "InitImports" , "os.system" )
1532- child_code = """
1533- import pickle
1534- import sys
1535- from pathlib import Path
1536-
1537- module_dir = Path(sys.argv[1])
1538- marker = Path(sys.argv[2])
1539- payload = bytes.fromhex(sys.argv[3])
1540-
1541- sys.path.insert(0, str(module_dir))
1543+ child_code = _pickle_exec_child_code (
1544+ """
15421545result = pickle.loads(payload)
15431546if getattr(result, "value", None) != "safe":
15441547 raise SystemExit(f"unexpected state: {result.__dict__!r}")
15451548if marker.exists():
15461549 raise SystemExit("NEWOBJ unexpectedly executed __init__")
15471550"""
1551+ )
15481552 result = _run_python_subprocess (
15491553 [sys .executable , "-c" , child_code , str (module_dir ), str (marker ), payload .hex ()],
15501554 cwd = tmp_path .parent ,
@@ -3642,7 +3646,7 @@ def test_scan_bytes_blocks_itertools_adapter_next_call_iterator_consumption_rce(
36423646
36433647
36443648@pytest .mark .parametrize (
3645- ("payload" , "values_literal" , "expected_repr" , "requires_python311 " ),
3649+ ("payload" , "values_literal" , "expected_repr" , "requires_python_3_11_plus " ),
36463650 [
36473651 (
36483652 _builtins_help_call_iterator_stdlib_materializer_payload ("array" , "array" , _unicode_operand ("i" ), b"h\x00 " ),
@@ -3859,7 +3863,7 @@ def test_scan_bytes_blocks_stdlib_eager_call_iterator_consumption_rce(
38593863 payload : bytes ,
38603864 values_literal : str ,
38613865 expected_repr : str ,
3862- requires_python311 : bool ,
3866+ requires_python_3_11_plus : bool ,
38633867) -> None :
38643868 module_dir = tmp_path / "modules"
38653869 module_dir .mkdir ()
@@ -3891,7 +3895,7 @@ def test_scan_bytes_blocks_stdlib_eager_call_iterator_consumption_rce(
38913895 )
38923896
38933897 assert not marker .exists ()
3894- if requires_python311 and sys .version_info < (3 , 11 ):
3898+ if requires_python_3_11_plus and sys .version_info < (3 , 11 ):
38953899 return
38963900 child_code = """
38973901import ast
@@ -3945,7 +3949,7 @@ def test_scan_bytes_blocks_stdlib_eager_call_iterator_consumption_rce(
39453949
39463950
39473951@pytest .mark .parametrize (
3948- ("payload" , "values_literal" , "expected_repr" , "requires_python311 " ),
3952+ ("payload" , "values_literal" , "expected_repr" , "requires_python_3_11_plus " ),
39493953 [
39503954 (
39513955 _builtins_help_call_iterator_stdlib_materializer_payload (
@@ -3976,7 +3980,7 @@ def test_scan_bytes_blocks_weighted_statistics_call_iterator_consumption_rce(
39763980 payload : bytes ,
39773981 values_literal : str ,
39783982 expected_repr : str ,
3979- requires_python311 : bool ,
3983+ requires_python_3_11_plus : bool ,
39803984) -> None :
39813985 module_dir = tmp_path / "modules"
39823986 module_dir .mkdir ()
@@ -4008,7 +4012,7 @@ def test_scan_bytes_blocks_weighted_statistics_call_iterator_consumption_rce(
40084012 )
40094013
40104014 assert not marker .exists ()
4011- if requires_python311 and sys .version_info < (3 , 11 ):
4015+ if requires_python_3_11_plus and sys .version_info < (3 , 11 ):
40124016 return
40134017
40144018 child_code = """
0 commit comments