Files
mercadodevida/work/artifacts/CLUB-003/security.json

35 lines
2.6 KiB
JSON

{
"feature_id": "CLUB-003",
"agent": "security",
"stage": "security_gate",
"verdict": "APPROVED",
"security_check": "security",
"summary": "Aprobado: la integración Club/TPV usa consultas parametrizadas, validación UUID en la API POS, y fail-safe para evitar que errores del ledger bloqueen ventas.",
"checks": {
"auth_pos_sale": "OK: POST /pos/sales sigue requiriendo authenticate + requireAnyRole(['admin','pos_manager','pos_cashier']); clubMemberId no es un campo privileged sino un identificador de socio que el cajero introduce en la caja.",
"input_validation": "OK: clubMemberId se valida como UUID en el schema Zod de pos.routes.ts; memberCode en /club/resolve se normaliza con trim() y se verifica como string no vacío antes de buscar.",
"sql_injection": "OK: todas las consultas SQL usan placeholders ($1, $2…); la idempotency_key del ledger se compone de club-earn-${orderId} donde orderId es un UUID del order ya existente.",
"ledger_integrity": "OK: INSERT INTO club_transactions usa ON CONFLICT (idempotency_key) DO NOTHING; si la clave ya existe por una escritura anterior, no se duplica la acumulación.",
"fail_safe": "OK: el bloque de cashback está envuelto en try/catch; si la escritura del ledger falla, la venta continúa y se devuelve sin clubEarnedCents.",
"integer_overflow": "OK: Math.round((totalCents * cashbackBps) / 10_000) es una operación de punto flotante redondeada; el resultado se inserta como integer en balance_delta_cents."
},
"notes": [
"GET /club/resolve es público (sin auth) porque el TPV necesita resolver códigos Club sin sesión backoffice; el código de socio es un identificador público que no expone secretos.",
"El cashback no puede ser negativo porque se calcula solo para ventas COMPLETED con cashbackBps >= 0.",
"loadResult recupera clubEarnedCents del ledger por sale_id para mantener consistencia con la fuente de verdad."
],
"evidence": [
"project/src/modules/club/api/club.routes.ts",
"project/src/modules/club/application/club-service.ts",
"project/src/modules/club/infrastructure/pg-club-repository.ts",
"project/src/modules/pos/application/create-pos-sale.ts",
"project/src/modules/pos/domain/pos-sale.ts",
"rg -n \"clubMemberId|clubEarnedCents|findMemberByCode|resolveByCode|/club/resolve\" project/src/modules/club project/src/modules/pos/application/create-pos-sale.ts",
"cd project && npm run typecheck",
"cd project && npm run build",
"cd project/apps/pos && npm run build",
"./scripts/verify.sh"
],
"timestamp": "2026-08-26T18:15:25Z"
}