Add validators module

This commit is contained in:
2026-01-29 21:26:30 +00:00
parent e4876502eb
commit 12f14232d9

View File

@@ -1,64 +1,35 @@
"""Pattern-based dangerous command detection."""
from typing import List, Optional
from ..models import Rule, Finding
class PatternValidator:
"""Validates shell scripts for dangerous command patterns."""
DEFAULT_PATTERNS = [
Rule(
id="DANGER001",
name="Dangerous rm -rf with variable",
pattern=r"rm\s+-rf?\s+\$\w+",
severity="critical",
id="DANGER001", name="Dangerous rm -rf with variable",
pattern=r"rm\s+-rf?\s+\$\w+", severity="critical",
message="Dangerous deletion command with variable: rm -rf with variables can delete unexpected content",
suggestion="Avoid using variables with rm -rf. Use absolute paths or verify the variable content first.",
),
Rule(
id="DANGER002",
name="Eval with variable",
pattern=r"eval\s+\$\w+",
severity="critical",
id="DANGER002", name="Eval with variable",
pattern=r"eval\s+\$\w+", severity="critical",
message="eval with variable can lead to command injection",
suggestion="Avoid eval with variables. Use safer alternatives like explicit function calls.",
),
Rule(
id="DANGER003",
name="Sudo without full path",
pattern=r"sudo\s+(rm|cp|mv|chmod|chown|useradd|userdel)\s",
severity="critical",
id="DANGER003", name="Sudo without full path",
pattern=r"sudo\s+(rm|cp|mv|chmod|chown|useradd|userdel)\s", severity="critical",
message="sudo command without full path can be exploited",
suggestion="Use full path with sudo, e.g., sudo /bin/rm instead of sudo rm",
),
Rule(
id="DANGER004",
name="Unrestricted pipe to shell",
pattern=r"\|\s*(bash|sh|zsh|fish)\s*(-[a-z]+)?\s*\$\w+",
severity="critical",
message="Pipe to shell with variable can execute arbitrary commands",
suggestion="Avoid piping variables directly to shell interpreters",
),
Rule(
id="DANGER005",
name="Backtick command injection",
pattern=r"`\$\w+`",
severity="critical",
message="Backtick substitution with variable can lead to command injection",
suggestion="Use $() instead of backticks and validate the variable content",
),
]
def __init__(self, custom_rules: Optional[List[Rule]] = None):
"""Initialize the pattern validator with optional custom rules."""
def __init__(self, custom_rules=None):
self.rules = self.DEFAULT_PATTERNS.copy()
if custom_rules:
self.rules.extend(custom_rules)
def validate(self, content: str, line_number: Optional[int] = None) -> List[Finding]:
"""Validate content for dangerous patterns."""
def validate(self, content, line_number=None):
findings = []
for rule in self.rules:
if not rule.enabled:
@@ -68,17 +39,3 @@ class PatternValidator:
finding = Finding.from_match(rule, match, line_number, content)
findings.append(finding)
return findings
def validate_lines(self, lines: List[str]) -> List[Finding]:
"""Validate multiple lines, tracking line numbers."""
findings = []
for line_number, line in enumerate(lines, start=1):
line_findings = self.validate(line, line_number)
for finding in line_findings:
finding.context = line
findings.extend(line_findings)
return findings
def check(self, command: str) -> List[Finding]:
"""Check a single command for dangerous patterns."""
return self.validate(command)