Skip to content

Commit

Permalink
convert django debug codemod to use codemod api (#123)
Browse files Browse the repository at this point in the history
* convert django debug codemod to use api

* optimize django debug codemod
  • Loading branch information
clavedeluna authored Nov 9, 2023
1 parent 7aaa51f commit 70f7903
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 83 deletions.
107 changes: 34 additions & 73 deletions src/core_codemods/django_debug_flag_on.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,41 @@
from typing import List
import libcst as cst
from libcst.codemod import Codemod, CodemodContext
from libcst.metadata import PositionProvider
from codemodder.change import Change
from codemodder.codemods.base_visitor import BaseTransformer
from codemodder.codemods.base_codemod import (
SemgrepCodemod,
CodemodMetadata,
ReviewGuidance,
)
from codemodder.file_context import FileContext
from codemodder.codemods.api import SemgrepCodemod
from codemodder.codemods.base_codemod import ReviewGuidance
from codemodder.codemods.utils import is_django_settings_file


class DjangoDebugFlagOn(SemgrepCodemod, Codemod):
METADATA = CodemodMetadata(
DESCRIPTION="Flip `Django` debug flag to off.",
NAME="django-debug-flag-on",
REVIEW_GUIDANCE=ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
REFERENCES=[
{
"url": "https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure",
"description": "",
},
{
"url": "https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-DEBUG",
"description": "",
},
],
)
class DjangoDebugFlagOn(SemgrepCodemod):
NAME = "django-debug-flag-on"
DESCRIPTION = "Flip `Django` debug flag to off."
SUMMARY = "Disable Django Debug Mode"
CHANGE_DESCRIPTION = METADATA.DESCRIPTION
YAML_FILES = [
"django-debug-flag-on.yaml",
REVIEW_GUIDANCE = ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW
REFERENCES = [
{
"url": "https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure",
"description": "",
},
{
"url": "https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-DEBUG",
"description": "",
},
]

METADATA_DEPENDENCIES = (PositionProvider,)

def __init__(self, codemod_context: CodemodContext, *args):
Codemod.__init__(self, codemod_context)
SemgrepCodemod.__init__(self, *args)

def transform_module_impl(self, tree: cst.Module) -> cst.Module:
# checks if the file we looking is a settings.py file from django's default directory structure
if is_django_settings_file(self.file_context.file_path):
debug_flag_transformer = DebugFlagTransformer(
self.context, self.file_context, self.file_context.findings
)
new_tree = debug_flag_transformer.transform_module(tree)
if debug_flag_transformer.changes_in_file:
self.file_context.codemod_changes.extend(
debug_flag_transformer.changes_in_file
)
return new_tree
return tree


class DebugFlagTransformer(BaseTransformer):
def __init__(
self, codemod_context: CodemodContext, file_context: FileContext, results
):
super().__init__(codemod_context, results)
self.line_exclude = file_context.line_exclude
self.line_include = file_context.line_include
self.changes_in_file: List[Change] = []

def leave_Assign(
self, original_node: cst.Assign, updated_node: cst.Assign
) -> cst.Assign:
pos_to_match = self.node_position(original_node)
if self.filter_by_result(
pos_to_match
) and self.filter_by_path_includes_or_excludes(pos_to_match):
line_number = pos_to_match.start.line
self.changes_in_file.append(
Change(line_number, DjangoDebugFlagOn.CHANGE_DESCRIPTION)
)
return updated_node.with_changes(value=cst.Name("False"))
return updated_node
@classmethod
def rule(cls):
return """
rules:
- id: django-debug-flag-on
pattern: DEBUG = True
paths:
include:
- settings.py
"""

def visit_Module(self, _: cst.Module) -> bool:
"""
Only visit module with this codemod if it's a settings.py file.
"""
return is_django_settings_file(self.file_context.file_path)

def on_result_found(self, _, updated_node):
return updated_node.with_changes(value=cst.Name("False"))
10 changes: 0 additions & 10 deletions src/core_codemods/semgrep/django-debug-flag-on.yaml

This file was deleted.

3 changes: 3 additions & 0 deletions tests/codemods/test_django_debug_flag_on.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def test_settings_dot_py(self, tmpdir):
input_code = """DEBUG = True"""
expected = """DEBUG = False"""
self.run_and_assert_filepath(django_root, file_path, input_code, expected)
assert len(self.file_context.codemod_changes) == 1

def test_not_settings_dot_py(self, tmpdir):
django_root, settings_folder = self.create_dir_structure(tmpdir)
Expand All @@ -23,10 +24,12 @@ def test_not_settings_dot_py(self, tmpdir):
input_code = """DEBUG = True"""
expected = input_code
self.run_and_assert_filepath(django_root, file_path, input_code, expected)
assert len(self.file_context.codemod_changes) == 0

def test_no_manage_dot_py(self, tmpdir):
django_root, settings_folder = self.create_dir_structure(tmpdir)
file_path = settings_folder / "settings.py"
input_code = """DEBUG = True"""
expected = input_code
self.run_and_assert_filepath(django_root, file_path, input_code, expected)
assert len(self.file_context.codemod_changes) == 0

0 comments on commit 70f7903

Please sign in to comment.