Files
RenewCMS/features/user_response_field_hygiene.qa.md
T

3.7 KiB

QA procedure: user_response_field_hygiene

Package: test (black-box), extending test/account_verification_http_test.go's newAccountVerificationRouter / newAccountVerificationTestUserRepo helpers and test/user_test.go's mockUserRepo / stubHasher.

Setup shared by every case

  1. Call validator.InitValidator() once.
  2. Reuse newAccountVerificationRouter(userRepo, mailRepo, token) from test/account_verification_http_test.go, which wires auth.NewHandler(...) with fakes over a fresh chi.NewRouter() mirroring api/router.go's /v1/auth group (public routes plus the jwtauth.Verifier + Authenticator-wrapped verify route). No live server, no real SQLite, no real SMTP.
  3. newAccountVerificationTestUserRepo() seeds user id 7 with a non-empty VerificationCode ("hashed:abc123") and VerificationExpiration one hour out, matching the existing fixture.

Response-shape check for POST /v1/auth/verify (the fix)

  1. Successful verify: POST /v1/auth/verify with {"code":"abc123"} and a valid jwt cookie for user id 7. Decode the response body into map[string]json.RawMessage (not into user.User) and assert:
    • the key set is exactly {"id", "username", "email", "is_verified", "created_at", "updated_at", "display_name", "role"};
    • none of password, password_reset_code, verification_code, verification_expiration, password_reset_expiration, token_version is present;
    • is_verified unmarshals to true;
    • display_name unmarshals to "";
    • role unmarshals to "owner" (seeded user 7 has Role: owner).
  2. Rejected verify: same seed, {"code":"wrong-code"} → assert status 403 and that the raw response body bytes, treated as a string, contain none of the substrings password, verification_code, password_reset_code, verification_expiration, password_reset_expiration (the body is plain text from http.Error, so this is a substring check, not a JSON-key check).

Registration check (its own case, correctly gated)

  1. POST /v1/auth/register against an empty mockUserRepo (the registration gate only allows register while no verified account exists) with {"username":"bob","password":"hunter2example12","email":"bob@example.com"} → assert status 200 and that the raw response body string contains none of the six sensitive substrings from step 5.

Table-driven sweep of the other auth endpoints (regression guard, not the fix)

  1. For each of POST /v1/auth/login, /logout, /password-reset, /password-reset/confirm, seed a mockUserRepo/mockMailRepo pair with a verified user "alice" (IsVerified: true, matching the Scenario Outline's Given, since these endpoints don't depend on the registration gate), send the request, and assert the raw response body string contains none of the six sensitive substrings from step 5. This should already pass today since these handlers only ever write a {"message": ...} body; the point of the test is to pin that fact down so a future change can't quietly regress it.

Manual verification (not exercised by the Go test)

  • The SPA's post-verification screen (web/src/) only ever needs username/is_verified to render; confirm by hand that no SPA code reads password, verification_code or password_reset_code off the verify response, since removing them from the wire format could otherwise silently break a screen that isn't covered by this Go test suite.
  • Confirm the public response type lives in the shared package under api/pkg (not a change to internal/domain/user/userDomain.go's json tags), per the project's stated preference to keep the domain struct's tags intact and shape the public response in the handler layer instead.