Modern ERP Reports Application with microservices architecture Tech Stack: - Backend: FastAPI + python-oracledb (Oracle DB integration) - Frontend: Vue.js 3 + PrimeVue + Vite - Telegram Bot: python-telegram-bot + SQLite - Infrastructure: Shared database pool, JWT authentication, SSH tunnel Features: - FastAPI backend with async Oracle connection pool - Vue.js 3 responsive frontend with PrimeVue components - Telegram bot alternative interface - Microservices architecture with shared components - Complete deployment support (Linux Docker + Windows IIS) - Comprehensive testing (Playwright E2E + pytest) Repository Structure: - reports-app/ - Main application (backend, frontend, telegram-bot) - shared/ - Shared components (database pool, auth, utils) - deployment/ - Deployment scripts (Linux & Windows) - docs/ - Project documentation - security/ - Security scanning and git hooks
283 lines
9.1 KiB
Python
283 lines
9.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
🔍 ROA2WEB Security Validation Tool
|
|
Validates that all security measures are properly implemented and functioning.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
class SecurityValidator:
|
|
"""Validates security implementation"""
|
|
|
|
def __init__(self, repo_path: str = "."):
|
|
self.repo_path = Path(repo_path)
|
|
self.errors = []
|
|
self.warnings = []
|
|
self.checks_passed = 0
|
|
self.total_checks = 0
|
|
|
|
def check(self, condition: bool, success_msg: str, error_msg: str, is_warning: bool = False):
|
|
"""Check a condition and track results"""
|
|
self.total_checks += 1
|
|
if condition:
|
|
print(f"✅ {success_msg}")
|
|
self.checks_passed += 1
|
|
else:
|
|
if is_warning:
|
|
print(f"⚠️ {error_msg}")
|
|
self.warnings.append(error_msg)
|
|
else:
|
|
print(f"❌ {error_msg}")
|
|
self.errors.append(error_msg)
|
|
|
|
def validate_files_exist(self):
|
|
"""Validate that all security files exist"""
|
|
print("\n🔍 Checking Security Files...")
|
|
|
|
required_files = [
|
|
"security/secrets_scanner.py",
|
|
"security/git_cleanup.py",
|
|
"security/install_hooks.sh",
|
|
"security/setup_security.sh",
|
|
"security/git_hooks/pre-commit",
|
|
"security/git_hooks/commit-msg",
|
|
"security/README.md",
|
|
"security/SECURITY_PROCEDURES.md"
|
|
]
|
|
|
|
for file_path in required_files:
|
|
full_path = self.repo_path / file_path
|
|
self.check(
|
|
full_path.exists(),
|
|
f"Security file exists: {file_path}",
|
|
f"Missing security file: {file_path}"
|
|
)
|
|
|
|
def validate_gitignore(self):
|
|
"""Validate .gitignore security patterns"""
|
|
print("\n🛡️ Checking .gitignore Security...")
|
|
|
|
gitignore_path = self.repo_path / ".gitignore"
|
|
|
|
if not gitignore_path.exists():
|
|
self.check(False, "", ".gitignore file missing")
|
|
return
|
|
|
|
with open(gitignore_path, 'r') as f:
|
|
gitignore_content = f.read()
|
|
|
|
critical_patterns = [
|
|
"*.env.*",
|
|
"!.env.example",
|
|
"*.pem",
|
|
"*.key",
|
|
"*secret*",
|
|
"*credential*",
|
|
"*password*",
|
|
".serena/cache/",
|
|
".serena/memories/"
|
|
]
|
|
|
|
for pattern in critical_patterns:
|
|
self.check(
|
|
pattern in gitignore_content,
|
|
f"Security pattern in .gitignore: {pattern}",
|
|
f"Missing .gitignore pattern: {pattern}",
|
|
is_warning=True
|
|
)
|
|
|
|
def validate_git_hooks(self):
|
|
"""Validate git hooks installation"""
|
|
print("\n🪝 Checking Git Hooks...")
|
|
|
|
hooks_dir = self.repo_path / ".git" / "hooks"
|
|
|
|
self.check(
|
|
hooks_dir.exists(),
|
|
"Git hooks directory exists",
|
|
"Git hooks directory missing"
|
|
)
|
|
|
|
required_hooks = ["pre-commit", "commit-msg"]
|
|
|
|
for hook in required_hooks:
|
|
hook_path = hooks_dir / hook
|
|
self.check(
|
|
hook_path.exists(),
|
|
f"Git hook installed: {hook}",
|
|
f"Git hook missing: {hook}"
|
|
)
|
|
|
|
if hook_path.exists():
|
|
self.check(
|
|
os.access(hook_path, os.X_OK),
|
|
f"Git hook executable: {hook}",
|
|
f"Git hook not executable: {hook}"
|
|
)
|
|
|
|
def validate_scripts_executable(self):
|
|
"""Validate that scripts are executable"""
|
|
print("\n🔧 Checking Script Permissions...")
|
|
|
|
executable_scripts = [
|
|
"security/secrets_scanner.py",
|
|
"security/git_cleanup.py",
|
|
"security/install_hooks.sh",
|
|
"security/setup_security.sh"
|
|
]
|
|
|
|
for script in executable_scripts:
|
|
script_path = self.repo_path / script
|
|
if script_path.exists():
|
|
self.check(
|
|
os.access(script_path, os.X_OK),
|
|
f"Script executable: {script}",
|
|
f"Script not executable: {script}"
|
|
)
|
|
|
|
def validate_scanner_functionality(self):
|
|
"""Validate scanner can run"""
|
|
print("\n🔍 Testing Security Scanner...")
|
|
|
|
try:
|
|
# Import and test scanner
|
|
sys.path.append(str(self.repo_path))
|
|
import security.secrets_scanner as scanner
|
|
|
|
s = scanner.SecretsScanner(self.repo_path)
|
|
self.check(
|
|
len(s.CRITICAL_PATTERNS) > 0,
|
|
f"Scanner patterns loaded: {len(s.CRITICAL_PATTERNS)} patterns",
|
|
"Scanner patterns not loaded"
|
|
)
|
|
|
|
self.check(
|
|
len(s.SUSPICIOUS_FILES) > 0,
|
|
f"Scanner file patterns loaded: {len(s.SUSPICIOUS_FILES)} patterns",
|
|
"Scanner file patterns not loaded"
|
|
)
|
|
|
|
except Exception as e:
|
|
self.check(
|
|
False,
|
|
"Scanner functionality test passed",
|
|
f"Scanner functionality test failed: {e}"
|
|
)
|
|
|
|
def validate_git_repository(self):
|
|
"""Validate git repository status"""
|
|
print("\n📦 Checking Git Repository...")
|
|
|
|
try:
|
|
# Check if in git repo
|
|
result = subprocess.run(
|
|
['git', 'status'],
|
|
cwd=self.repo_path,
|
|
capture_output=True,
|
|
check=True
|
|
)
|
|
|
|
self.check(
|
|
True,
|
|
"Git repository status OK",
|
|
"Git repository issues detected"
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
self.check(
|
|
False,
|
|
"Git repository status OK",
|
|
"Not in a valid git repository"
|
|
)
|
|
|
|
def check_environment_files(self):
|
|
"""Check for environment files that should be protected"""
|
|
print("\n🔐 Checking Environment Files...")
|
|
|
|
# Find .env files
|
|
env_files = []
|
|
for root, dirs, files in os.walk(self.repo_path):
|
|
for file in files:
|
|
if file.endswith('.env') and not file.endswith('.env.example'):
|
|
rel_path = os.path.relpath(os.path.join(root, file), self.repo_path)
|
|
env_files.append(rel_path)
|
|
|
|
for env_file in env_files:
|
|
# Check if file is in git tracking
|
|
try:
|
|
result = subprocess.run(
|
|
['git', 'ls-files', env_file],
|
|
cwd=self.repo_path,
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
if result.stdout.strip():
|
|
self.check(
|
|
False,
|
|
"",
|
|
f"Environment file tracked in git: {env_file}",
|
|
is_warning=True
|
|
)
|
|
else:
|
|
self.check(
|
|
True,
|
|
f"Environment file properly ignored: {env_file}",
|
|
""
|
|
)
|
|
|
|
except subprocess.CalledProcessError:
|
|
pass
|
|
|
|
def run_validation(self):
|
|
"""Run complete security validation"""
|
|
print("🔒 ROA2WEB Security Validation")
|
|
print("=" * 50)
|
|
|
|
self.validate_files_exist()
|
|
self.validate_gitignore()
|
|
self.validate_git_hooks()
|
|
self.validate_scripts_executable()
|
|
self.validate_scanner_functionality()
|
|
self.validate_git_repository()
|
|
self.check_environment_files()
|
|
|
|
# Print summary
|
|
print("\n" + "=" * 50)
|
|
print("📊 VALIDATION SUMMARY")
|
|
print("=" * 50)
|
|
|
|
print(f"✅ Checks passed: {self.checks_passed}/{self.total_checks}")
|
|
|
|
if self.errors:
|
|
print(f"❌ Errors: {len(self.errors)}")
|
|
for error in self.errors:
|
|
print(f" • {error}")
|
|
|
|
if self.warnings:
|
|
print(f"⚠️ Warnings: {len(self.warnings)}")
|
|
for warning in self.warnings:
|
|
print(f" • {warning}")
|
|
|
|
# Overall status
|
|
if not self.errors:
|
|
if not self.warnings:
|
|
print("\n🎉 VALIDATION PASSED - Security implementation complete!")
|
|
return True
|
|
else:
|
|
print("\n✅ VALIDATION PASSED - Minor warnings noted")
|
|
return True
|
|
else:
|
|
print("\n❌ VALIDATION FAILED - Critical issues found")
|
|
return False
|
|
|
|
def main():
|
|
validator = SecurityValidator()
|
|
success = validator.run_validation()
|
|
sys.exit(0 if success else 1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |