22import re
33import os
44from pathlib import Path
5- from openaudit .core .domain import Finding , Severity , Confidence , ScanContext
5+ from openaudit .core .domain import Finding , Severity , Confidence , ScanContext , Rule
66from openaudit .core .interfaces import ScannerProtocol
77
88class TechDebtScanner (ScannerProtocol ):
99 """
1010 Scans for technical debt, leftovers, and temporary code ("Vibe Checks").
11+ Now supports both built-in patterns and custom rules.
1112 """
1213
13- def __init__ (self , rules : Dict = None ):
14+ def __init__ (self , rules : List [Rule ] = None ):
15+ # Built-in patterns (backward compatibility)
1416 self .patterns = {
1517 "ANNOTATION" : {
1618 "pattern" : re .compile (r"(TODO|FIXME|HACK|XXX|BUG):\s*(.*)" , re .IGNORECASE ),
@@ -33,6 +35,23 @@ def __init__(self, rules: Dict = None):
3335 "desc" : "Hardcoded IP address"
3436 }
3537 }
38+
39+ # Custom rules from YAML
40+ self .custom_rules = []
41+ if rules :
42+ # Filter for technical_debt category rules
43+ self .custom_rules = [r for r in rules if r .category in ["technical_debt" , "security" , "general" ]]
44+ self ._compile_custom_rules ()
45+
46+ def _compile_custom_rules (self ):
47+ """Compile regex patterns for custom rules."""
48+ self .compiled_custom_rules = []
49+ for rule in self .custom_rules :
50+ try :
51+ self .compiled_custom_rules .append ((rule , re .compile (rule .regex )))
52+ except re .error as e :
53+ print (f"Warning: Failed to compile regex for rule { rule .id } : { e } " )
54+ pass
3655
3756 def _iterate_files (self , context : ScanContext ):
3857 target = Path (context .target_path )
@@ -79,7 +98,7 @@ def scan_content(self, content: str, file_path: str) -> List[Finding]:
7998 findings = []
8099 lines = content .splitlines ()
81100
82- # Line-by-line scanning
101+ # Scan with built-in patterns
83102 for i , line in enumerate (lines , 1 ):
84103 for key , rule in self .patterns .items ():
85104 match = rule ["pattern" ].search (line )
@@ -103,6 +122,28 @@ def scan_content(self, content: str, file_path: str) -> List[Finding]:
103122 category = "technical_debt" ,
104123 remediation = "Review and clean up code."
105124 ))
125+
126+ # Scan with custom rules
127+ for rule , regex in self .compiled_custom_rules :
128+ for line_num , line in enumerate (lines , 1 ):
129+ for match in regex .finditer (line ):
130+ # Skip if ignore comment is present
131+ if "noqa" in line or "@ignore" in line :
132+ continue
133+
134+ matched_text = match .group (0 ).strip ()[:50 ]
135+ findings .append (Finding (
136+ rule_id = rule .id ,
137+ description = rule .description ,
138+ file_path = file_path ,
139+ line_number = line_num ,
140+ secret_hash = matched_text ,
141+ severity = rule .severity ,
142+ confidence = rule .confidence ,
143+ category = rule .category ,
144+ remediation = rule .remediation
145+ ))
146+
106147 return findings
107148
108149 return findings
0 commit comments