fix(auth): drop the invite reopen — keep the fix to the lost account alone

Round 3 of the review killed the reopen from b5a1002: flipping an approved
invite back to pending let an unauthenticated POST /auth/register REVOKE a
standing approval for any whitelisted-but-unclaimed address, which then fails
is_allowed() and locks the real owner out of Google sign-in — the primary way
people get in here. It also re-armed the pre-emption window it was meant to
close, because with no SMTP email_verified is set True and the SEC-10 guard the
design leaned on never fires.

Two attempts at fixing the stranded-account UX in the same change both came back
worse than the wart. What remains is the narrow, real bug: the account was
silently rolled back and is now committed. An admin still binds the approval to
the account, exactly as before this branch. UX-25 in the roadmap records the
follow-up and both dead ends so they are not retried.

Also from round 3: the upsert docstring no longer claims the admin UI cannot
reach these accounts (re-entering the address in the same panel's whitelist box
does, and a test now pins it), the release notes are scoped to what the diff
actually changes with the operator note moved where the dialog renders it, and
RateLimiter has unit tests so reset() is not production code only a fixture
calls.
This commit is contained in:
2026-09-01 21:34:38 +02:00
parent b5a1002412
commit b64c3f514d
4 changed files with 116 additions and 78 deletions
+6 -7
View File
@@ -18,16 +18,15 @@ export const RELEASE_NOTES: ReleaseEntry[] = [
version: "0.78.5",
date: "2026-09-01",
summary:
"Two ways a sign-up could quietly go nowhere are fixed: on an instance that sends no email the account was discarded outright, and an address the admin had whitelisted in advance landed in a request no admin screen ever showed.",
"On an instance that cannot send email, signing up with an address that had already been whitelisted or had already requested access created no account at all. The sign-up said it worked, nothing existed, and trying again did the same.",
fixes: [
"On an instance that sends no email, signing up with an address that already had a request on file created nothing at all. The sign-up reported success, no account existed, and trying again did the same — so the person could neither sign in nor get back into the queue.",
"Whitelisting someone before they sign up now works the way it looks like it should. Their sign-up reopens the request so it appears under Users → Access requests, where approving it lets them in; previously it landed against a decision already made, which the queue does not list and the Approve action refuses, leaving nobody able to complete it.",
"Retrying a sign-up while a request is already pending no longer emails every admin again.",
"Such a sign-up now creates the account. Previously the person could neither sign in nor get back into the access queue — they had no account to approve, and every retry silently repeated the same nothing. Only a brand-new address was unaffected. As before, the account starts inactive and an admin's approval is what lets it sign in.",
"Signing up with an address that had already asked for access no longer sends admins a second copy of the same request, and one that was already whitelisted no longer produces a notice pointing at a queue with nothing in it.",
"Operator note: an incomplete SMTP setting makes Siftlode skip every message silently by design — that is what left the sign-ups above with nothing to fall back on. If your instance has never delivered mail, check Configuration → Email and use “Send test email”.",
],
chores: [
"Registration commits the new account explicitly — upsert_pending_invite() commits only when it actually writes an invite row, and the only other commit on that path is gated on working SMTP, so with mail unavailable the flushed user row was rolled back when the background task's session closed. An approval that predates the account now reopens the invite instead of being treated as a standing grant, which keeps a human (and with them the SEC-10 preset-password guard in _activate_user_by_email) between a whitelisted address and whoever registers it. The admin notice is gated on a fresh decision, matching the other two callers.",
"Two regression tests (no-SMTP with a request already pending, and the reopen-then-approve loop) plus guards for the unknown-email, previously-denied and SMTP-on branches, the first end-to-end tests of the /auth/register route and its allow_registration gate, and an autouse fixture that resets the module-level rate limiters between tests so their windows stop pooling across the suite.",
"Operator note: an incomplete SMTP setting makes Siftlode skip every message silently by design. If your instance has never delivered mail, check Configuration → Email and use “Send test email”.",
"Registration commits the new account explicitly. upsert_pending_invite() commits only when it actually writes an invite row — not when the address already has a pending or approved one — and the only other commit on that path is gated on working SMTP, so with mail unavailable the flushed user row was rolled back when the background task's session closed. The admin notice is now gated on that same fresh-decision signal, matching the two other callers.",
"Three DB-lane regression tests (pre-approved and already-pending sign-ups on a no-SMTP instance, plus the admin-activation recovery that depends on the account existing), guards for the unknown-email, previously-denied and SMTP-on branches, the first end-to-end tests of the /auth/register route and its allow_registration gate, unit tests for the rate limiter, and an autouse fixture resetting the module-level limiters between tests so their windows stop pooling across the suite.",
],
},
{