From 34f8ddbcfeb648234b6794914771cc84f047d263 Mon Sep 17 00:00:00 2001 From: Claus Lohmar Date: Thu, 15 Oct 2026 07:08:31 +0000 Subject: [PATCH] test(setup): pin the closed-window refusal on the TOTP step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lock in the behaviour the fix introduces (docs/specs/spec-005-setup-wizard.md §11 D-2): once the admin's bounded enrollment window has closed (SPEC-004 §4, A1) `admin.totp.begin` answers a clean 409 and issues no secret, rather than propagating the flow's "no pending identity" as a server fault. --- internal/core/server/setup_wizard_test.go | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/internal/core/server/setup_wizard_test.go b/internal/core/server/setup_wizard_test.go index b31738f..983c55c 100644 --- a/internal/core/server/setup_wizard_test.go +++ b/internal/core/server/setup_wizard_test.go @@ -705,3 +705,31 @@ func TestSpec005SetupHoldsMidWizard(t *testing.T) { t.Errorf("GET /setup after finish = %d, want 404 (D-045)", rec.Code) } } + +// TestSpec005TOTPBeginRefusesAClosedWindow: the wizard's TOTP step must refuse +// once the admin's bounded enrollment window has closed (SPEC-004 §4, A1). It +// must not issue a secret, and the refusal must be a clean 4xx — not the +// server fault a bare propagation of the flow's "no pending identity" would be. +func TestSpec005TOTPBeginRefusesAClosedWindow(t *testing.T) { + h := newSetupHarness(t) + h.beginAdmin(t) + + // Backdate the identity so it sits comfortably outside the bounded window. + if _, err := h.db.Exec( + `UPDATE identities SET created_at = ? WHERE user_id = ?`, + store.FormatTime(time.Now().Add(-365*24*time.Hour)), 1, + ); err != nil { + t.Fatalf("backdate the identity: %v", err) + } + if inWindow, err := h.ids.WithinEnrollmentWindow(h.ctx, 1); err != nil || inWindow { + t.Fatalf("precondition: the window is still open (inWindow=%v err=%v)", inWindow, err) + } + + rec := h.post("admin.totp.begin", nil) + if rec.Code != http.StatusConflict { + t.Fatalf("admin.totp.begin past the window = %d, want 409 (A1)", rec.Code) + } + if _, err := h.ids.TOTPSecret(h.ctx, 1); err == nil { + t.Error("the wizard issued a TOTP secret for an identity outside its window (A1)") + } +}