55
66UNSAFE_LOADERS = yaml .loader .__all__ .copy () # type: ignore
77UNSAFE_LOADERS .remove ("SafeLoader" )
8+ loaders = pytest .mark .parametrize ("loader" , UNSAFE_LOADERS )
89
910
1011class TestHardenPyyaml (BaseSemgrepCodemodTest ):
@@ -19,8 +20,9 @@ def test_safe_loader(self, tmpdir):
1920deserialized_data = yaml.load(data, Loader=yaml.SafeLoader)
2021"""
2122 self .run_and_assert (tmpdir , input_code , input_code )
23+ assert len (self .file_context .codemod_changes ) == 0
2224
23- @pytest . mark . parametrize ( "loader" , UNSAFE_LOADERS )
25+ @loaders
2426 def test_all_unsafe_loaders_arg (self , tmpdir , loader ):
2527 input_code = f"""import yaml
2628data = b'!!python/object/apply:subprocess.Popen \\ n- ls'
@@ -32,8 +34,9 @@ def test_all_unsafe_loaders_arg(self, tmpdir, loader):
3234deserialized_data = yaml.load(data, yaml.SafeLoader)
3335"""
3436 self .run_and_assert (tmpdir , input_code , expected )
37+ assert len (self .file_context .codemod_changes ) == 1
3538
36- @pytest . mark . parametrize ( "loader" , UNSAFE_LOADERS )
39+ @loaders
3740 def test_all_unsafe_loaders_kwarg (self , tmpdir , loader ):
3841 input_code = f"""import yaml
3942data = b'!!python/object/apply:subprocess.Popen \\ n- ls'
@@ -45,6 +48,7 @@ def test_all_unsafe_loaders_kwarg(self, tmpdir, loader):
4548deserialized_data = yaml.load(data, Loader=yaml.SafeLoader)
4649"""
4750 self .run_and_assert (tmpdir , input_code , expected )
51+ assert len (self .file_context .codemod_changes ) == 1
4852
4953 def test_import_alias (self , tmpdir ):
5054 input_code = """import yaml as yam
@@ -60,6 +64,7 @@ def test_import_alias(self, tmpdir):
6064deserialized_data = yam.load(data, Loader=yam.SafeLoader)
6165"""
6266 self .run_and_assert (tmpdir , input_code , expected )
67+ assert len (self .file_context .codemod_changes ) == 1
6368
6469 def test_preserve_custom_loader (self , tmpdir ):
6570 expected = input_code = """
@@ -70,6 +75,7 @@ def test_preserve_custom_loader(self, tmpdir):
7075 """
7176
7277 self .run_and_assert (tmpdir , input_code , expected )
78+ assert len (self .file_context .codemod_changes ) == 0
7379
7480 def test_preserve_custom_loader_kwarg (self , tmpdir ):
7581 expected = input_code = """
@@ -80,3 +86,116 @@ def test_preserve_custom_loader_kwarg(self, tmpdir):
8086 """
8187
8288 self .run_and_assert (tmpdir , input_code , expected )
89+ assert len (self .file_context .codemod_changes ) == 0
90+
91+
92+ class TestHardenPyyamlClassInherit (BaseSemgrepCodemodTest ):
93+ codemod = HardenPyyaml
94+
95+ def test_safe_loader (self , tmpdir ):
96+ input_code = """\
97+ import yaml
98+
99+ class MyCustomLoader(yaml.SafeLoader):
100+ def __init__(self, *args, **kwargs):
101+ super(MyCustomLoader, self).__init__(*args, **kwargs)
102+
103+ """
104+
105+ self .run_and_assert (tmpdir , input_code , input_code )
106+ assert len (self .file_context .codemod_changes ) == 0
107+
108+ @loaders
109+ def test_unsafe_loaders (self , tmpdir , loader ):
110+ input_code = f"""\
111+ import yaml
112+
113+ class MyCustomLoader(yaml.{ loader } ):
114+ def __init__(self, *args, **kwargs):
115+ super(MyCustomLoader, self).__init__(*args, **kwargs)
116+ """
117+ expected = """\
118+ import yaml
119+
120+ class MyCustomLoader(yaml.SafeLoader):
121+ def __init__(self, *args, **kwargs):
122+ super(MyCustomLoader, self).__init__(*args, **kwargs)
123+ """
124+ self .run_and_assert (tmpdir , input_code , expected )
125+ assert len (self .file_context .codemod_changes ) == 1
126+
127+ def test_from_import (self , tmpdir ):
128+ input_code = """\
129+ from yaml import UnsafeLoader
130+
131+ class MyCustomLoader(UnsafeLoader):
132+ def __init__(self, *args, **kwargs):
133+ super(MyCustomLoader, self).__init__(*args, **kwargs)
134+ """
135+ expected = """\
136+ from yaml import SafeLoader
137+
138+ class MyCustomLoader(SafeLoader):
139+ def __init__(self, *args, **kwargs):
140+ super(MyCustomLoader, self).__init__(*args, **kwargs)
141+ """
142+ self .run_and_assert (tmpdir , input_code , expected )
143+ assert len (self .file_context .codemod_changes ) == 1
144+
145+ def test_import_alias (self , tmpdir ):
146+ input_code = """\
147+ import yaml as yam
148+
149+ class MyCustomLoader(yam.UnsafeLoader):
150+ def __init__(self, *args, **kwargs):
151+ super(MyCustomLoader, self).__init__(*args, **kwargs)
152+ """
153+ expected = """\
154+ import yaml as yam
155+
156+ class MyCustomLoader(yam.SafeLoader):
157+ def __init__(self, *args, **kwargs):
158+ super(MyCustomLoader, self).__init__(*args, **kwargs)
159+ """
160+ self .run_and_assert (tmpdir , input_code , expected )
161+ assert len (self .file_context .codemod_changes ) == 1
162+
163+ def test_multiple_bases (self , tmpdir ):
164+ input_code = """\
165+ from abc import ABC
166+ import yaml as yam
167+ from whatever import Loader
168+
169+ class MyCustomLoader(ABC, yam.UnsafeLoader, Loader):
170+ def __init__(self, *args, **kwargs):
171+ super(MyCustomLoader, self).__init__(*args, **kwargs)
172+ """
173+ expected = """\
174+ from abc import ABC
175+ import yaml as yam
176+ from whatever import Loader
177+
178+ class MyCustomLoader(ABC, yam.SafeLoader, Loader):
179+ def __init__(self, *args, **kwargs):
180+ super(MyCustomLoader, self).__init__(*args, **kwargs)
181+ """
182+ self .run_and_assert (tmpdir , input_code , expected )
183+ assert len (self .file_context .codemod_changes ) == 1
184+
185+ def test_different_yaml (self , tmpdir ):
186+ input_code = """\
187+ from yaml import UnsafeLoader
188+ import whatever as yaml
189+
190+ class MyLoader(UnsafeLoader, yaml.Loader):
191+ ...
192+ """
193+ expected = """\
194+ from yaml import SafeLoader
195+ import whatever as yaml
196+
197+ class MyLoader(SafeLoader, yaml.Loader):
198+ ...
199+ """
200+ self .run_and_assert (tmpdir , input_code , expected )
201+ assert len (self .file_context .codemod_changes ) == 1
0 commit comments