feat: add daily security audit job (07:00 București)

- Add tools/security_audit.py script
- Add security-audit cron job
- Update TOOLS.md with job schedule
This commit is contained in:
Echo
2026-02-03 21:13:16 +00:00
parent 9a6446070a
commit 0ba44b52a0
2 changed files with 129 additions and 0 deletions

View File

@@ -234,6 +234,7 @@ create_event(
| Oră (UTC) | Oră (București) | Job | Canal | Ce face | | Oră (UTC) | Oră (București) | Job | Canal | Ce face |
|-----------|-----------------|-----|-------|---------| |-----------|-----------------|-----|-------|---------|
| 00:00 | 02:00 | content-discovery | - | Caută video+articole pe teme recente → memory/kb/ | | 00:00 | 02:00 | content-discovery | - | Caută video+articole pe teme recente → memory/kb/ |
| 05:00 | 07:00 | security-audit | #echo-work (doar alerte) | Audit securitate zilnic |
| 01:00 | 03:00 | night-execute-late | #echo-work | Continuă execuția task-uri (run 2) | | 01:00 | 03:00 | night-execute-late | #echo-work | Continuă execuția task-uri (run 2) |
| 03:00 | 05:00 | archive-tasks | #echo-work | Arhivează task-uri vechi | | 03:00 | 05:00 | archive-tasks | #echo-work | Arhivează task-uri vechi |
| 06:00,17:00 | 08:00,19:00 | insights-extract | - | Extrage insights din memory/kb/ + actualizează tehnici-pauza.md | | 06:00,17:00 | 08:00,19:00 | insights-extract | - | Extrage insights din memory/kb/ + actualizează tehnici-pauza.md |

128
tools/security_audit.py Executable file
View File

@@ -0,0 +1,128 @@
#!/usr/bin/env python3
"""
Security audit script - verifică zilnic:
1. Permisiuni fișiere sensibile (600)
2. Parole hardcoded în cod
3. Fișiere sensibile în git tracking
4. Porturi expuse neașteptat
Exit codes:
0 = OK
1 = Warnings found
2 = Critical issues found
"""
import os
import sys
import subprocess
from pathlib import Path
CLAWD_DIR = Path(__file__).parent.parent
SENSITIVE_FILES = [".env", "credentials"]
REQUIRED_PERMS = 0o600
REQUIRED_DIR_PERMS = 0o700
issues = []
warnings = []
def check_permissions():
"""Check sensitive files have 600 permissions"""
env_file = CLAWD_DIR / ".env"
if env_file.exists():
mode = env_file.stat().st_mode & 0o777
if mode != REQUIRED_PERMS:
issues.append(f".env has {oct(mode)} permissions (should be 0o600)")
creds_dir = CLAWD_DIR / "credentials"
if creds_dir.exists():
for f in creds_dir.iterdir():
if f.is_file():
mode = f.stat().st_mode & 0o777
if mode != REQUIRED_PERMS:
issues.append(f"credentials/{f.name} has {oct(mode)} (should be 0o600)")
def check_hardcoded_secrets():
"""Scan Python files for potential hardcoded secrets"""
patterns = [
'password.*=.*"[^"]{4,}"',
'api_key.*=.*"[^"]{8,}"',
'secret.*=.*"[^"]{8,}"',
]
for py_file in CLAWD_DIR.rglob("*.py"):
if "venv" in str(py_file) or "__pycache__" in str(py_file):
continue
try:
content = py_file.read_text()
for i, line in enumerate(content.split('\n'), 1):
line_lower = line.lower()
# Skip comments and env reads
if line.strip().startswith('#') or 'os.getenv' in line or 'environ' in line:
continue
# Check for hardcoded passwords (excluding empty strings and placeholders)
if ('password' in line_lower or 'api_pass' in line_lower) and '= "' in line and 'in line' not in line_lower:
if '= ""' not in line and '= "***"' not in line:
# Check if it's actually setting a value, not reading
if 'getenv' not in line and 'environ' not in line:
rel_path = py_file.relative_to(CLAWD_DIR)
warnings.append(f"Potential hardcoded secret in {rel_path}:{i}")
except Exception:
pass
def check_git_tracking():
"""Check if sensitive files are tracked by git"""
try:
result = subprocess.run(
["git", "ls-files", ".env", "credentials/"],
cwd=CLAWD_DIR,
capture_output=True,
text=True
)
if result.stdout.strip():
for f in result.stdout.strip().split('\n'):
issues.append(f"Sensitive file tracked by git: {f}")
except Exception:
pass
def check_gitignore():
"""Verify .gitignore contains sensitive patterns"""
gitignore = CLAWD_DIR / ".gitignore"
if gitignore.exists():
content = gitignore.read_text()
required = [".env", "credentials/"]
for pattern in required:
if pattern not in content:
warnings.append(f"Missing from .gitignore: {pattern}")
def main():
print("🔒 Security Audit - Echo")
print("=" * 40)
check_permissions()
check_hardcoded_secrets()
check_git_tracking()
check_gitignore()
if issues:
print("\n🔴 CRITICAL ISSUES:")
for issue in issues:
print(f" - {issue}")
if warnings:
print("\n🟠 WARNINGS:")
for warning in warnings:
print(f" - {warning}")
if not issues and not warnings:
print("\n✅ All checks passed!")
return 0
print(f"\n📊 Summary: {len(issues)} critical, {len(warnings)} warnings")
if issues:
return 2
return 1
if __name__ == "__main__":
sys.exit(main())