mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-29 16:16:08 +00:00
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>
This commit is contained in:
152
superclaude/validators/runtime_policy.py
Normal file
152
superclaude/validators/runtime_policy.py
Normal file
@@ -0,0 +1,152 @@
|
||||
"""Runtime Policy Validator
|
||||
|
||||
Validates runtime requirements:
|
||||
- Node.js version (LTS, latest, project-specified)
|
||||
- Python version (LTS, latest, project-specified)
|
||||
- Consistency with lockfiles
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
|
||||
from .base import Validator, ValidationResult
|
||||
|
||||
|
||||
class RuntimePolicyValidator(Validator):
|
||||
"""Validates runtime policies"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Runtime Policy")
|
||||
|
||||
def validate(self, context: Dict[str, Any]) -> ValidationResult:
|
||||
"""
|
||||
Validate runtime requirements.
|
||||
|
||||
Context should contain:
|
||||
- contract: Context Contract (for runtime info)
|
||||
- changes: File changes (to detect version changes)
|
||||
"""
|
||||
contract = context.get("contract", {})
|
||||
changes = context.get("changes", {})
|
||||
|
||||
runtime = contract.get("runtime", {})
|
||||
if not runtime:
|
||||
return self._skip("No runtime requirements specified")
|
||||
|
||||
issues = []
|
||||
warnings = []
|
||||
|
||||
# Validate Node.js runtime
|
||||
if "node" in runtime:
|
||||
node_result = self._validate_node_runtime(runtime["node"], changes)
|
||||
issues.extend(node_result.get("issues", []))
|
||||
warnings.extend(node_result.get("warnings", []))
|
||||
|
||||
# Validate Python runtime
|
||||
if "python" in runtime:
|
||||
python_result = self._validate_python_runtime(runtime["python"], changes)
|
||||
issues.extend(python_result.get("issues", []))
|
||||
warnings.extend(python_result.get("warnings", []))
|
||||
|
||||
# Return result
|
||||
if issues:
|
||||
return self._fail(
|
||||
f"Runtime policy violations ({len(issues)} issues)",
|
||||
details={"issues": issues, "warnings": warnings}
|
||||
)
|
||||
|
||||
if warnings:
|
||||
return self._warning(
|
||||
f"Runtime policy warnings ({len(warnings)} warnings)",
|
||||
details={"warnings": warnings}
|
||||
)
|
||||
|
||||
return self._pass("Runtime requirements satisfied")
|
||||
|
||||
def _validate_node_runtime(self, node_config: Dict[str, Any], changes: Dict[str, str]) -> Dict[str, List[str]]:
|
||||
"""Validate Node.js runtime"""
|
||||
issues = []
|
||||
warnings = []
|
||||
|
||||
manager = node_config.get("manager", "npm")
|
||||
source = node_config.get("source", "package-json-defined")
|
||||
|
||||
# Check if package.json specifies engines
|
||||
for file_path, content in changes.items():
|
||||
if "package.json" in file_path:
|
||||
try:
|
||||
data = json.loads(content)
|
||||
engines = data.get("engines", {})
|
||||
node_version = engines.get("node")
|
||||
|
||||
if not node_version and source == "package-json-defined":
|
||||
warnings.append("No Node.js version specified in package.json engines")
|
||||
|
||||
if manager == "pnpm" and "pnpm" not in engines:
|
||||
warnings.append("Using pnpm but no pnpm version in engines")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
issues.append("Invalid package.json format")
|
||||
|
||||
return {"issues": issues, "warnings": warnings}
|
||||
|
||||
def _validate_python_runtime(self, python_config: Dict[str, Any], changes: Dict[str, str]) -> Dict[str, List[str]]:
|
||||
"""Validate Python runtime"""
|
||||
issues = []
|
||||
warnings = []
|
||||
|
||||
manager = python_config.get("manager", "pip")
|
||||
source = python_config.get("source", "pyproject-defined")
|
||||
|
||||
# Check if pyproject.toml specifies python version
|
||||
for file_path, content in changes.items():
|
||||
if "pyproject.toml" in file_path:
|
||||
# Basic check for python version requirement
|
||||
if "requires-python" in content:
|
||||
# Extract version requirement
|
||||
match = re.search(r'requires-python\s*=\s*[\'"]([^"\']+)[\'"]', content)
|
||||
if match:
|
||||
version_spec = match.group(1)
|
||||
# Validate version format
|
||||
if not re.match(r'^[><=~^!]+\d+\.\d+', version_spec):
|
||||
warnings.append(f"Unusual Python version format: {version_spec}")
|
||||
else:
|
||||
warnings.append("Could not parse requires-python version")
|
||||
elif source == "pyproject-defined":
|
||||
warnings.append("No requires-python specified in pyproject.toml")
|
||||
|
||||
return {"issues": issues, "warnings": warnings}
|
||||
|
||||
def get_current_node_version(self) -> Optional[str]:
|
||||
"""Get current Node.js version"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["node", "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=2,
|
||||
check=False
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def get_current_python_version(self) -> Optional[str]:
|
||||
"""Get current Python version"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["python", "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=2,
|
||||
check=False
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
Reference in New Issue
Block a user