Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 8s
CI / E2E Tests (push) Has been skipped
CI / AI Services (Python) — Smoke (push) Failing after 5s
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 41s
Deploy / Build API Image (push) Failing after 6s
Deploy / Build Web Image (push) Failing after 6s
Deploy / Build AI Services Image (push) Failing after 8s
E2E Tests / Playwright E2E (push) Failing after 11s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 49s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 33s
Security Scanning / Trivy Filesystem Scan (push) Failing after 32s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Production DB had 11 User rows with `phoneHash` / `emailHash` either
NULL (legacy seed before the privacy hashing layer) or filled with the
wrong format (an earlier short-circuit used plain SHA-256). Either way,
`PrismaUserRepository.findByPhone` calls
`fieldEncryption.computeHash(phone)` and looks up `phoneHash` —
returning null and surfacing "Số điện thoại hoặc mật khẩu không đúng"
even when the password is correct.
Two fixes:
1. `scripts/backfill-user-pii-hashes.ts` — re-run-safe one-shot:
- Reads `FIELD_ENCRYPTION_KEY` (or `KYC_ENCRYPTION_KEY`),
- Derives the same HMAC key the runtime uses (HKDF-SHA256 with the
"goodgo-field-hash" info string),
- Recomputes `phoneHash` + `emailHash` for every User and writes
them back if they differ from the stored value.
Verified: after run, login of seed-admin-001, seed-agent-001,
seed-buyer-001 and seed-developer-001 all succeed against
api.goodgo.vn with the seed default password.
2. `prisma/seed.ts` — `seedUsers()` now computes the HMAC hashes on
create AND update (idempotent), so future `pnpm db:seed` runs
produce rows that work with the runtime auth flow out of the box.
When `FIELD_ENCRYPTION_KEY` isn't set (dev mode without encryption),
the hash is `null` and the repository falls back to the plaintext
`phone` / `email` query — preserving local-dev behaviour.
Default seed password remains `Velik@2026`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>