-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable use-defusedxml codemod #95
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
[run] | ||
source = codemodder | ||
omit = | ||
*/codemodder/scripts/* | ||
|
||
[paths] | ||
codemodder = | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from core_codemods.use_defused_xml import UseDefusedXml | ||
from integration_tests.base_test import ( | ||
BaseIntegrationTest, | ||
original_and_expected_from_code_path, | ||
) | ||
|
||
|
||
class TestUseDefusedXml(BaseIntegrationTest): | ||
codemod = UseDefusedXml | ||
code_path = "tests/samples/use_defusedxml.py" | ||
|
||
original_code, _ = original_and_expected_from_code_path(code_path, []) | ||
expected_new_code = """\ | ||
from io import StringIO | ||
from xml.etree import ElementInclude # pylint: disable=unused-import | ||
import defusedxml.ElementTree | ||
|
||
xml = StringIO("<root>Hello XML</root>") | ||
et = defusedxml.ElementTree.parse(xml) | ||
""" | ||
|
||
num_changed_files = 2 | ||
expected_diff = """\ | ||
--- | ||
+++ | ||
@@ -1,5 +1,6 @@ | ||
from io import StringIO | ||
-from xml.etree import ElementTree, ElementInclude # pylint: disable=unused-import | ||
+from xml.etree import ElementInclude # pylint: disable=unused-import | ||
+import defusedxml.ElementTree | ||
|
||
xml = StringIO("<root>Hello XML</root>") | ||
-et = ElementTree.parse(xml) | ||
+et = defusedxml.ElementTree.parse(xml) | ||
""" | ||
|
||
expected_line_change = "5" | ||
change_description = UseDefusedXml.CHANGE_DESCRIPTION | ||
|
||
requirements_path = "tests/samples/requirements.txt" | ||
original_requirements = "# file used to test dependency management\nrequests==2.31.0\nblack==23.7.*\nmypy~=1.4\npylint>1\n" | ||
expected_new_reqs = "# file used to test dependency management\nrequests==2.31.0\nblack==23.7.*\nmypy~=1.4\npylint>1\ndefusedxml~=0.7.1\n" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,8 +28,8 @@ def new_requirements(self) -> list[str]: | |
def add(self, dependencies: list[Dependency]): | ||
"""add any number of dependencies to the end of list of dependencies.""" | ||
for dep in dependencies: | ||
if dep not in self.dependencies: | ||
self.dependencies.update({dep.requirement: None}) | ||
if dep.requirement.name not in self.dependencies: | ||
self.dependencies.update({dep.requirement.name: dep.requirement}) | ||
self._new_requirements.append(dep) | ||
|
||
def write(self, dry_run: bool = False) -> Optional[ChangeSet]: | ||
|
@@ -58,7 +58,7 @@ def write(self, dry_run: bool = False) -> Optional[ChangeSet]: | |
if not dry_run: | ||
with open(self.dependency_file, "w", encoding="utf-8") as f: | ||
f.writelines(self._lines) | ||
f.writelines(self.new_requirements) | ||
f.writelines([f"{line}\n" for line in self.new_requirements]) | ||
|
||
self.dependency_file_changed = True | ||
return ChangeSet(str(self.dependency_file), diff, changes=changes) | ||
|
@@ -77,7 +77,7 @@ def dependency_file(self) -> Optional[Path]: | |
return None | ||
|
||
@cached_property | ||
def dependencies(self) -> dict[Requirement, None]: | ||
def dependencies(self) -> dict[str, Requirement]: | ||
""" | ||
Extract list of dependencies from requirements.txt file. | ||
Same order of requirements is maintained, no alphabetical sorting is done. | ||
|
@@ -89,8 +89,10 @@ def dependencies(self) -> dict[Requirement, None]: | |
self._lines = f.readlines() | ||
|
||
return { | ||
Requirement(line): None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the intention here was order preservation? not sure but change LGTM There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that makes sense. We actually don't need that anymore since we preserve the original lines, but we still want to check for the presence of existing dependencies, and we want to do it on the basis of name only (and not version). |
||
requirement.name: requirement | ||
for x in self._lines | ||
# Skip empty lines and comments | ||
if (line := x.strip()) and not line.startswith("#") | ||
if (line := x.strip()) | ||
and not line.startswith("#") | ||
and (requirement := Requirement(line)) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
You might be surprised to learn that Python's standard library XML libraries are | ||
[considered insecure](https://docs.python.org/3/library/xml.html#xml-vulnerabilities) | ||
against various kinds of attacks. | ||
|
||
In fact, the [Python documentation | ||
itself](https://docs.python.org/3/library/xml.html#the-defusedxml-package) | ||
recommends the use of [defusedxml](https://pypi.org/project/defusedxml/) for | ||
parsing untrusted XML data. `defusedxml` is an | ||
[open-source](https://github.com/tiran/defusedxml), permissively licensed | ||
project that is intended as a drop-in replacement for Python's standard library | ||
XML parsers. | ||
|
||
This codemod updates all relevant uses of the standard library parsers with | ||
safe versions from `defusedxml`. It also adds the `defusedxml` dependency to | ||
your project where possible. | ||
|
||
The changes from this codemod look like this: | ||
```diff | ||
- from xml.etree.ElementTree import parse | ||
+ import defusedxml.ElementTree | ||
|
||
- et = parse('data.xml') | ||
+ et = defusedxml.ElementTree.parse('data.xml') | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from io import StringIO | ||
from xml.etree import ElementTree, ElementInclude # pylint: disable=unused-import | ||
|
||
xml = StringIO("<root>Hello XML</root>") | ||
et = ElementTree.parse(xml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can now indent?