fix(e2e): make the TOTP 2fa step window-safe to stop /login/2fa stalls #486
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/e2e-totp-window-race"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fix the flaky
/login/2fastall in the E2E login helperSymptom
Merge-gate E2E runs intermittently failed the interactive-login precondition (
loginViaSpa) with "SPA login never navigated away from the /login or /oauth2/consent flow (30s timeout; last path: /login/2fa)" or awaitFortimeout on the login form. It was browser-nondeterministic: webkit failed one run while firefox passed, firefox failed the next while webkit passed. The bearer-based[api]tests (login captured once in setup) always passed - only the interactive browser login flaked.Root cause
fillTotpStepgenerated the TOTP code up front, then waited up to 10s for the code input to become visible before submitting:TOTP codes live for a 30s window. On a slow browser run the code crossed its window boundary before it reached the hub, bunyip rejected the stale code, and the page stayed on
/login/2fauntil the caller's 30s poll gave up. The timing dependence is exactly why it moved between browsers run to run.Fix (
e2e/lib/login.ts,fillTotpStep)authenticator.timeRemaining() >= 5, otherwise wait for the next window first - so a submitted code cannot expire in flight (network + hub validation).2fa_verifyat 5 FAILED codes / 15 min per account and a success resets the counter (BUNYIP-201). Each attempt relies on the BUNYIP-331 input-event auto-submit (one POST, no button click), so the same code is never re-POSTed; worst case is three failed submits, well under the cap. The explicit Verify click is kept only as a single fallback for a hub that stops auto-submitting.Verification
npx tsc --noEmitpasses. otplib primitives confirmed against the installed types and at runtime (timeRemaining()in(0, 30],generate()a valid 6-digit code) - and in a local checktimeRemaining()returned 4, precisely the sub-5s boundary the guard now waits out. Full E2E runs against staging (needs the E2E account + TOTP secret + a deployed target), so the behavioural proof is the next gate run.Separate from the PMS-710 seed work; this only touches the E2E login helper and unblocks the gate for every PR.