New skills covering 10 categories: **Security & Audit**: 007 (STRIDE/PASTA/OWASP), cred-omega (secrets management) **AI Personas**: Karpathy, Hinton, Sutskever, LeCun (4 sub-skills), Altman, Musk, Gates, Jobs, Buffett **Multi-agent Orchestration**: agent-orchestrator, task-intelligence, multi-advisor **Code Analysis**: matematico-tao (Terence Tao-inspired mathematical code analysis) **Social & Messaging**: Instagram Graph API, Telegram Bot, WhatsApp Cloud API, social-orchestrator **Image Generation**: AI Studio (Gemini), Stability AI, ComfyUI Gateway, image-studio router **Brazilian Domain**: 6 auction specialist modules, 2 legal advisors, auctioneers data scraper **Product & Growth**: design, invention, monetization, analytics, growth engine **DevOps & LLM Ops**: Docker/CI-CD/AWS, RAG/embeddings/fine-tuning **Skill Governance**: installer, sentinel auditor, context management Each skill includes: - Standardized YAML frontmatter (name, description, risk, source, tags, tools) - Structured sections (Overview, When to Use, How it Works, Best Practices) - Python scripts and reference documentation where applicable - Cross-platform compatibility (Claude Code, Antigravity, Cursor, Gemini CLI, Codex CLI) Co-authored-by: ProgramadorBrasil <214873561+ProgramadorBrasil@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
190 lines
7.5 KiB
Python
190 lines
7.5 KiB
Python
"""
|
|
Analyzer de seguranca.
|
|
|
|
Verifica: secrets hardcoded, SQL injection, validacao de input,
|
|
HTTPS enforcement, tokens em logs, padroes de autenticacao.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List, Tuple
|
|
|
|
from config import SECRET_EXCEPTIONS, SECRET_PATTERNS, SQL_INJECTION_PATTERNS
|
|
|
|
|
|
def _check_secrets(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
"""Verifica patterns de secrets hardcoded."""
|
|
findings = []
|
|
for i, line in enumerate(source.splitlines(), 1):
|
|
for pattern in SECRET_PATTERNS:
|
|
if pattern.search(line):
|
|
# Checar se eh excecao conhecida
|
|
is_exception = any(exc in line for exc in SECRET_EXCEPTIONS)
|
|
if is_exception:
|
|
continue
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "security",
|
|
"severity": "critical",
|
|
"category": "hardcoded_secret",
|
|
"title": f"Possivel secret hardcoded em {rel_path}:{i}",
|
|
"description": "Credencial ou token encontrado no codigo-fonte. "
|
|
"Mover para variavel de ambiente.",
|
|
"file_path": rel_path,
|
|
"line_number": i,
|
|
"recommendation": "Usar os.environ.get() ou arquivo .env (nao versionado)",
|
|
"effort": "low",
|
|
"impact": "high",
|
|
})
|
|
return findings
|
|
|
|
|
|
def _check_sql_injection(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
"""Verifica uso de f-strings/format em queries SQL."""
|
|
findings = []
|
|
for i, line in enumerate(source.splitlines(), 1):
|
|
for pattern in SQL_INJECTION_PATTERNS:
|
|
if pattern.search(line):
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "security",
|
|
"severity": "high",
|
|
"category": "sql_injection",
|
|
"title": f"Possivel SQL injection em {rel_path}:{i}",
|
|
"description": "Interpolacao de string em query SQL. Usar queries parametrizadas (?)",
|
|
"file_path": rel_path,
|
|
"line_number": i,
|
|
"recommendation": "Substituir f-string/format por query parametrizada: cursor.execute(sql, [param])",
|
|
"effort": "low",
|
|
"impact": "high",
|
|
})
|
|
return findings
|
|
|
|
|
|
def _check_https(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
"""Verifica se URLs usam HTTP em vez de HTTPS."""
|
|
findings = []
|
|
http_pattern = re.compile(r'["\']http://(?!localhost|127\.0\.0\.1|0\.0\.0\.0)')
|
|
for i, line in enumerate(source.splitlines(), 1):
|
|
if http_pattern.search(line):
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "security",
|
|
"severity": "medium",
|
|
"category": "insecure_http",
|
|
"title": f"URL HTTP insegura em {rel_path}:{i}",
|
|
"description": "Uso de HTTP em vez de HTTPS para comunicacao externa.",
|
|
"file_path": rel_path,
|
|
"line_number": i,
|
|
"recommendation": "Trocar http:// por https://",
|
|
"effort": "low",
|
|
"impact": "medium",
|
|
})
|
|
return findings
|
|
|
|
|
|
def _check_token_in_logs(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
"""Verifica se tokens/secrets aparecem em print/logging."""
|
|
findings = []
|
|
log_pattern = re.compile(
|
|
r'(?:print|logging\.\w+|logger\.\w+)\s*\(.*(?:token|secret|password|key|credential)',
|
|
re.I
|
|
)
|
|
for i, line in enumerate(source.splitlines(), 1):
|
|
if log_pattern.search(line):
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "security",
|
|
"severity": "high",
|
|
"category": "token_in_log",
|
|
"title": f"Possivel token em log em {rel_path}:{i}",
|
|
"description": "Dados sensiveis podem estar sendo logados.",
|
|
"file_path": rel_path,
|
|
"line_number": i,
|
|
"recommendation": "Nao logar tokens/secrets. Usar mascaramento ou remover do log.",
|
|
"effort": "low",
|
|
"impact": "high",
|
|
})
|
|
return findings
|
|
|
|
|
|
def _check_input_validation(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
"""Verifica se argumentos CLI sao validados."""
|
|
findings = []
|
|
# Se usa argparse mas nao tem choices/type/nargs restritivos, e warning leve
|
|
if "argparse" in source and "add_argument" in source:
|
|
# Verificar se ao menos alguns args tem type= ou choices=
|
|
args_count = source.count("add_argument")
|
|
typed_count = len(re.findall(r'add_argument\([^)]*(?:type=|choices=)', source))
|
|
if args_count > 3 and typed_count == 0:
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "security",
|
|
"severity": "low",
|
|
"category": "weak_input_validation",
|
|
"title": f"Validacao fraca de argumentos CLI em {rel_path}",
|
|
"description": f"{args_count} argumentos sem type= ou choices=",
|
|
"file_path": rel_path,
|
|
"recommendation": "Adicionar type= e choices= nos argumentos do argparse",
|
|
"effort": "low",
|
|
"impact": "low",
|
|
})
|
|
return findings
|
|
|
|
|
|
def analyze(skill_data: Dict[str, Any]) -> Tuple[float, List[Dict[str, Any]]]:
|
|
"""Analisa seguranca de uma skill. Retorna (score, findings)."""
|
|
score = 100.0
|
|
findings: List[Dict[str, Any]] = []
|
|
skill_name = skill_data["name"]
|
|
skill_path = Path(skill_data["path"])
|
|
|
|
has_auth_module = False
|
|
uses_env_vars = False
|
|
|
|
for rel_path in skill_data.get("python_files", []):
|
|
filepath = skill_path / rel_path
|
|
if not filepath.exists():
|
|
continue
|
|
|
|
try:
|
|
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
except OSError:
|
|
continue
|
|
|
|
if "auth" in rel_path.lower():
|
|
has_auth_module = True
|
|
if "os.environ" in source or "os.getenv" in source or "dotenv" in source:
|
|
uses_env_vars = True
|
|
|
|
# Checks
|
|
secret_findings = _check_secrets(source, rel_path, skill_name)
|
|
findings.extend(secret_findings)
|
|
score -= len([f for f in secret_findings if f["severity"] == "critical"]) * 20
|
|
score -= len([f for f in secret_findings if f["severity"] == "high"]) * 10
|
|
|
|
sql_findings = _check_sql_injection(source, rel_path, skill_name)
|
|
findings.extend(sql_findings)
|
|
score -= len(sql_findings) * 15
|
|
|
|
https_findings = _check_https(source, rel_path, skill_name)
|
|
findings.extend(https_findings)
|
|
score -= len(https_findings) * 5
|
|
|
|
token_findings = _check_token_in_logs(source, rel_path, skill_name)
|
|
findings.extend(token_findings)
|
|
score -= len(token_findings) * 10
|
|
|
|
input_findings = _check_input_validation(source, rel_path, skill_name)
|
|
findings.extend(input_findings)
|
|
score -= len(input_findings) * 2
|
|
|
|
# Bonus por boas praticas
|
|
if has_auth_module:
|
|
score = min(100.0, score + 5)
|
|
if uses_env_vars:
|
|
score = min(100.0, score + 5)
|
|
|
|
return max(0.0, min(100.0, score)), findings
|