diff --git a/src/gdiffer/issue_detector.py b/src/gdiffer/issue_detector.py index 7efb08f..36fad45 100644 --- a/src/gdiffer/issue_detector.py +++ b/src/gdiffer/issue_detector.py @@ -21,15 +21,22 @@ class IssueDetector: SECURITY_PATTERNS = [ { - 'pattern': r'(?i)(sql\s*\(|execute\s*\(|exec\s*\(|SELECT\s+|UPDATE\s+|INSERT\s+|DELETE\s+)', + 'pattern': ( + r'(?i)(sql\\s*\\(|execute\\s*\\(|exec\\s*\\(|SELECT\\s+|UPDATE\\s+|' + r'INSERT\\s+|DELETE\\s+)' + ), 'type': 'sql_injection', 'severity': 'critical', 'title': 'Potential SQL Injection', - 'description': 'String concatenation or interpolation used in SQL query', - 'suggestion': 'Use parameterized queries or ORM methods instead of string concatenation', + 'description': ( + 'String concatenation or interpolation used in SQL query' + ), + 'suggestion': ( + 'Use parameterized queries or ORM methods instead of string concatenation' + ), }, { - 'pattern': r'(?i)(innerHTML\s*=|outerHTML\s*=|document\.write\s*\()', + 'pattern': r'(?i)(innerHTML\\s*=|outerHTML\\s*=|document\\.write\\s*\\()', 'type': 'xss', 'severity': 'critical', 'title': 'Potential XSS Vulnerability', @@ -37,7 +44,7 @@ class IssueDetector: 'suggestion': 'Use textContent or sanitize HTML before insertion', }, { - 'pattern': r'(?i)(eval\s*\(|setTimeout\s*\(\s*['"]|setInterval\s*\(\s*['"])', + 'pattern': r'(?i)(eval\\s*\\(|setTimeout\\s*\\(\\s*[\\'\\"]|setInterval\\s*\\(\\s*[\\'\\"])', 'type': 'code_injection', 'severity': 'critical', 'title': 'Code Injection Risk', @@ -45,7 +52,7 @@ class IssueDetector: 'suggestion': 'Avoid eval() and dynamic code execution when possible', }, { - 'pattern': r'(?i)(os\.system\s*\(|subprocess\.|shell=True|popen)', + 'pattern': r'(?i)(os\\.system\\s*\\(|subprocess\\.|shell=True|popen)', 'type': 'command_injection', 'severity': 'critical', 'title': 'Command Injection Risk', @@ -53,7 +60,7 @@ class IssueDetector: 'suggestion': 'Use subprocess with shell=False and validate/sanitize inputs', }, { - 'pattern': r'(?i)(password\s*=|passwd\s*=|secret\s*=|token\s*=|api_key\s*=)', + 'pattern': r'(?i)(password\\s*=|passwd\\s*=|secret\\s*=|token\\s*=|api_key\\s*=)', 'type': 'hardcoded_secret', 'severity': 'high', 'title': 'Hardcoded Secret Detected', @@ -69,7 +76,7 @@ class IssueDetector: 'suggestion': 'Use HTTPS for all network communications', }, { - 'pattern': r'(?i)(random\.randint\s*\(|random\.random\s*\()', + 'pattern': r'(?i)(random\\.randint\\s*\\(|random\\.random\\s*\\()', 'type': 'weak_crypto', 'severity': 'medium', 'title': 'Weak Random Number Generator', @@ -80,7 +87,7 @@ class IssueDetector: BUG_PATTERNS = [ { - 'pattern': r'(?i)(if\s*\([^)]*==[^)]*\)\s*:|if\s*\([^)]*=\s*[^)]*\)\s*:)', + 'pattern': r'(?i)(if\\s*\\([^)]*==[^)]*\\)\\s*:|if\\s*\\([^)]*=\\s*[^)]*\\)\\s*:)', 'type': 'assignment_in_condition', 'severity': 'high', 'title': 'Assignment in Condition', @@ -88,7 +95,7 @@ class IssueDetector: 'suggestion': 'Use == for comparison, not =', }, { - 'pattern': r'(?i)(\bNone\b.*==|==.*\bNone\b)', + 'pattern': r'(?i)(\\bNone\\b.*==|==.*\\bNone\\b)', 'type': 'none_comparison', 'severity': 'medium', 'title': 'Direct None Comparison', @@ -96,7 +103,7 @@ class IssueDetector: 'suggestion': 'Use "is None" for None comparisons in Python', }, { - 'pattern': r'\bexcept\s*:\s*$', + 'pattern': r'\\bexcept\\s*:\\s*$', 'type': 'bare_except', 'severity': 'medium', 'title': 'Bare Except Clause', @@ -104,7 +111,7 @@ class IssueDetector: 'suggestion': 'Catch specific exceptions or at least Exception', }, { - 'pattern': r'(?i)(\.get\s*\(\s*['"]?\s*['"]?\s*\))', + 'pattern': r'(?i)(\\.get\\s*\\(\\s*[\\'\\"]?\\s*[\\'\\"]?\\s*\\))', 'type': 'unused_get', 'severity': 'low', 'title': 'Dictionary get() with no default', @@ -115,7 +122,7 @@ class IssueDetector: CODE_SMELL_PATTERNS = [ { - 'pattern': r'^\s*for\s+.*\s+in\s+.*:\s*$', + 'pattern': r'^\\s*for\\s+.*\\s+in\\s+.*:\\s*$', 'type': 'long_loop', 'severity': 'low', 'title': 'Complex Loop', @@ -123,7 +130,7 @@ class IssueDetector: 'suggestion': 'Consider using list comprehensions or vectorized operations', }, { - 'pattern': r'(?i)(\bTODO\b|\bFIXME\b|\bHACK\b|\bXXX\b)', + 'pattern': r'(?i)(\\bTODO\\b|\\bFIXME\\b|\\bHACK\\b|\\bXXX\\b)', 'type': 'code_tag', 'severity': 'low', 'title': 'Code Tag Found', @@ -131,7 +138,7 @@ class IssueDetector: 'suggestion': 'Address the TODO or create a ticket to track it', }, { - 'pattern': r'(?i)(\bprint\s*\(|console\.log\s*\()', + 'pattern': r'(?i)(\\bprint\\s*\\(|console\\.log\\s*\\()', 'type': 'debug_statement', 'severity': 'low', 'title': 'Debug Statement', @@ -147,7 +154,7 @@ class IssueDetector: 'suggestion': 'Split long lines for better readability', }, { - 'pattern': r'\bpass\b', + 'pattern': r'\\bpass\\b', 'type': 'empty_block', 'severity': 'low', 'title': 'Empty Code Block', @@ -192,7 +199,9 @@ class IssueDetector: return issues - def detect_diff_issues(self, old_code: str, new_code: str, language: str = "text") -> list[Issue]: + def detect_diff_issues( + self, old_code: str, new_code: str, language: str = "text" + ) -> list[Issue]: """Detect issues specifically in the diff (added/modified lines).""" issues = [] new_lines = new_code.splitlines()