chore: upgrade Node.js runtime to v24 across codebase #419

Merged
jason.woltje merged 438 commits from fix/auth-frontend-remediation into main 2026-02-17 01:04:47 +00:00
2 changed files with 43 additions and 10 deletions
Showing only changes of commit 5328390f4c - Show all commits

View File

@@ -44,9 +44,10 @@ vi.mock("@/lib/auth/fetch-with-retry", () => ({
fetchWithRetry: mockFetchWithRetry,
}));
// Mock parseAuthError to use the real implementation
vi.mock("@/lib/auth/auth-errors", async (importOriginal) => {
return importOriginal();
// Use real parseAuthError implementation — vi.mock required for module resolution in vitest
vi.mock("@/lib/auth/auth-errors", async () => {
const actual = await import("../../../lib/auth/auth-errors");
return { ...actual };
});
/* ------------------------------------------------------------------ */
@@ -317,7 +318,7 @@ describe("LoginPage", (): void => {
});
});
it("shows error banner on sign-in failure", async (): Promise<void> => {
it("sanitizes BetterAuth error messages through parseAuthError", async (): Promise<void> => {
mockFetchConfig(EMAIL_ONLY_CONFIG);
mockSignInEmail.mockResolvedValueOnce({
error: { message: "Invalid credentials" },
@@ -334,8 +335,39 @@ describe("LoginPage", (): void => {
await user.type(screen.getByLabelText(/password/i), "wrong");
await user.click(screen.getByRole("button", { name: /continue/i }));
// Raw "Invalid credentials" is mapped through parseAuthError to a PDA-friendly message
await waitFor((): void => {
expect(screen.getByText("Invalid credentials")).toBeInTheDocument();
expect(
screen.getByText("Authentication didn't complete. Please try again when ready.")
).toBeInTheDocument();
});
expect(mockPush).not.toHaveBeenCalled();
});
it("maps raw DB/server errors to PDA-friendly messages instead of leaking details", async (): Promise<void> => {
mockFetchConfig(EMAIL_ONLY_CONFIG);
// Simulate a leaked internal server error from BetterAuth
mockSignInEmail.mockResolvedValueOnce({
error: { message: "Internal server error: connection to DB pool exhausted" },
});
const user = userEvent.setup();
render(<LoginPage />);
await waitFor((): void => {
expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
});
await user.type(screen.getByLabelText(/email/i), "test@example.com");
await user.type(screen.getByLabelText(/password/i), "wrong");
await user.click(screen.getByRole("button", { name: /continue/i }));
// parseAuthError maps "internal server" keyword to server_error PDA-friendly message
await waitFor((): void => {
expect(
screen.getByText("The service is taking a break. Please try again in a moment.")
).toBeInTheDocument();
});
expect(mockPush).not.toHaveBeenCalled();
@@ -359,9 +391,11 @@ describe("LoginPage", (): void => {
await user.type(screen.getByLabelText(/password/i), "wrong");
await user.click(screen.getByRole("button", { name: /continue/i }));
// When error.message is falsy, parseAuthError receives the raw error object
// which falls through to the "unknown" code PDA-friendly message
await waitFor((): void => {
expect(
screen.getByText("Unable to sign in. Please check your credentials and try again.")
screen.getByText("Authentication didn't complete. Please try again when ready.")
).toBeInTheDocument();
});

View File

@@ -102,11 +102,10 @@ export default function LoginPage(): ReactElement {
const result = await signIn.email({ email, password });
if (result.error) {
setError(
typeof result.error.message === "string"
? result.error.message
: "Unable to sign in. Please check your credentials and try again."
const parsed = parseAuthError(
result.error.message ? new Error(String(result.error.message)) : result.error
);
setError(parsed.message);
} else {
router.push("/tasks");
}