Files
SuperClaude/superclaude/validators/security_roughcheck.py
kazuki ca29e595fd feat: add comprehensive validation framework
Add validators package with 6 specialized validators:
- base.py: Abstract base validator with common patterns
- context_contract.py: PM mode context validation
- dep_sanity.py: Dependency consistency checks
- runtime_policy.py: Runtime policy enforcement
- security_roughcheck.py: Security vulnerability scanning
- test_runner.py: Automated test execution validation

Supports validation gates for quality assurance and risk mitigation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 03:52:40 +09:00

145 lines
5.0 KiB
Python

"""Security Roughcheck Validator
Detects common security anti-patterns:
- Hardcoded secrets (API keys, tokens, passwords)
- .env file creation in commits
- Exposed credentials in code
- Unsafe practices
"""
from typing import Dict, Any, List
import re
from pathlib import Path
from .base import Validator, ValidationResult
class SecurityRoughcheckValidator(Validator):
"""Validates against common security issues"""
# Secret detection patterns
SECRET_PATTERNS = [
(r'sk_live_[a-zA-Z0-9]{24,}', 'Stripe live secret key'),
(r'pk_live_[a-zA-Z0-9]{24,}', 'Stripe live publishable key'),
(r'sk_test_[a-zA-Z0-9]{24,}', 'Stripe test secret key'),
(r'SUPABASE_SERVICE_ROLE_KEY\s*=\s*[\'"]eyJ', 'Supabase service role key'),
(r'SUPABASE_ANON_KEY\s*=\s*[\'"]eyJ', 'Supabase anon key'),
(r'OPENAI_API_KEY\s*=\s*[\'"]sk-', 'OpenAI API key'),
(r'TWILIO_AUTH_TOKEN\s*=\s*[\'"][a-f0-9]{32}', 'Twilio auth token'),
(r'INFISICAL_TOKEN\s*=\s*[\'"]st\.', 'Infisical token'),
(r'DATABASE_URL\s*=\s*[\'"]postgres.*password', 'Database password in URL'),
(r'AWS_SECRET_ACCESS_KEY\s*=\s*[\'"][\w/+=]{40}', 'AWS secret access key'),
(r'GITHUB_TOKEN\s*=\s*[\'"]gh[ps]_[a-zA-Z0-9]{36}', 'GitHub token'),
]
# Unsafe patterns
UNSAFE_PATTERNS = [
(r'eval\s*\(', 'Use of eval() function'),
(r'exec\s*\(', 'Use of exec() function'),
(r'__import__\s*\(', 'Dynamic import with __import__'),
(r'shell=True', 'Shell command execution'),
(r'pickle\.loads?\s*\(', 'Unsafe pickle deserialization'),
]
def __init__(self):
super().__init__("Security Roughcheck")
def validate(self, context: Dict[str, Any]) -> ValidationResult:
"""
Validate security.
Context should contain:
- changes: File changes
"""
changes = context.get("changes", {})
if not changes:
return self._pass("No changes to validate")
critical_issues = []
warnings = []
for file_path, content in changes.items():
# Check 1: .env file creation
if ".env" in Path(file_path).name:
critical_issues.append(f"❌ CRITICAL: .env file detected: {file_path}")
# Check 2: Hardcoded secrets
for pattern, description in self.SECRET_PATTERNS:
matches = re.findall(pattern, content)
if matches:
critical_issues.append(
f"❌ CRITICAL: {description} detected in {file_path}"
)
# Check 3: Unsafe patterns
for pattern, description in self.UNSAFE_PATTERNS:
matches = re.findall(pattern, content)
if matches:
warnings.append(f"⚠️ {description} in {file_path}")
# Check 4: Exposed API endpoints without auth
if self._looks_like_api_route(file_path):
if not self._has_auth_check(content):
warnings.append(
f"⚠️ Possible unauthenticated API endpoint in {file_path}"
)
# Generate suggestions
suggestions = []
if critical_issues:
suggestions.extend([
"Remove hardcoded secrets immediately",
"Use environment variables or secret management (Infisical)",
"Never commit .env files - add to .gitignore"
])
if warnings:
suggestions.extend([
"Review security warnings carefully",
"Consider safer alternatives where possible"
])
# Return result
if critical_issues:
return self._fail(
f"CRITICAL security issues detected ({len(critical_issues)} issues)",
details={
"critical": critical_issues,
"warnings": warnings
},
suggestions=suggestions
)
if warnings:
return self._warning(
f"Security warnings detected ({len(warnings)} warnings)",
details={"warnings": warnings},
suggestions=suggestions
)
return self._pass("No security issues detected")
def _looks_like_api_route(self, file_path: str) -> bool:
"""Check if file looks like an API route"""
api_indicators = [
"/api/",
"/routes/",
"/endpoints/",
".route.",
".api.",
]
return any(indicator in file_path.lower() for indicator in api_indicators)
def _has_auth_check(self, content: str) -> bool:
"""Check if content has authentication checks"""
auth_patterns = [
r'@auth', # Decorator
r'authenticate',
r'authorize',
r'requireAuth',
r'verifyToken',
r'checkAuth',
r'isAuthenticated',
]
return any(re.search(pattern, content, re.IGNORECASE) for pattern in auth_patterns)