- Hexagonal identity module: domain ports, use cases, argon2id hasher, pg repos - Migration 002_identity: identity_users + identity_sessions (token hash only) - Opaque 512-bit session tokens; DB stores SHA-256 hash; 7-day TTL in SQL - Cookie HttpOnly + Secure (COOKIE_SECURE, default true) + SameSite=Lax - LoginRateLimiter: 10 failures -> 429 + Retry-After, 15-min cooldown - Anti-enumeration: identical generic 401 + dummy-hash timing equalization - buildApp gains optional pool/cookieSecure; foundation-only app preserved - 47 unit + 14 integration tests; live smoke covers all acceptance criteria
29 lines
1.9 KiB
JSON
29 lines
1.9 KiB
JSON
{
|
|
"feature_id": "F-005",
|
|
"agent": "reviewer",
|
|
"verdict": "APPROVED",
|
|
"summary": "Identity module cumple specs/F-005 DESIGN.md: hexagonal real (domain sin framework, ports en domain, infra los implementa), sesiones server-side con token hash en DB, rate limit detrás de interfaz, envelope v2 intacto. Fix de review aplicado (tests COOKIE_SECURE).",
|
|
"checks": {
|
|
"architecture_hexagonal": "PASS: domain no toca framework; application depende de ports; infra implementa; api es adaptador delgado con parseJson",
|
|
"module_boundaries": "PASS: lint:boundaries 39 files OK; identity tests importan solo su subárbol; integración DB vive en src/app/tests (R1/R2)",
|
|
"server_side_authority": "PASS: expiración y revocación de sesión resueltas en SQL; el frontend no decide estado de identidad",
|
|
"naming_convention": "PASS: identity_users / identity_sessions siguen <module>_<table>",
|
|
"migration_reversible": "PASS: down con count:0 (full revert) testeado en integration suite; identity tables + app_meta caen limpias",
|
|
"error_envelope_v2": "PASS: mapeo AppError con codes estables (INVALID_CREDENTIALS, EMAIL_ALREADY_REGISTERED, TOO_MANY_ATTEMPTS); 5xx genérico preservado",
|
|
"test_coverage": "PASS: 47 unit + 14 integration; los 6 AC cubiertos por tests automatizados o evidencia live"
|
|
},
|
|
"findings": [
|
|
{
|
|
"severity": "fixed_in_review",
|
|
"finding": "COOKIE_SECURE (config nueva de F-005) no tenía tests dedicados",
|
|
"resolution": "Test agregado: default true, parse true/false, inválido reporta la variable. Suite verde."
|
|
},
|
|
{
|
|
"severity": "follow_up",
|
|
"finding": "server.ts no tiene graceful shutdown (SIGTERM -> close app + pool.end)",
|
|
"resolution": "Preexistente de F-001/F-003; fuera del scope de identidad. Registrar como mejora de infraestructura."
|
|
}
|
|
],
|
|
"notes": "Rate limiter in-memory por instancia es limitación documentada y aceptada; interfaz permite swap a Redis sin tocar casos de uso."
|
|
}
|