fix(auth): repair the JIT placeholder email once bunyip verifies it #494

Merged
Claude-Run merged 1 commit from fix/PMS-635-repair-jit-placeholder-email into main 2026-08-06 11:39:26 +02:00
Member

A bunyip user mirrored into mokosh before their email was verified lands under the {sub}@unresolved.invalid placeholder with email_verified_at NULL. upsert_user_from_oidc runs on first sight only, and PMS-713 skips the /oauth2/userinfo hop for an already-placed user, so nothing ever revisited that row: the placeholder was permanent. Every mokosh-side email to the account was then addressed to a domain in the RFC 2606 reserved .invalid TLD, which never resolves and is rejected outright by Google Workspace, and the email_verified_at IS NOT NULL invite gate could never open.

bunyip_userinfo_needed now keeps fetching userinfo while the row holds a placeholder (the only way to learn the address was verified since), and place_bunyip_user calls the new AuthService::repair_placeholder_email to write the real address and stamp email_verified_at. The UPDATE re-checks the placeholder domain in its WHERE clause, so it is idempotent and can never overwrite a real address. Once repaired the row returns to the no-userinfo fast path.

SmtpMailer::send_multipart now refuses a recipient in the reserved .invalid TLD instead of handing the relay a message that can only bounce. The Message-ID / Date header formation from PMS-624 is unchanged and still covered by base_builder_sets_message_id_and_date_headers.

#PMS-635

A bunyip user mirrored into mokosh before their email was verified lands under the `{sub}@unresolved.invalid` placeholder with `email_verified_at` NULL. `upsert_user_from_oidc` runs on first sight only, and PMS-713 skips the `/oauth2/userinfo` hop for an already-placed user, so nothing ever revisited that row: the placeholder was permanent. Every mokosh-side email to the account was then addressed to a domain in the RFC 2606 reserved `.invalid` TLD, which never resolves and is rejected outright by Google Workspace, and the `email_verified_at IS NOT NULL` invite gate could never open. `bunyip_userinfo_needed` now keeps fetching userinfo while the row holds a placeholder (the only way to learn the address was verified since), and `place_bunyip_user` calls the new `AuthService::repair_placeholder_email` to write the real address and stamp `email_verified_at`. The UPDATE re-checks the placeholder domain in its WHERE clause, so it is idempotent and can never overwrite a real address. Once repaired the row returns to the no-userinfo fast path. `SmtpMailer::send_multipart` now refuses a recipient in the reserved `.invalid` TLD instead of handing the relay a message that can only bounce. The Message-ID / Date header formation from PMS-624 is unchanged and still covered by `base_builder_sets_message_id_and_date_headers`. #PMS-635
fix(auth): repair the JIT placeholder email once bunyip verifies it
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 1m47s
Check / fmt + clippy + build + tests (pull_request) Successful in 14m45s
Integration / integration tests (pull_request) Successful in 22m52s
Create release / Gate (release-branch merges only) (pull_request) Successful in 1s
Create release / Create release from merged PR (pull_request) Has been skipped
f647e52ffa
A bunyip user mirrored into mokosh before their email was verified lands under the `{sub}@unresolved.invalid` placeholder with `email_verified_at` NULL. `upsert_user_from_oidc` runs on first sight only, and PMS-713 skips the `/oauth2/userinfo` hop for an already-placed user, so nothing ever revisited that row: the placeholder was permanent. Every mokosh-side email to the account was then addressed to a domain in the RFC 2606 reserved `.invalid` TLD, which never resolves and is rejected outright by Google Workspace, and the `email_verified_at IS NOT NULL` invite gate could never open.

`bunyip_userinfo_needed` now keeps fetching userinfo while the row holds a placeholder (the only way to learn the address was verified since), and `place_bunyip_user` calls the new `AuthService::repair_placeholder_email` to write the real address and stamp `email_verified_at`. The UPDATE re-checks the placeholder domain in its WHERE clause, so it is idempotent and can never overwrite a real address. Once repaired the row returns to the no-userinfo fast path.

`SmtpMailer::send_multipart` now refuses a recipient in the reserved `.invalid` TLD instead of handing the relay a message that can only bounce. The Message-ID / Date header formation from PMS-624 is unchanged and still covered by `base_builder_sets_message_id_and_date_headers`.

#PMS-635
Claude-Run deleted branch fix/PMS-635-repair-jit-placeholder-email 2026-08-06 11:39:26 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!494
No description provided.