BLOQUEAR — No apto para producción
Se detectaron 4 secretos hardcodeados (API keys y contraseñas en texto plano),
múltiples inyecciones SQL por concatenación de strings, y un bloque
except: pass
que silencia errores críticos. Este PR no puede mergearse hasta resolver las incidencias
de seguridad marcadas como CRÍTICO.
82
/ 100 — Nota B
Promedio 3 archivos
4
Secretos expuestos
API keys, passwords en texto plano
6
SQL Injections
Concatenación de strings en queries
24
Code Smells
3 high · 5 medium · 16 low
3
Archivos revisados
Python 3.11 · 669 líneas totales
🚨
Problemas críticos de seguridad
🔑 Secretos hardcodeados detectados — CRÍTICO
- ●
STRIPE_SECRET_KEY = "sk_live_abc123xyz789secretkey"— clave Stripe live en texto plano (línea 21, payment_processor.py) - ●
DB_PASSWORD = "nexuspay_prod_pass_2024"— contraseña de base de datos expuesta (línea 22) - ●
REDIS_PASSWORD = "redis_secret_abc"— credencial Redis en código fuente (línea 23) - ●
WEBHOOK_SECRET = "whsec_live_secret_key_789abc"— webhook secret de Stripe en webhook_handler.py (línea 14)
💉 Inyección SQL por concatenación de strings — ALTO
- ●
cursor.execute("SELECT * FROM customers WHERE id = '" + customer_id + "'")— payment_processor.py:67 - ●
cursor.execute("SELECT * FROM payments WHERE id = '" + payment_id + "'")— payment_processor.py:171 - ● Función
get_payment_historyconstruye query con f-string interpolando parámetros no sanitizados (líneas 185–191) - ●
_check_fraudtambién usa concatenación para query SQL (línea 145)
⚠ Excepción silenciada — ALTO
- ●
except: passen_send_email()— fallos de email se ignoran silenciosamente sin log ni alerta (payment_processor.py:168) - ● Implementar al menos:
except Exception as e: logger.error(f"Email failed: {e}")
📊
Resumen por archivo
📄
Detalle por archivo
🐍 payment_processor.py
253 líneas
8 funciones
1 clase
🔥 Complejidad avg 6.6
C
Smells detectados (13)
medium
Function 'process_payment' tiene 89 líneas — supera el límite de 50
process_payment
medium
Function 'process_payment' tiene complejidad ciclomática 19 — supera límite de 10
process_payment
low
Function 'process_payment' tiene 11 parámetros — máximo recomendado: 5
process_payment
low
Function 'refund_payment' tiene 7 parámetros — usar objeto de request DTO
refund_payment
low
Function 'get_payment_history' tiene 7 parámetros — usar objeto de filtros
get_payment_history
low
Magic number 30000 — usar constante TIMEOUT_MS
línea 43
low
Magic number 86400 — usar constante CACHE_TTL_SECONDS
línea 105
low
Magic number 10000 — usar constante MAX_AMOUNT_FRAUD_THRESHOLD
línea 148
Métricas de funciones
🐍 subscription_manager.py
259 líneas
7 funciones
1 clase
Complejidad avg 6.4
B
Smells detectados (5)
medium
Function 'create_subscription' tiene 62 líneas — refactorizar en helpers privados
create_subscription
medium
Function 'create_subscription' tiene complejidad 12 — separar validación de lógica Stripe
create_subscription
low
Function 'create_subscription' tiene 6 parámetros — usar dataclass SubscriptionRequest
create_subscription
low
Function 'apply_discount' tiene 7 parámetros — consolidar en DiscountRequest DTO
apply_discount
low
Magic number 300 en get_subscription_status — usar constante SUBSCRIPTION_CACHE_TTL
línea 179
🐍 webhook_handler.py
157 líneas
1 función
Complejidad 9.0
B
Smells detectados (6)
medium
Function 'handle_stripe_webhook' tiene 57 líneas — extraer handlers por tipo de evento
handle_stripe_webhook
low
Magic number 400 — usar HTTPStatus.BAD_REQUEST o constante HTTP_400
líneas 32, 34
low
Magic number 86400 — usar constante WEBHOOK_DEDUP_TTL
línea 154
low
Magic numbers 100 (x2) para divisor de centavos — usar constante STRIPE_AMOUNT_DIVISOR
líneas 48, 124
📋
Recomendaciones priorizadas para Carlos
🚫
CRÍTICO: Mover todos los secretos a variables de entorno
Revocar inmediatamente las claves expuestas en el repositorio. Usar
payment_processor.py:21-24 · webhook_handler.py:14
os.environ.get("STRIPE_SECRET_KEY") o un gestor de secretos (AWS Secrets Manager, Doppler). Añadir los nombres de variables a .env.example sin valores reales.💉
CRÍTICO: Eliminar todas las inyecciones SQL
Reemplazar concatenación de strings por parámetros preparados:
payment_processor.py:67, 145, 171, 185-191
cursor.execute("SELECT * FROM customers WHERE id = %s", (customer_id,)). Afecta a todas las queries dinámicas en process_payment, _check_fraud, refund_payment y get_payment_history.🔄
ALTO: Descomponer process_payment (89 líneas, complejidad 19)
Extraer lógica en métodos privados:
payment_processor.py:56-149
_validate_input(), _create_stripe_intent(), _post_payment_tasks(). Usar un dataclass PaymentRequest para reducir los 11 parámetros a 1.🔇
ALTO: Corregir except silencioso en _send_email
El bloque
payment_processor.py:168
except: pass oculta errores de envío de email. Como mínimo: except Exception as e: logger.error("Email send failed", exc_info=True). Considerar también mover email a un servicio asíncrono (Celery/SES).📦
MEDIO: Consolidar parámetros excesivos con DTOs/dataclasses
Funciones con 6-11 parámetros deben agruparse en objetos:
payment_processor.py · subscription_manager.py
@dataclass PaymentRequest, @dataclass RefundRequest, @dataclass SubscriptionRequest. Mejora legibilidad y facilita validación con Pydantic.🧹
BAJO: Definir constantes para todos los magic numbers
Crear un archivo
todos los archivos
constants.py con: CACHE_TTL = 86400, STRIPE_CENTS = 100, FRAUD_THRESHOLD = 75, etc. Elimina ambigüedad y facilita ajustes futuros.