feat(identity): F-005 register/login/logout with argon2 sessions and rate limiting
- 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
This commit is contained in:
28
work/artifacts/F-005/reviewer.json
Normal file
28
work/artifacts/F-005/reviewer.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"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."
|
||||
}
|
||||
Reference in New Issue
Block a user