import { beforeEach, describe, expect, it, vi } from "vitest"; import { enforceAdminMfa } from "~/utils/auth/mfa/enforcement.server"; import { checkMfaStepUpState } from "~/utils/auth/mfa/step-up.server"; import { getUserSession } from "~/utils/session.server"; import { getUser, getUserTotpStatus } from "~/utils/db/users.db.server"; import { writeAdminSsoAuditEvent } from "~/modules/admin-sso/audit.server"; import { requireAdminMfaForAction, SENSITIVE_ADMIN_ACTIONS, isSensitiveAdminAction, } from "./admin-mfa-gate.server"; vi.mock("@toolctrl/config", () => ({ loadRequiredWebConfig: vi.fn(() => ({ routing: { appUrl: "https://app.example.test" } })), })); vi.mock("~/utils/auth/mfa/enforcement.server", () => ({ enforceAdminMfa: vi.fn(), })); vi.mock("~/utils/auth/mfa/step-up.server", () => ({ checkMfaStepUpState: vi.fn(), })); vi.mock("~/utils/app/CrossHostUrls", () => ({ absoluteAppRootPath: vi.fn(() => "https://app.example.test"), })); vi.mock("~/utils/session.server", () => ({ getUserSession: vi.fn(), })); vi.mock("~/utils/db/users.db.server", () => ({ getUser: vi.fn(), getUserTotpStatus: vi.fn(), })); vi.mock("~/modules/admin-sso/audit.server", () => ({ writeAdminSsoAuditEvent: vi.fn(), })); const enforceAdminMfaMock = vi.mocked(enforceAdminMfa); const checkMfaStepUpStateMock = vi.mocked(checkMfaStepUpState); const getUserSessionMock = vi.mocked(getUserSession); const getUserMock = vi.mocked(getUser); const getUserTotpStatusMock = vi.mocked(getUserTotpStatus); const writeAdminSsoAuditEventMock = vi.mocked(writeAdminSsoAuditEvent); beforeEach(() => { vi.clearAllMocks(); getUserSessionMock.mockResolvedValue({ get: vi.fn() } as never); getUserMock.mockResolvedValue({ id: "user_1", admin: true } as never); getUserTotpStatusMock.mockResolvedValue({ enabled: true } as never); checkMfaStepUpStateMock.mockReturnValue({ verified: true, state: { userId: "user_1", method: "totp", verifiedAt: "2026-05-25T12:00:00.000Z" }, ageMs: 1000, }); enforceAdminMfaMock.mockReturnValue({ allowed: true, reason: "allowed", redirectTo: "/admin" }); writeAdminSsoAuditEventMock.mockResolvedValue(undefined); }); describe("SENSITIVE_ADMIN_ACTIONS taxonomy", () => { it("includes the spec-required actions", () => { expect(SENSITIVE_ADMIN_ACTIONS).toContain("impersonation.start"); expect(SENSITIVE_ADMIN_ACTIONS).toContain("tenant.delete"); expect(SENSITIVE_ADMIN_ACTIONS).toContain("permission.grant"); expect(SENSITIVE_ADMIN_ACTIONS).toContain("audit.export"); expect(SENSITIVE_ADMIN_ACTIONS).toContain("data.export"); }); it("typeguard accepts known actions and rejects unknown", () => { expect(isSensitiveAdminAction("impersonation.start")).toBe(true); expect(isSensitiveAdminAction("tenant.delete")).toBe(true); expect(isSensitiveAdminAction("totally-random")).toBe(false); expect(isSensitiveAdminAction("")).toBe(false); }); }); describe("requireAdminMfaForAction", () => { it("returns the actor and writes success audit when MFA enforcement allows the action", async () => { const request = new Request("https://admin.example.test/admin/accounts"); await expect(requireAdminMfaForAction(request, "tenant.delete", "user_1")).resolves.toEqual({ userId: "user_1", action: "tenant.delete", }); expect(getUserSessionMock).toHaveBeenCalledWith(request); expect(getUserMock).toHaveBeenCalledWith("user_1"); expect(getUserTotpStatusMock).toHaveBeenCalledWith("user_1"); expect(enforceAdminMfaMock).toHaveBeenCalledWith( expect.objectContaining({ requestUrl: request.url, userId: "user_1", isAdmin: true, redirectMode: "host-aware", appFallbackPath: "https://app.example.test", }), ); expect(writeAdminSsoAuditEventMock).toHaveBeenCalledWith( expect.objectContaining({ action: "admin.mfa.app.challenge.success", actorAdminUserId: "user_1", request, meta: { action: "tenant.delete" }, }), ); }); it("audits and throws a redirect response when enforcement returns a Response", async () => { const request = new Request("https://admin.example.test/admin/accounts"); const redirectResponse = new Response(null, { status: 302, headers: { Location: "/admin/security/mfa-challenge" }, }); enforceAdminMfaMock.mockReturnValue(redirectResponse as never); await expect(requireAdminMfaForAction(request, "audit.export", "user_1")).rejects.toBe(redirectResponse); expect(writeAdminSsoAuditEventMock).toHaveBeenCalledWith( expect.objectContaining({ action: "admin.mfa.app.challenge.failure", actorAdminUserId: "user_1", request, meta: { action: "audit.export", reason: "redirect-response" }, }), ); }); it("audits denied enforcement and throws a redirect to the challenge path", async () => { const request = new Request("https://admin.example.test/admin/accounts"); enforceAdminMfaMock.mockReturnValue({ allowed: false, reason: "step-up-missing", redirectTo: "/admin/security/mfa-challenge?redirectTo=%2Fadmin%2Faccounts", }); await expect(requireAdminMfaForAction(request, "permission.grant", "user_1")).rejects.toMatchObject({ status: 302, }); expect(writeAdminSsoAuditEventMock).toHaveBeenCalledWith( expect.objectContaining({ action: "admin.mfa.app.challenge.failure", actorAdminUserId: "user_1", request, meta: { action: "permission.grant", reason: "step-up-missing" }, }), ); }); });