feat(F-088): completed feature
This commit is contained in:
@@ -2,19 +2,54 @@
|
||||
"feature_id": "F-083",
|
||||
"verdict": "APPROVED",
|
||||
"checks": [
|
||||
{ "name": "Endpoints match spec", "result": "PASS", "notes": "POST /auth/password-reset/request and /confirm both registered; request always 200; confirm 200/400." },
|
||||
{ "name": "Token storage is hash-only", "result": "PASS", "notes": "token_hash column UNIQUE; raw token only leaves the system via email link." },
|
||||
{ "name": "Single-use enforcement", "result": "PASS", "notes": "isTokenUsable checks usedAt IS NULL + expires_at > now; markUsed is atomic UPDATE." },
|
||||
{ "name": "Rate limit per IP and per email", "result": "PASS", "notes": "RequestPasswordReset.execute checks both buckets before any DB work; silently drops when over." },
|
||||
{ "name": "User enumeration prevented", "result": "PASS", "notes": "No-user path returns silently after ~80ms delay; never reveals whether the email exists." },
|
||||
{ "name": "Admin Send reset link action", "result": "PASS", "notes": "Per-row 🔑 button + toast in customers/page.tsx." },
|
||||
{ "name": "Storefront reset page", "result": "PASS", "notes": "/cuenta/restablecer reads ?token= from URL; submits via storefront proxy." },
|
||||
{ "name": "Audit log entries", "result": "PASS", "notes": "request and confirm both call auditLogger.log via the build-app hook." }
|
||||
{
|
||||
"name": "Endpoints match spec",
|
||||
"result": "PASS",
|
||||
"notes": "POST /auth/password-reset/request and /confirm both registered; request always 200; confirm 200/400."
|
||||
},
|
||||
{
|
||||
"name": "Token storage is hash-only",
|
||||
"result": "PASS",
|
||||
"notes": "token_hash column UNIQUE; raw token only leaves the system via email link."
|
||||
},
|
||||
{
|
||||
"name": "Single-use enforcement",
|
||||
"result": "PASS",
|
||||
"notes": "isTokenUsable checks usedAt IS NULL + expires_at > now; markUsed is atomic UPDATE."
|
||||
},
|
||||
{
|
||||
"name": "Rate limit per IP and per email",
|
||||
"result": "PASS",
|
||||
"notes": "RequestPasswordReset.execute checks both buckets before any DB work; silently drops when over."
|
||||
},
|
||||
{
|
||||
"name": "User enumeration prevented",
|
||||
"result": "PASS",
|
||||
"notes": "No-user path returns silently after ~80ms delay; never reveals whether the email exists."
|
||||
},
|
||||
{
|
||||
"name": "Admin Send reset link action",
|
||||
"result": "PASS",
|
||||
"notes": "Per-row 🔑 button + toast in customers/page.tsx."
|
||||
},
|
||||
{
|
||||
"name": "Storefront reset page",
|
||||
"result": "PASS",
|
||||
"notes": "/cuenta/restablecer reads ?token= from URL; submits via storefront proxy."
|
||||
},
|
||||
{
|
||||
"name": "Audit log entries",
|
||||
"result": "PASS",
|
||||
"notes": "request and confirm both call auditLogger.log via the build-app hook."
|
||||
}
|
||||
],
|
||||
"lint": { "errors_introduced": 0 },
|
||||
"lint": {
|
||||
"errors_introduced": 0
|
||||
},
|
||||
"typecheck": "PASS",
|
||||
"tests": "9/9 passed (password-reset.test.ts)",
|
||||
"verdict_reason": "Reset flow implemented end to end with the expected security properties (single-use, hashed tokens, rate limit, no enumeration, audit log).",
|
||||
"reviewer": "reviewer",
|
||||
"reviewed_at": "2026-08-20T04:09:00Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:09:00Z",
|
||||
"agent": "reviewer"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user