Files
rikrdo 75293f39bc 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
2026-08-14 22:58:32 +02:00

30 lines
2.1 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"feature_id": "F-005",
"agent": "qa",
"verdict": "APPROVED",
"summary": "Los 6 criterios de aceptación pasan con evidencia doble: suite automatizada (47 unit + 14 integration) y smoke live contra PostgreSQL real. Sin regresiones en F-001..F-004.",
"acceptance_criteria": {
"AC1_login_200_with_cookie": "PASS - integration 'login with valid credentials -> 200 + secure cookie' + curl live: HTTP 200 + Set-Cookie mdv_session=...; Max-Age=604800; Path=/; HttpOnly; Secure; SameSite=Lax",
"AC2_wrong_password_401_no_enumeration": "PASS - integration compara bodies .error idénticos para wrong-password vs unknown-email; curl live confirma 401 INVALID_CREDENTIALS genérico en ambos",
"AC3_argon2_never_plaintext": "PASS - integration: fila DB password_hash arranca con $argon2id$ y el plaintext no aparece en ningún valor serializado de la fila",
"AC4_rate_limit_429": "PASS - integration: 10 fallos -> 429 TOO_MANY_ATTEMPTS + Retry-After > 0; live: 401×10 y luego 429 con retry-after: 900",
"AC5_cookie_flags": "PASS - integration valida HttpOnly + SameSite=Lax + Secure + Max-Age sobre el header Set-Cookie; confirmado en vivo",
"AC6_verify_green": "PASS - ./scripts/verify.sh OK tras el cierre de build+gates"
},
"regression": {
"health_endpoint": "PASS (suite)",
"error_envelope_v2_404": "PASS (suite) + foundation-only app sin pool mantiene /auth 404 (integration)",
"config_fail_fast": "PASS (suite: DATABASE_URL missing, COOKIE_SECURE inválido reporta variable)",
"feature_flags": "PASS (suite: unknown OFF, case-insensitive, runtime flip)",
"migrations_lifecycle": "PASS (integration: fresh up full schema, second up no-op, full down limpio)"
},
"evidence": [
"npm run lint / lint:boundaries (39 files) / typecheck / build: clean",
"npm test: 47 passed | 14 skipped",
"npm run test:integration: 14/14 passed",
"curl live: register 201, login 200+cookie, wrong/unknown 401 idénticos, logout 204+clear, 429+Retry-After",
"./scripts/verify.sh: OK"
],
"notes": "Logout smoke verificado: cookie borrada (Max-Age=0 + Expires 1970) y fila de sesión con revoked_at IS NOT NULL en DB."
}